우리는 조기 최적화가 코드를 읽을 수 없거나 유지할 수 없기 때문에 모든 악의 근원이라는 것을 알고 있습니다. 누군가가 "최적화"를 구현하면 더 빠를 것이라고 생각 하기 때문에 비관 화가 더 심해 집니다. 그러나 더 느리고 결국 버그가 많고 유지 관리가 불가능한 등의 결과가 나옵니다. ?
우리는 조기 최적화가 코드를 읽을 수 없거나 유지할 수 없기 때문에 모든 악의 근원이라는 것을 알고 있습니다. 누군가가 "최적화"를 구현하면 더 빠를 것이라고 생각 하기 때문에 비관 화가 더 심해 집니다. 그러나 더 느리고 결국 버그가 많고 유지 관리가 불가능한 등의 결과가 나옵니다. ?
답변:
오래된 프로젝트에서 우리는 방대한 Z-8000 경험을 가진 일부 (그렇지 않으면 우수한) 임베디드 시스템 프로그래머를 물려 받았습니다.
우리의 새로운 환경은 32 비트 Sparc Solaris였습니다.
RAM 중 16 비트를 잡는 것이 32 비트를 잡는 것보다 빠르기 때문에 녀석 중 한 명이 가서 모든 정수를 반바지로 변경하여 코드 속도를 높였습니다.
32 비트 시스템에서 32 비트 값을 잡는 것이 16 비트 값을 잡는 것보다 빠르다는 것을 보여주기 위해 데모 프로그램을 작성해야했으며 16 비트 값을 잡으려면 CPU가 32 비트 너비를 가져야한다고 설명했습니다 메모리 액세스 후 16 비트 값에 필요하지 않은 비트를 마스킹 또는 시프트합니다.
"초기 최적화는 모든 악의 근원"이라는 문구가 사용 된 방식이라고 생각합니다. 많은 프로젝트의 경우 프로젝트 후반까지 성능을 고려하지 않는 것이 변명되었습니다.
이 문구는 종종 사람들이 일을 피하기위한 목발입니다. 나는 사람들이 정말로 "Gee, 우리는 그것을 미리 생각하지 않았고 지금 그것을 다룰 시간이 없다"고 말할 때이 문구가 사용 된 것을 본다.
나는 "pesimization"으로 인해 발생한 문제의 예보다 멍청한 성능 문제에 대한 더 많은 "우스꽝스러운"예를 보았습니다.
내가 더 나은 진술이라고 생각하는 것은 "측정과 이해없는 최적화는 전혀 최적화가 아니라 무작위 변화"라는 것이다.
우수한 성능 작업은 시간이 많이 걸리며 기능 또는 구성 요소 자체의 개발에 더 많은 시간이 소요됩니다.
데이터베이스는 비관적 인 플레이 랜드입니다.
즐겨 찾기에는 다음이 포함됩니다.
그것은 내 머리 꼭대기에서 벗어났다.
나는 절대적인 규칙이 없다고 생각합니다. 어떤 것들은 가장 잘 최적화되어 있고 어떤 것은 그렇지 않습니다.
예를 들어 위성에서 데이터 패킷을 수신 한 회사에서 근무했습니다. 각 패킷은 많은 비용이 들기 때문에 모든 데이터가 고도로 최적화되었습니다 (즉, 압축). 예를 들어 위도 / 경도는 절대 값 (부동)으로 전송되지 않고 "현재"영역의 "북서쪽"코너에 상대적인 오프셋으로 전송되었습니다. 사용하기 전에 모든 데이터의 압축을 풀어야했습니다. 그러나 이것은 비관적이지 않다고 생각합니다. 통신 비용을 줄이는 것은 지능적인 최적화입니다.
반면 소프트웨어 설계자는 압축을 푼 데이터를 읽을 수있는 XML 문서로 형식화하고 각 열을 해당 열에 저장하는 것과 달리 데이터베이스에 저장해야한다고 결정했습니다. 그들의 아이디어는 "XML은 미래입니다", "디스크 공간은 싸다", "프로세서는 싸다"라는 것이므로 아무것도 최적화 할 필요가 없었습니다. 그 결과 16 바이트 패킷이 한 열에 저장된 2kB 문서로 바뀌 었으며 간단한 쿼리조차도 메가 바이트의 XML 문서를 메모리에로드해야했습니다! 초당 50 개가 넘는 패킷을 받았으므로 성능이 얼마나 끔찍한 지 상상할 수 있습니다 (BTW, 회사 파산).
다시 말하지만 절대 규칙은 없습니다. 예, 때로는 너무 일찍 최적화하는 것은 실수입니다. 그러나 때때로 "cpu / disk space / memory is cheap"모토는 모든 악의 근원입니다.
오 주여, 나는 그들 모두를 본 것 같아요. 너무 자주 게으른 사람이 성능 문제의 원인으로 문제를 해결하거나 실제로 성능 문제가 있는지 여부를 조사하기 위해 성능 문제를 해결하려는 노력이 종종 있습니다. 이 중 많은 경우에 특정 기술을 시험 해보고 싶어하는 사람이 반짝이는 새 망치에 맞는 못을 필사적으로 찾고 있는지 궁금합니다.
최근 예는 다음과 같습니다.
데이터 아키텍트는 상당히 크고 복잡한 응용 프로그램에서 키 테이블을 세로로 분할하는 정교한 제안을 제공합니다. 그는 변화에 적응하기 위해 어떤 유형의 개발 노력이 필요한지 알고 싶어합니다. 대화는 다음과 같이 진행되었습니다.
나 : 왜 이걸 고려하고 있니? 해결하려는 문제는 무엇입니까?
그를: 표 X가 너무 넓어서 성능상의 이유로 분할하고 있습니다.
나 : 왜 그렇게 넓다고 생각하니?
컨설턴트 : 컨설턴트는 한 테이블에 너무 많은 열이 있다고 말했다.
나 : 그리고 이것은 성능에 영향을 미치고 있습니까?
사용자 : 그렇습니다. 사용자는 애플리케이션의 XYZ 모듈에서 간헐적 인 속도 저하를보고했습니다.
나 : 테이블 너비가 문제의 원인이라는 것을 어떻게 알 수 있습니까?
그 : 그것은 XYZ 모듈이 사용하는 키 테이블이며, 200 열과 같습니다. 문제가되어야합니다.
Me (설명) : 그러나 XYZ 모듈은 특히 해당 테이블의 대부분의 열을 사용하며 사용자가 해당 테이블에서 표시하려는 데이터를 표시하도록 앱을 구성하기 때문에 사용하는 열을 예측할 수 없습니다. 그것은 시간의 95 %는 우리가 것이다 어쨌든 다시 함께 모든 테이블을 조인 바람 줄 가능성이 상처 성능을.
그 : 컨설턴트는 너무 넓어서 변경해야한다고 말했습니다.
나 : 이 컨설턴트는 누구입니까? 컨설턴트를 고용하거나 개발 팀과 전혀 대화하지 않았습니다.
그분 : 글쎄, 우리는 아직 그들을 고용하지 않았습니다. 이것은 그들이 제안한 제안의 일부이지만, 우리는이 데이터베이스를 재구성 할 필요가 있다고 주장했다.
나 : 어. 데이터베이스 재 설계 서비스를 판매하는 컨설턴트는 데이터베이스 재 설계가 필요하다고 생각합니다.
대화는 이런 식으로 진행되었습니다. 그 후, 문제의 테이블을 다시 살펴보고 이국적인 분할 전략이 필요하지 않은 간단한 정규화로 좁힐 수 있다고 결정했습니다. 물론 성능 문제 (이전에는보고되지 않음)를 조사하고 다음 두 가지 요소로 추적하면 문제가 될 수 있습니다.
물론 건축가는 여전히 "너무 넓은"메타 문제에 매달려있는 테이블의 수직 분할을 추진하고있다. 또한 앱을 보거나 성능 분석을 실행하지 않고도 데이터베이스에 대한 주요 디자인 변경이 필요하다고 판단한 다른 데이터베이스 컨설턴트의 제안을 받아 자신의 사례를 강화했습니다.
알파 드라이브 -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가 동기화되어 있기 때문에 몇 개의 문자열 만 연결하면 실제로 추가 오버 헤드가 있다는 것입니다. (이 규모에서는 그 차이가 절대적으로 사소한 것은 말할 것도 없습니다.)이 연습에 대한 두 가지 다른 점 :
한 번은 '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와 회사에 대해 불을 지피고 하루 종일을 죽이는 동안 돌아 왔고, 웃고, 농담하고, 빅맥을 위해 외출 할 때 내 동료들이 음소거했다. .
당연히 내 동료는 책상에서 하루나 이틀 동안 휴식을 취하여 퀘이크의 조준 기술을 향상 시켰습니다. 그런 다음 두 번째 또는 세 번째 날에 그는 지연 호출을 삭제하고 "긴급 패치"를 재건하고 발표했습니다. 성능 문제를 해결하기 위해 이틀 밤을 보냈습니다.
사악한 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 개 행의 데이터에서 충분히 잘 작동했을 때 만족했습니다. 고객이 몇 천 행을 추가 한 후에는 그다지 잘 진행되지 않았습니다.
한 번은 다음과 같은 코드로 가득 찬 앱에서 작업했습니다.
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;
앱 성능이 두 배가되었습니다.
한때 Constants 클래스에 이러한 gem을 포함하는 코드를 수정하려고 시도했습니다.
public static String COMMA_DELIMINATOR=",";
public static String COMMA_SPACE_DELIMINATOR=", ";
public static String COLIN_DELIMINATOR=":";
이들 각각은 다른 목적으로 다른 응용 프로그램에서 여러 번 사용되었습니다. COMMA_DELIMINATOR는 8 가지 다른 패키지에서 200 번 이상 사용하면서 코드를 흩뜨 렸습니다.
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 % 향상을 위해 읽을 수있는 코드를 읽을 수없는 코드로 전환하고 때로는 실제로는 더 느린 코드를 만듭니다.
if
. C의 표현에 대한 진술에 대한 주장은 어떤 종류의 객관적인 관행이 아니라 문화적 / 종교적 교리 입니다. (더 나은 지침 : 중첩 된 삼항이 읽기에 너무 길면 if
어느 쪽 도 사용하지 않아야 합니다.)
if
함수에서 단일 을 가져 와서 삼항으로 바꾸는 것에 대해 이야기하지 않습니다 . 괜찮고 종종 더 읽기 쉽습니다. 전체 30 + 라인 메소드를 단일 return 문과 중첩 삼항으로 바꾸는 것에 대해 이야기하고 있습니다. 아무도 새로운 코드가 더 읽기 쉽다고 생각했지만 한 개발자가 더 빠르다고 생각했습니다.
본격적인 개발자로서의 첫 번째 직업 중 하나에서 확장 문제가있는 프로그램의 프로젝트를 인수했습니다. 소규모 데이터 세트에서는 합리적으로 작동하지만 대량의 데이터가 제공되면 완전히 충돌합니다.
내가 파고 들었을 때, 원래 프로그래머는 분석을 병렬화하여 각 데이터 소스마다 새로운 스레드를 시작하여 속도를 높이려고한다는 것을 알았습니다. 그러나 그는 모든 스레드가 교착 상태였던 공유 리소스가 필요하다는 점에서 실수를했습니다. 물론 동시성의 모든 이점은 사라졌습니다. 또한 대부분의 시스템에서 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;
}
제곱근은 매우 민감한 장소에서 계산되었으므로 더 빨리 만드는 방법을 찾아야했습니다. 이 작은 리팩토링은 실행 시간을 3 분의 1로 줄였습니다 (하드웨어와 컴파일러 사용 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;
}
물론이 작업을 수행하는 더 빠르고 더 좋은 방법이 있지만 비관 화의 깔끔한 예라고 생각합니다.
편집 : 그것을 생각해 보면, 풀린 루프는 실제로 깔끔한 비관 화였습니다. 버전 제어를 통해 파고 들자면 리팩토링의 두 번째 단계도 제시 할 수 있습니다.
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;
}
약간 다른 구현이지만 이것은 정확히 동일한 알고리즘이므로 자격이 있다고 가정합니다.
isqrt()
계산 한다고 가정 floor(sqrt())
하지만이 코드가 왜 작동합니까?
이것은 당신이 그랬던 것보다 더 높은 수준에 있지만, 그것을 고치면 (허용되는 경우) 더 높은 수준의 고통이 수반됩니다.
확립되고 테스트 된 성숙한 라이브러리 중 하나를 사용하는 대신 (고객이 지적한 후에도) Object Relationship Manager / Data Access Layer를 직접 롤링해야합니다.
이것은 정확히 질문에 맞지는 않지만 어쨌든주의 이야기에 대해 언급하겠습니다. 나는 느리게 실행되는 분산 응용 프로그램을 만들고 있었고 DC로 내려가 문제 해결을 목표로 한 회의에 참석했습니다. 프로젝트 리더는 지연 해결을 목표로 재구성을 개괄하기 시작했습니다. 나는 병목 현상을 단일 방법으로 격리하는 주말에 몇 가지 측정을 수행했다고 자원했다. 로컬 조회에 누락 된 레코드가있어 애플리케이션이 모든 트랜잭션에서 원격 서버로 이동해야하는 것으로 나타났습니다. 레코드를 다시 로컬 저장소에 추가함으로써 지연이 제거되었습니다. 문제가 해결되었습니다. 재 아키텍처로도 문제가 해결되지 않았 음을 참고하십시오.
모든 자바 스크립트 작업 전에 작동중인 객체가 존재하는지 확인하십시오.
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
}
이 유형의 코드에 대한 내 문제는 아무도 존재하지 않으면 어떻게 신경 쓰지 않는 것입니까? 아무것도하지 않습니까? 사용자에게 피드백을 제공하지 않습니까?
Object expected
오류가 성가신 다는 데 동의 하지만 이것이 최선의 해결책은 아닙니다.
YAGNI 극단주의는 어떻습니까. 조기 비관 화의 한 형태입니다. YAGNI를 적용 할 때마다 필요한 것 같아서 처음에 추가했을 때보 다 10 배의 노력이 필요합니다. 성공적인 프로그램을 만들면 IT가 필요할 가능성이 높습니다. 삶이 빨리 소모되는 프로그램을 만드는 데 익숙하다면 YAGNI를 계속 연습하십시오 .YAGNI라고 가정합니다.
조기 최적화는 아니지만 확실하게 잘못 안내 된 것은 Windows 7에 대한 기사에서 BBC 웹 사이트에서 읽었습니다.
Curran은 Microsoft Windows 팀이 개선을 위해 운영 체제의 모든 측면을 검토하고 있다고 말했습니다. "WAV 파일 종료 음악을 약간 잘라서 종료 시간을 400 밀리 초로 줄일 수있었습니다.
이제 Windows 7을 아직 시도하지 않았으므로 잘못되었을 수도 있지만 종료하는 데 걸리는 시간보다 더 중요한 다른 문제가 있음을 확신합니다. 결국 'Shutting down Windows'메시지가 표시되면 모니터가 꺼지고 걸어가는 것입니다. 400 밀리 초는 어떤 이점이 있습니까?
내 부서의 누군가가 한 번 문자열 클래스를 작성했습니다. 같은 인터페이스CString
이지만 Windows 의존성이 없습니다.
그들이 한 "최적화" 는 필요한 것보다 더 많은 메모리를 할당하지 않는 것이 었습니다 . 클래스 std::string
가 초과 메모리를 할당하는 것과 같은 이유 +=
가 O (n) 시간 내에 일련의 작업을 실행할 수 있다는 것을 분명히 알지 못합니다 .
대신, 모든 단일 +=
호출 이 재 할당을 강요하여 반복 된 추가가 O (n²) Schlemiel the Painter 's algorithm으로 바뀌 었습니다 .
고객의 데이터 (소매 산업)를 수집하고 분석해야하는 Java ERP 용 새 모듈을 구축하기 위해 전직 동료 ( 실제로 soab )를 지정했습니다. 그는 "달마다 '어떻게 월요일에 쿼리합니까?"
누구에게도 공격하지 않지만 방금 과제가있는 과제 (자바)를 채점했습니다.
import java.lang.*;