IT

당신이 본 가장 우스운 비관은 무엇입니까?

lottoking 2020. 6. 14. 10:09
반응형

당신이 본 가장 우스운 비관은 무엇입니까? [닫은]


우리는 조기 최적화가 코드를 읽을 수 없거나 유지할 수 없기 때문에 모든 악의 근원이라는 것을 알고 있습니다. 누군가가 "최적화"를 구현하면 더 빠를 것이라고 생각 하기 때문에 비관 화가 더 심해 집니다. 그러나 더 느리고 결국 버그가 많고 유지 관리가 불가능한 등의 결과가 나옵니다. 가장 우스운 예는 무엇입니까? ?


오래된 프로젝트에서 우리는 방대한 Z-8000 경험을 가진 일부 (그렇지 않으면 우수한) 임베디드 시스템 프로그래머를 물려 받았습니다.

우리의 새로운 환경은 32 비트 Sparc Solaris였습니다.

RAM에서 16 비트를 잡는 것이 32 비트를 잡는 것보다 빠르기 때문에 녀석 중 한 명이 가서 모든 정수를 반바지로 변경하여 코드 속도를 높였습니다.

32 비트 시스템에서 32 비트 값을 잡는 것이 16 비트 값을 잡는 것보다 빠르다는 것을 보여주기 위해 데모 프로그램을 작성해야했으며 16 비트 값을 잡으려면 CPU가 32 비트 너비를 가져야한다고 설명했습니다 메모리 액세스 후 16 비트 값에 필요하지 않은 비트를 마스킹 또는 시프트합니다.


"초기 최적화는 모든 악의 근원"이라는 문구가 사용 된 방식이라고 생각합니다. 많은 프로젝트의 경우 프로젝트 후반까지 성능을 고려하지 않는 것이 변명되었습니다.

이 문구는 종종 사람들이 일을 피하기위한 목발입니다. 나는 사람들이 정말로 "Gee, 우리는 그것을 미리 생각하지 않았고 지금 그것을 다룰 시간이 없다"고 말할 때이 문구가 사용 된 것을 본다.

나는 "pesimization"으로 인한 문제의 예보다 멍청한 성능 문제에 대한 더 많은 "우스운"예를 보았습니다.

  • 프로그램 시작 동안 같은 레지스트리 키를 수천 번 (또는 수만) 읽는다.
  • 동일한 DLL을 수백 또는 수천 번로드
  • 불필요하게 파일의 전체 경로를 유지하여 메가 바이트의 메모리 낭비
  • 데이터 구조를 구성하지 않으므로 필요한 것보다 더 많은 메모리를 차지합니다.
  • 파일 이름 또는 경로를 MAX_PATH에 저장하는 모든 문자열 크기 조정
  • 이벤트, 콜백 또는 기타 알림 메커니즘이있는 대상에 대한 무료 폴링

내가 더 나은 진술이라고 생각하는 것은 "측정과 이해없는 최적화는 전혀 최적화가 아니라 무작위 변화"라는 것이다.

우수한 성능 작업은 시간이 많이 걸리며 기능 또는 구성 요소 자체의 개발에 더 많은 시간이 소요됩니다.


데이터베이스는 비관적 인 플레이 랜드입니다.

즐겨 찾기에는 다음이 포함됩니다.

  • 테이블이 너무 커서 날짜 범위, 알파벳 범위 등으로 여러 테이블로 나눕니다.
  • 폐기 된 레코드에 대한 아카이브 테이블을 작성하지만 프로덕션 테이블과 계속 UNION하십시오.
  • (구분 / 고객 / 제품 / 등)에 의해 전체 데이터베이스 복제
  • 열이 너무 커지므로 인덱스에 열을 추가하지 마십시오.
  • 원시 데이터에서 재 계산이 너무 느리므로 많은 요약 테이블을 작성하십시오.
  • 공간을 절약하기 위해 서브 필드로 열을 작성하십시오.
  • 필드를 배열로 비정규 화합니다.

그것은 내 머리 꼭대기에서 벗어났다.


나는 절대적인 규칙이 없다고 생각합니다. 어떤 것들은 가장 잘 최적화되어 있고 어떤 것은 그렇지 않습니다.

예를 들어 위성에서 데이터 패킷을 수신 한 회사에서 근무했습니다. 각 패킷은 많은 비용이 들기 때문에 모든 데이터가 고도로 최적화되었습니다 (즉, 압축). 예를 들어 위도 / 경도는 절대 값 (부동)으로 전송되지 않고 "현재"영역의 "북서쪽"코너에 상대적인 오프셋으로 전송되었습니다. 사용하기 전에 모든 데이터의 압축을 풀어야했습니다. 그러나 이것은 비관적이지 않다고 생각합니다. 통신 비용을 줄이는 것은 지능적인 최적화입니다.

반면 소프트웨어 설계자는 압축을 푼 데이터를 읽을 수있는 XML 문서로 형식화하고 각 열을 해당 열에 저장하는 것과 달리 데이터베이스에 저장해야한다고 결정했습니다. 그들의 아이디어는 "XML은 미래입니다", "디스크 공간은 싸다", "프로세서는 싸다"라는 것이므로 아무것도 최적화 할 필요가 없었습니다. 그 결과 16 바이트 패킷이 한 열에 저장된 2kB 문서로 바뀌었고 간단한 쿼리조차도 메가 바이트의 XML 문서를 메모리에로드해야했습니다! 초당 50 개가 넘는 패킷을 받았으므로 성능이 얼마나 끔찍한 지 상상할 수 있습니다 (BTW, 회사 파산).

다시 말하지만 절대 규칙은 없습니다. 예, 때로는 너무 일찍 최적화하는 것은 실수입니다. 그러나 때때로 "cpu / disk space / memory is cheap"라는 좌우명은 모든 악의 근원입니다.


오 주님, 나는 그들 모두를 본 것 같아요. 너무 자주 게으른 사람이 성능 문제의 원인으로 문제를 해결하거나 실제로 성능 문제가 있는지 여부를 조사하기 위해 성능 문제를 해결하려는 노력이 아닌 경우가 많습니다. 이 중 많은 경우에 나는 특정 기술을 시도하고 그들의 새롭고 반짝이는 망치에 맞는 손톱을 필사적으로 찾는 사람이 아닌지 궁금합니다.

최근 예는 다음과 같습니다.

데이터 아키텍트는 상당히 크고 복잡한 응용 프로그램에서 키 테이블을 세로로 분할하는 정교한 제안을 제공합니다. 그는 변화에 적응하기 위해 어떤 유형의 개발 노력이 필요한지 알고 싶어합니다. 대화는 다음과 같이 진행되었습니다.

나 : 왜 이걸 고려하고 있니? 해결하려는 문제는 무엇입니까?

그 : 표 X가 너무 넓어서 성능상의 이유로 분할하고 있습니다.

나 : 왜 그렇게 넓다고 생각하니?

컨설턴트 : 컨설턴트는 한 테이블에 너무 많은 열이 있다고 말했다.

나 : 그리고 이것은 성능에 영향을 미치고 있습니까?

사용자 : 그렇습니다. 사용자는 애플리케이션의 XYZ 모듈에서 간헐적 인 속도 저하를보고했습니다.

나 : 테이블 너비가 문제의 원인이라는 것을 어떻게 알 수 있습니까?

그 : 그것은 XYZ 모듈이 사용하는 키 테이블이며, 200 열과 같습니다. 문제가되어야합니다.

Me (설명) : 그러나 XYZ 모듈은 특히 해당 테이블의 대부분의 열을 사용하며 사용자가 해당 테이블에서 표시하려는 데이터를 표시하도록 앱을 구성하기 때문에 사용하는 열을 예측할 수 없습니다. 그것은 시간의 95 %는 우리가 것이다 어쨌든 다시 함께 모든 테이블을 조인 바람 줄 가능성이 상처 성능을.

그 : 컨설턴트는 너무 넓어서 변경해야한다고 말했습니다.

나 : 이 컨설턴트는 누구입니까? 컨설턴트를 고용하거나 개발 팀과 전혀 대화하지 않았습니다.

그분 : 우리는 아직 그들을 고용하지 않았습니다. 이것은 그들이 제안한 제안의 일부이지만, 우리는이 데이터베이스를 재구성 할 필요가 있다고 주장했다.

나 : 어. 데이터베이스 재 설계 서비스를 판매하는 컨설턴트는 데이터베이스 재 설계가 필요하다고 생각합니다.

대화는 이런 식으로 진행되었습니다. 그 후, 문제의 테이블을 다시 살펴보고 이국적인 분할 전략이 필요없는 간단한 정규화로 좁힐 수 있다고 결정했습니다. 물론 성능 문제 (이전에는보고되지 않음)를 조사하고 다음 두 가지 요소로 추적하면 문제가 될 수 있습니다.

  1. 몇 개의 키 열에 인덱스가 없습니다.
  2. MSAccess를 사용하여 프로덕션 데이터베이스를 직접 쿼리하여 키 테이블 ( "너무 넓은"포함)을 주기적으로 잠그는 일부 불량 데이터 분석가.

물론 건축가는 여전히 "너무 넓은"메타 문제에 매달려있는 테이블의 수직 분할을 추진하고있다. 그는 앱을 보거나 성능 분석을 실행하지 않고도 데이터베이스에 대한 주요 디자인 변경이 필요하다고 판단한 다른 데이터베이스 컨설턴트의 제안을 받아 자신의 사례를 강화했습니다.


알파 드라이브 -7을 사용하여 CHX-LT를 완전히 배양하는 사람들을 보았습니다. 이것은 드문 습관입니다. 보다 일반적인 방법은 ZT 변환기를 초기화하여 버퍼 과부하가 줄어들고 (순 과부하 저항이 커짐) 자바 스타일 바이트 그래픽을 작성하는 것입니다.

완전히 비관적입니다!


지구를 산산조각내는 것은 없지만 인정하지만 StringBuffer를 사용하여 Java의 루프 외부에서 문자열을 연결하는 사람들을 잡았습니다. 터닝과 같은 간단한 것이 었습니다

String msg = "Count = " + count + " of " + total + ".";

으로

StringBuffer sb = new StringBuffer("Count = ");
sb.append(count);
sb.append(" of ");
sb.append(total);
sb.append(".");
String msg = sb.toString();

이 기술은 루프에서 상당히 빠르기 때문에 루프에서 사용하는 것이 일반적이었습니다. 문제는 StringBuffer가 동기화되어 있기 때문에 몇 개의 문자열 만 연결하면 실제로 추가 오버 헤드가 있다는 것입니다. (이 규모에서는 그 차이가 절대적으로 사소한 것은 말할 것도 없습니다.)이 연습에 대한 두 가지 다른 점 :

  1. StringBuilder는 동기화되지 않으므로 코드를 여러 스레드에서 호출 할 수없는 경우 StringBuffer보다 선호되어야합니다.
  2. 최신 Java 컴파일러는 읽을 수있는 문자열 연결을 어쨌든 필요할 때 최적화 된 바이트 코드로 변환합니다.

한 번은 'Root'테이블을 사용하는 MSSQL 데이터베이스를 보았습니다. 루트 테이블에는 GUID (고유 식별자), ID (int), LastModDate (datetime) 및 CreateDate (datetime)의 네 가지 열이 있습니다. 데이터베이스의 모든 테이블은 루트 테이블에 대한 외래 키입니다. 새 행이 만들어졌습니다 때마다 어떤 DB를 테이블, 당신은 당신이 (신경 쓰지 실제 테이블에 도착하기 전에 루트 테이블에 항목을 삽입하는 저장 프로 시저의 몇 가지를 사용했다 오히려 작업을하고있는 데이터베이스가 아닌 몇 가지 트리거를 사용하면 간단한 트리거가 발생합니다).

이것은 쓸모없는 오버 헤드와 두통의 혼란을 야기했으며, 그 위에 sprocs를 사용하고 (LINQ를 회사에 소개하려는 희망을 없애기 위해 그 위에 쓰여진 모든 것이 필요했습니다. 가능하지만 두통의 가치는 없습니다) 심지어해야 할 일을 완수하기까지합니다.

이 경로를 선택한 개발자는 테이블 자체에서 Guids를 사용하지 않았기 때문에 많은 공간이 절약되었다는 가정하에 경로를 방어했습니다 (그러나 ... 우리가 만드는 모든 행에 대해 루트 테이블에서 생성 된 GUID는 아닙니까?) , 어떻게 든 성능을 개선하고 데이터베이스의 변경 사항을 감사하기가 "쉽습니다".

아, 그리고 데이터베이스 다이어그램은 지옥의 돌연변이 거미처럼 보였습니다.


POBI어떻습니까?

90 년대 내 동료는 CEO가 새로운 기능에서 성능 문제를 찾아 모든 ERP 소프트웨어 (맞춤형) 릴리스의 첫날을 보냈기 때문에 CEO가 엉덩이에 차는 데 지쳤다. 새로운 기능으로 인해 기가 바이트가 발생하여 불가능한 것이 가능 해지더라도 그는 항상 세부적인 부분이나 겉으로는 큰 문제를 발견했습니다. 그는 프로그래밍에 대해 많이 알고 있다고 생각했고 프로그래머의 엉덩이를 차면서 킥을 얻었다.

무능한 비판의 성격 (그는 IT 담당자가 아닌 CEO였습니다)으로 인해 제 동료는 결코 제대로 이해하지 못했습니다. 성능 문제가 없으면 제거 할 수 없습니다 ...

한 번의 릴리스까지 그는 많은 지연 (200) 함수 호출 (Delphi)을 새 코드에 넣었습니다. 생방송 후 불과 20 분이 걸렸으며, CEO 사무실에 출연하여 기한이 지난 모욕을 직접 가져 오라는 명령을 받았습니다.

그가 평소에 테이블을 걷어차 고 CEO와 회사에 대해 불을 지피고 하루 중 나머지 시간을 죽음에 빠뜨리는 동안 동료가 돌아와 웃고, 농담하고, BigMac을 위해 2 ~ 2 번 외출 할 때, 내 동료가 음소거했다 .

당연히 내 동료는 책상에서 하루나 이틀 동안 휴식을 취하여 퀘이크의 조준 기술을 향상 시켰습니다. 그런 다음 두 번째 또는 세 번째 날에 그는 지연 호출을 삭제하고 "긴급 패치"를 재건하고 발표했습니다. 성능 문제를 해결하기 위해 이틀 밤을 보냈습니다.

사악한 CEO가 "훌륭한 직업"이라고 말한 것은 이번이 처음입니다. 그에게. 그게 다야, 맞지?

이것은 진짜 POBI였습니다.

그러나 그것은 일종의 사회적 프로세스 최적화이기도하므로 100 % 괜찮습니다.

내 생각에


"데이터베이스 독립성". 이것은 저장된 procs, 트리거 등을 의미하지 않았으며 외래 키조차도 의미하지 않았습니다.


var stringBuilder = new StringBuilder();
stringBuilder.Append(myObj.a + myObj.b + myObj.c + myObj.d);
string cat = stringBuilder.ToString();

내가 본 StringBuilder를 가장 잘 사용합니다.


간단한 문자열로 충분할 때 정규식을 사용하여 문자열 분할


내가 알고있는이 실에 매우 늦었지만 최근에 이것을 보았습니다.

bool isFinished = GetIsFinished();

switch (isFinished)
{
    case true:
        DoFinish();
        break;

    case false:
        DoNextStep();
        break;

    default:
        DoNextStep();
}

부울에 여분의 값이있는 경우를 대비하여 ...


내가 생각할 수있는 최악의 예는 모든 직원에 대한 정보가 포함 된 회사의 내부 데이터베이스입니다. HR에서 야간 업데이트를 받고 맨 위에 ASP.NET 웹 서비스가 있습니다. 다른 많은 앱은 웹 서비스를 사용하여 검색 / 드롭 다운 필드와 같은 항목을 채 웁니다.

비관론은 개발자가 웹 서비스에 대한 반복 된 호출이 너무 느려서 SQL 쿼리를 반복하기에는 어렵다고 생각했다는 것입니다. 그래서 그는 무엇을 했습니까? 응용 프로그램 시작 이벤트는 전체 데이터베이스에서 읽고 응용 프로그램 풀이 재활용 될 때까지 무기한으로 저장된 메모리의 개체로 모두 변환합니다. 이 코드는 너무 느리기 때문에 2000 명 미만의 직원을로드하는 데 15 분이 걸립니다. 하루 동안 실수로 앱 풀을 재활용 한 경우 각 웹 서비스 요청이 여러 개의 동시 재로드를 시작하므로 30 분 이상 걸릴 수 있습니다. 이러한 이유로, 신규 고용은 계정이 생성 된 첫날에 데이터베이스에 나타나지 않으므로 처음 며칠 동안 대부분의 내부 앱에 액세스 할 수 없어 엄지 손가락을 돌리게됩니다.

비관론의 두 번째 수준은 개발 관리자가 종속 응용 프로그램을 손상시킬 우려가 있기 때문에이를 만지고 싶지는 않지만, 단순한 구성 요소의 설계가 잘못되어 회사 전체에서 중요한 응용 프로그램이 산발적으로 중단되는 일이 계속되고 있다는 것입니다.


아무도 분류에 대해 언급하지 않은 것 같습니다.

여러 번 다른 사람들이 이미 존재했던 "너무 공상적인"퀵 정렬 알고리즘에 대한 호출이 "필요하지 않았기"때문에 누군가가 버블 정렬을 직접 만들었 음을 발견했습니다. 개발자는 손수 만든 Bubblesort가 테스트에 사용하는 10 개 행의 데이터에서 충분히 잘 작동했을 때 만족했습니다. 고객이 몇 천 행을 추가 한 후에는 그다지 잘 진행되지 않았습니다.


한때 Constants 클래스에 이러한 gem을 포함하는 코드를 수정하려고 시도했습니다.

public static String COMMA_DELIMINATOR=",";
public static String COMMA_SPACE_DELIMINATOR=", ";
public static String COLIN_DELIMINATOR=":";

이들 각각은 다른 목적으로 다른 응용 프로그램에서 여러 번 사용되었습니다. COMMA_DELIMINATOR는 8 가지 다른 패키지에서 200 번 이상 사용하면서 코드를 흩뜨 렸습니다.


한 번은 다음과 같은 코드로 가득 찬 앱에서 작업했습니다.

 1 tuple *FindTuple( DataSet *set, int target ) {
 2     tuple *found = null;
 3     tuple *curr = GetFirstTupleOfSet(set);
 4     while (curr) {
 5         if (curr->id == target)
 6             found = curr;
 7         curr = GetNextTuple(curr);
 8     }
 9     return found;
10 }

간단히을 제거 하고 마지막으로 found돌아가서 null여섯 번째 줄을 다음과 같이 변경하십시오.

            return curr;

앱 성능이 두 배가되었습니다.


사내 소프트웨어에서 몇 번이고 반복되는 가장 큰 숫자는 다음과 같습니다.

"나중에 다른 공급 업체로 전환하고 싶을 수 있기 때문에"이식성 때문에 DBMS의 기능을 사용하지 않습니다.

내 입술을 읽으십시오. 사내 작업 : IT가 발생하지 않습니다!


C 컴파일러의 옵티 마이저를 능가하려고 노력하는 동료가 있었고 일상적으로 읽을 수있는 코드를 다시 작성했습니다. 그의 가장 좋아하는 트릭 중 하나는 다음과 같이 읽을 수있는 메소드를 변경하는 것이 었습니다.

int some_method(int input1, int input2) {
    int x;
    if (input1 == -1) {
        return 0;
    }
    if (input1 == input2) {
        return input1;
    }
    ... a long expression here ...
    return x;
}

이것으로 :

int some_method() {
    return (input == -1) ? 0 : (input1 == input2) ? input 1 :
           ... a long expression ...
           ... a long expression ...
           ... a long expression ...
}

즉, 한 번 읽을 수있는 메소드의 첫 번째 행은 " return" 가되고 다른 모든 논리는 깊이 중첩 된 3 차 표현식으로 대체됩니다. 이것이 어떻게 유지 될 수 없는지에 대해 논하려고 할 때, 그는 그의 방법의 어셈블리 출력이 3-4 개의 어셈블리 명령보다 짧다는 사실을 지적 할 것입니다. 그것은 어떤 필요하지 않았다 빠른 그러나 그것은 항상이었다 작은 조금 짧아. 이것은 메모리 사용이 때때로 문제가되는 임베디드 시스템 이었지만 코드를 읽을 수있는 것보다 훨씬 더 최적화가 훨씬 쉬웠습니다.

그런 다음 어떤 이유로 든 ptr->structElement읽을 수 없다고 결정 했기 때문에 (*ptr).structElement더 읽기 쉽고 빠르다는 이론 으로 모든 것을 바꾸기 시작했습니다 .

최대 1 % 향상을 위해 읽을 수있는 코드를 읽을 수없는 코드로 전환하고 때로는 실제로는 더 느린 코드를 만듭니다.


본격적인 개발자로서의 첫 번째 직업 중 하나에서 확장 문제가있는 프로그램의 프로젝트를 인수했습니다. 소규모 데이터 세트에서는 합리적으로 작동하지만 대량의 데이터가 제공되면 완전히 충돌합니다.

내가 파고 들었을 때, 원래 프로그래머는 분석을 병렬화하여 각 데이터 소스마다 새로운 스레드를 시작하여 속도를 높이려고한다는 것을 알았습니다. 그러나 그는 모든 스레드가 교착 상태였던 공유 리소스가 필요하다는 점에서 실수를했습니다. 물론 동시성의 모든 이점은 사라졌습니다. 또한 대부분의 시스템에서 100 개 이상의 스레드 만 시작하여 그 중 하나를 제외한 모든 스레드를 잠급니다. 내 약한 개발 기계는 약 6 시간 안에 150 개의 소스 데이터 세트를 통해 이탈했다는 점에서 예외였다.

이를 수정하기 위해 멀티 스레딩 구성 요소를 제거하고 I / O를 정리했습니다. 다른 변경 사항이 없으면 150 소스 데이터 세트의 실행 시간이 내 컴퓨터에서 10 분 아래로 떨어지고 평균 회사 컴퓨터에서 무한대에서 30 분 아래로 떨어졌습니다.


이 보석을 제공 할 수 있다고 가정합니다.

unsigned long isqrt(unsigned long value)
{
    unsigned long tmp = 1, root = 0;
    #define ISQRT_INNER(shift) \
    { \
        if (value >= (tmp = ((root << 1) + (1 << (shift))) << (shift))) \
        { \
            root += 1 << shift; \
            value -= tmp; \
        } \
    }

    // Find out how many bytes our value uses
    // so we don't do any uneeded work.
    if (value & 0xffff0000)
    {
        if ((value & 0xff000000) == 0)
            tmp = 3;
        else
            tmp = 4;
    }
    else if (value & 0x0000ff00)
        tmp = 2;

    switch (tmp)
    {
        case 4:
            ISQRT_INNER(15);
            ISQRT_INNER(14);
            ISQRT_INNER(13);
            ISQRT_INNER(12);
        case 3:
            ISQRT_INNER(11);
            ISQRT_INNER(10);
            ISQRT_INNER( 9);
            ISQRT_INNER( 8);
        case 2:
            ISQRT_INNER( 7);
            ISQRT_INNER( 6);
            ISQRT_INNER( 5);
            ISQRT_INNER( 4);
        case 1:
            ISQRT_INNER( 3);
            ISQRT_INNER( 2);
            ISQRT_INNER( 1);
            ISQRT_INNER( 0);
    }
#undef ISQRT_INNER
    return root;
}

Since the square-root was calculated at a very sensitive place, I got the task of looking into a way to make it faster. This small refactoring reduced the execution time by a third (for the combination of hardware and compiler used, YMMV):

unsigned long isqrt(unsigned long value)
{
    unsigned long tmp = 1, root = 0;
    #define ISQRT_INNER(shift) \
    { \
        if (value >= (tmp = ((root << 1) + (1 << (shift))) << (shift))) \
        { \
            root += 1 << shift; \
            value -= tmp; \
        } \
    }

    ISQRT_INNER (15);
    ISQRT_INNER (14);
    ISQRT_INNER (13);
    ISQRT_INNER (12);
    ISQRT_INNER (11);
    ISQRT_INNER (10);
    ISQRT_INNER ( 9);
    ISQRT_INNER ( 8);
    ISQRT_INNER ( 7);
    ISQRT_INNER ( 6);
    ISQRT_INNER ( 5);
    ISQRT_INNER ( 4);
    ISQRT_INNER ( 3);
    ISQRT_INNER ( 2);
    ISQRT_INNER ( 1);
    ISQRT_INNER ( 0);

#undef ISQRT_INNER
    return root;
}

Of course there are both faster AND better ways to do this, but I think it's a pretty neat example of a pessimization.

Edit: Come to think of it, the unrolled loop was actually also a neat pessimization. Digging though the version control, I can present the second stage of refactoring as well, which performed even better than the above:

unsigned long isqrt(unsigned long value)
{
    unsigned long tmp = 1 << 30, root = 0;

    while (tmp != 0)
    {
        if (value >= root + tmp) {
            value -= root + tmp;
            root += tmp << 1;
        }
        root >>= 1;
        tmp >>= 2;
    }

    return root;
}

This is exactly the same algorithm, albeit a slightly different implementation, so I suppose it qualifies.


This might be at a higher level that what you were after, but fixing it (if you're allowed) also involves a higher level of pain:

Insisting on hand rolling an Object Relationship Manager / Data Access Layer instead of using one of the established, tested, mature libraries out there (even after they've been pointed out to you).


All foreign-key constraints were removed from a database, because otherwise there would be so many errors.


This doesn't exactly fit the question, but I'll mention it anyway a cautionary tale. I was working on a distributed app that was running slowly, and flew down to DC to sit in on a meeting primarily aimed at solving the problem. The project lead started to outline a re-architecture aimed at resolving the delay. I volunteered that I had taken some measurements over the weekend that isolated the bottleneck to a single method. It turned out there was a missing record on a local lookup, causing the application to have to go to a remote server on every transaction. By adding the record back to the local store, the delay was eliminated - problem solved. Note the re-architecture wouldn't have fixed the problem.


Checking before EVERY javascript operation whether the object you are operating upon exists.

if (myObj) { //or its evil cousin, if (myObj != null) {
    label.text = myObj.value; 
    // we know label exists because it has already been 
    // checked in a big if block somewhere at the top
}

My problem with this type of code is nobody seems to care what if it doesn't exist? Just do nothing? Don't give the feedback to the user?

I agree that the Object expected errors are annoying, but this is not the best solution for that.


How about YAGNI extremism. It is a form of premature pessimization. It seems like anytime you apply YAGNI, then you end up needing it, resulting in 10 times the effort to add it than if you had added it in the beginning. If you create a successful program then odds are YOU ARE GOING TO NEED IT. If you are used to creating programs whose life runs out quickly then continue to practice YAGNI because then I suppose YAGNI.


Not exactly premature optimisation - but certainly misguided - this was read on the BBC website, from an article discussing Windows 7.

Mr Curran said that the Microsoft Windows team had been poring over every aspect of the operating system to make improvements. "We were able to shave 400 milliseconds off the shutdown time by slightly trimming the WAV file shutdown music.

Now, I haven't tried Windows 7 yet, so I might be wrong, but I'm willing to bet that there are other issues in there that are more important than how long it takes to shut-down. After all, once I see the 'Shutting down Windows' message, the monitor is turned off and I'm walking away - how does that 400 milliseconds benefit me?


Someone in my department once wrote a string class. An interface like CString, but without the Windows dependence.

One "optimization" they did was to not allocate any more memory than necessary. Apparently not realizing that the reason classes like std::string do allocate excess memory is so that a sequence of += operations can run in O(n) time.

Instead, every single += call forced a reallocation, which turned repeated appends into an O(n²) Schlemiel the Painter's algorithm.


An ex-coworker of mine (a s.o.a.b., actually) was assigned to build a new module for our Java ERP that should have collected and analyzed customers' data (retail industry). He decided to split EVERY Calendar/Datetime field in its components (seconds, minutes, hours, day, month, year, day of week, bimester, trimester (!)) because "how else would I query for 'every monday'?"


No offense to anyone, but I just graded an assignment (java) that had this

import java.lang.*;

참고URL : https://stackoverflow.com/questions/312003/what-is-the-most-ridiculous-pessimization-youve-seen

반응형