최적화는 좋은 결과보다는 해로운 결과로 이어지기 쉽고, 섣불리 진행하면 특히 더 그렇습니다. 빠르지도 않고 제대로 동작하지도 않으면서 수정하기는 어려운 소프트웨어를 탄생시키는 것입니다.
성능 때문에 견고한 구조를 희생하지 맙시다. 좋은 프로그램이지만 원하는 성능이 나오지 않는다면 그 아키텍처 자체가 최적화할 수 있는 길을 안내해줄 것입니다. 좋은 프로그램은 정보 은닉 원칙을 따르므로 개별 구성요소의 내부를 독립적으로 설계할 수 있습니다. 따라서 시스템의 나머지에 영향을 주지 않고도 각 요소를 다시 설계할 수 있습니다.(아이템 15 - 클래스와 멤버의 접근 권한을 최소화하라)
프로그램을 완성할 때까지 성능 문제를 무시하라는 뜻이 아닙니다. 구현상의 문제는 나중에 최적화해 해결할 수 있지만, 아키텍처의 결함이 성능을 제한하는 상황이라면 시스템 전체를 다시 작성하지 않고는 해결하기 불가능할 수 있습니다. 완성된 설계의 기본 틀을 변경하려다 보면 유지보수하거나 개선하기 어려운 꼬인 구조의 시스템이 만들어지기 쉽기 때문입니다. 그래서 설계 단계에서 반드시 성능을 염두에 두어야 합니다.
완성 후 변경하기가 가정 어려운 설계 요소는 바로 컴포넌트끼리, 혹은 외부 시스템과 하는 소통 방식입니다. API, 네트워크 프로토콜 등이 대표적입니다. 이런 설계 요소들은 완성 후에는 변경하기 어렵거나 불가능 할 수 있고 시스템 성능을 심각하게 제한할 수 있습니다.
public 타입을 가변으로 만들면, 즉 내부 데이터를 변경할 수 있게 만들면 불필요한 방어적 복사를 수없이 유발할 수 있습니다(아이템 50 - 적시에 방어적 복사본을 만들라). 비슷하게, 컴포지션으로 해결할 수 있음에도 상속 방식으로 설계한 public 클래스는 상위 클래스에 영원히 종속되며 그 성능 제약까지도 물려받게 됩니다(아이템 18 - 상속보다는 컴포지션을 사용하라) 인터페이스도 있는데 굳이 구현타입을 사용하는 것도 좋지 않습니다. 특정 구현체에 종속되게 하여 나중에 더 빠른 구현체가 나오더라도 이용하지 못하게 됩니다(아이템 64 - 객체는 인터페이스를 사용해 참조하라).
잘 설계된 API는 보통 성능도 좋습니다. 그러므로 성능을 위해 API를 왜곡하는 건 매우 좋지 않습니다. API를 왜곡하도록 만든 그 성능 문제는 해당 플랫폼이나 소프트웨어의 다음 버전에서 사라질 수도 있지만, 왜곡된 API와 이를 지원하는 데 따르는 고통은 더 오래 지속될 것입니다.
신중한 설계를 바탕으로 한 명확한 구조를 가진 프로그램을 완성한 다음에야 최적화를 고려하십시오. 물론 성능에 만족하지 못할 경우에만입니다.
아마 측정 결과에 놀랄지도 모릅니다. 시도한 최적화 기법이 성능을 눈에 띄게 높이지 못하는 경우가 많고, 심지어 더 나빠지게 할 수도 있습니다. 주요 원인은 우리의 프로그램에서 시간을 잡아먹는 부분을 추측하기 어렵기 때문입니다. 느릴 거라고 생각한 부분이 사실은 성능에 별 영향을 주지 않는 곳이라면 시간만 허비한 셈입니다. 일반적으로 90%의 시간을 단 10%의 코드에서 사용한다는 사실을 기억하십시오.
프로파일링 도구(profiling tool)는 최적화 노력을 어디에 집중해야 할지 찾는 데 도움을 줍니다. 이런 도구는 개별 메서드의 소비 시간과 호출 횟수 같은 런타입 정보를 제공해, 집중 할 곳과 알고리즘을 변경해야 한다는 사실을 알려줍니다.
좋은 프로그램을 작성하다 보면 성능은 따라오게 마련입니다. 하지만 시스템을 설계할 때, 특히 API, 네트워크 프로토콜등을 설계 할 때는 성능을 염두에 두십시오. 이것들이 완료 된 이후에는 성능을 측정해보고 개선 할 필요성이 있는 경우 프로파일러를 사용해 문제의 원인이 되는 지점을 찾아 최적화를 수행하면 됩니다.