effective-swift

item 67. 최적화는 신중히 하라

(맹목적인 어리석음을 포함해) 그 어떤 핑계보다 효율성이라는 이름 아래 행해진 컴퓨팅 죄악이 더 많다(심지어 효율을 높이지도 못하면서). - 윌리엄 울프(Wulf72)
(전체의 97% 정도인) 자그마한 효율성은 모두 잊자. 섣부른 최적화가 만악의 근원이다. - 도널드 크누스(Knuth74)
최적화를 할 때는 다음 두 규칙을 따르라. 첫 번째, 하지 마라. 두 번째, (전문가 한정) 아직 하지 마라. 다시 말해, 완전히 명백하고 최적화되지 않은 해법을 찾을 때까지는 하지 마라. - M. A. 잭슨(Jackson75)

최적화는 좋은 결과보다는 해로운 결과로 이어지기 쉽고, 섣불리 진행하면 특히 더 그렇습니다. 빠르지도 않고 제대로 동작하지도 않으면서 수정하기는 어려운 소프트웨어를 탄생시키는 것입니다.


설계 시 고려할 점

빠른 프로그램보다는 좋은 프로그램을 작성하라.

성능 때문에 견고한 구조를 희생하지 맙시다. 좋은 프로그램이지만 원하는 성능이 나오지 않는다면 그 아키텍처 자체가 최적화할 수 있는 길을 안내해줄 것입니다. 좋은 프로그램은 정보 은닉 원칙을 따르므로 개별 구성요소의 내부를 독립적으로 설계할 수 있습니다. 따라서 시스템의 나머지에 영향을 주지 않고도 각 요소를 다시 설계할 수 있습니다.(아이템 15 - 클래스와 멤버의 접근 권한을 최소화하라)

프로그램을 완성할 때까지 성능 문제를 무시하라는 뜻이 아닙니다. 구현상의 문제는 나중에 최적화해 해결할 수 있지만, 아키텍처의 결함이 성능을 제한하는 상황이라면 시스템 전체를 다시 작성하지 않고는 해결하기 불가능할 수 있습니다. 완성된 설계의 기본 틀을 변경하려다 보면 유지보수하거나 개선하기 어려운 꼬인 구조의 시스템이 만들어지기 쉽기 때문입니다. 그래서 설계 단계에서 반드시 성능을 염두에 두어야 합니다.

성능을 제한하는 설계를 피하라.

완성 후 변경하기가 가정 어려운 설계 요소는 바로 컴포넌트끼리, 혹은 외부 시스템과 하는 소통 방식입니다. API, 네트워크 프로토콜 등이 대표적입니다. 이런 설계 요소들은 완성 후에는 변경하기 어렵거나 불가능 할 수 있고 시스템 성능을 심각하게 제한할 수 있습니다.

API를 설계할 때 성능에 주는 영향을 고려하라.

public 타입을 가변으로 만들면, 즉 내부 데이터를 변경할 수 있게 만들면 불필요한 방어적 복사를 수없이 유발할 수 있습니다(아이템 50 - 적시에 방어적 복사본을 만들라). 비슷하게, 컴포지션으로 해결할 수 있음에도 상속 방식으로 설계한 public 클래스는 상위 클래스에 영원히 종속되며 그 성능 제약까지도 물려받게 됩니다(아이템 18 - 상속보다는 컴포지션을 사용하라) 인터페이스도 있는데 굳이 구현타입을 사용하는 것도 좋지 않습니다. 특정 구현체에 종속되게 하여 나중에 더 빠른 구현체가 나오더라도 이용하지 못하게 됩니다(아이템 64 - 객체는 인터페이스를 사용해 참조하라).

성능을 위해 API를 왜곡하지 말라.

잘 설계된 API는 보통 성능도 좋습니다. 그러므로 성능을 위해 API를 왜곡하는 건 매우 좋지 않습니다. API를 왜곡하도록 만든 그 성능 문제는 해당 플랫폼이나 소프트웨어의 다음 버전에서 사라질 수도 있지만, 왜곡된 API와 이를 지원하는 데 따르는 고통은 더 오래 지속될 것입니다.

신중한 설계를 바탕으로 한 명확한 구조를 가진 프로그램을 완성한 다음에야 최적화를 고려하십시오. 물론 성능에 만족하지 못할 경우에만입니다.

각각의 최적화 시도 전후로 성능을 측정하라

아마 측정 결과에 놀랄지도 모릅니다. 시도한 최적화 기법이 성능을 눈에 띄게 높이지 못하는 경우가 많고, 심지어 더 나빠지게 할 수도 있습니다. 주요 원인은 우리의 프로그램에서 시간을 잡아먹는 부분을 추측하기 어렵기 때문입니다. 느릴 거라고 생각한 부분이 사실은 성능에 별 영향을 주지 않는 곳이라면 시간만 허비한 셈입니다. 일반적으로 90%의 시간을 단 10%의 코드에서 사용한다는 사실을 기억하십시오.

프로파일링 도구(profiling tool)는 최적화 노력을 어디에 집중해야 할지 찾는 데 도움을 줍니다. 이런 도구는 개별 메서드의 소비 시간과 호출 횟수 같은 런타입 정보를 제공해, 집중 할 곳과 알고리즘을 변경해야 한다는 사실을 알려줍니다.


정리

좋은 프로그램을 작성하다 보면 성능은 따라오게 마련입니다. 하지만 시스템을 설계할 때, 특히 API, 네트워크 프로토콜등을 설계 할 때는 성능을 염두에 두십시오. 이것들이 완료 된 이후에는 성능을 측정해보고 개선 할 필요성이 있는 경우 프로파일러를 사용해 문제의 원인이 되는 지점을 찾아 최적화를 수행하면 됩니다.