최적화는 신중히 하라

최적화는 좋은 결과보다는 해로운 결과로 이어지기 쉽다.

빠른 프로그램보다는 좋은 프로그램

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

설계 단계에서 성능을 염두에 두자

구현상의 문제는 나중에 최적화해 해결할 수 있지만, 아키텍처의 결함이 성능을 제한하는 상황이라면 시스템 전체를 다시 작성하지 않고는 해결하기 불가능할 수 있다. 완성된 설계의 기본 틀을 변경하려다 보면 유지보수하거나 개선하기 어려운 꼬인 구조의 시스템이 만들어지기 쉽기 때문이다.

성능을 제한하는 설계를 피하자

완성 후 변경하기가 가장 어려운 설계 요소는 바로 컴포넌트끼리, 혹은 외부 시스템과의 소통 방식이다. API, 네트워크 프로토콜, 영구 저장용 데이터 포맷 등이 대표적이다. 이런 설계 요소들은 완성 후에는 변경하기 어렵거나 불가능할 수 있으며, 동시에 시스템 성능을 심각하게 제한할 수 있다.

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

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

잘 설계된 API는 성능도 좋은게 보통이다. 성능을 위해 API를 왜곡하는 건 매우 안 좋은 생각이다. API를 왜곡하도록 만든 그 성능 문제는 해당 플랫폼이나 아랫단 소프트웨어의 다음 버전에서 사라질 수도 있지만, 왜곡된 API와 이를 지원하는 데 따르는 고통은 영원히 계속될 것이다.

최적화 시도 전후의 성능 측정

성능 측정은 C와 C++ 같은 전통적인 언어에서도 중요하지만, 성능 모델이 덜 정교한 자바에서는 중요성이 더욱 크다. 자바는 다양한 기본 연산에 드는 상대적인 비용을 덜 명확하게 정의하고 있다. 다시 말해, 프로그래머가 작성하는 코드와 CPU에서 수행하는 명령 사이의 추상화 격차가 커서 최적화로 인한 성능 변화를 일정하게 예측하기가 더 어렵다.

자바의 성능 모델은 정교하지 않을뿐더러 구현 시스템, 릴리스, 프로세서마다 차이가 있다. 프로그램을 여러 가지 자바 플랫폼이나 여러 하드웨어 플랫폼에서 구동한다면 최적화의 효과를 각각에서 측정해야 한다.

좋은 프로그램을 작성하다 보면 성능은 따라오게 된다. 하지만 시스템을 설계할 때, 특히 API, 네트워크 프로토콜, 영구 저장용 데이터 포맷을 설계할 때는 성능을 염두에 두어야 한다. 시스템 구현을 완료했다면 성능을 측정하자. 충분히 빠르면 그것으로 끝이다. 그렇지 않다면 프로파일러를 사용해 문제의 원인이 되는 지점을 찾아 최적화를 수행하자. 가장 먼저 어떤 알고리즘을 사용했는지를 살펴보자. 알고리즘을 잘못 골랐다면 다른 저수준 최적화는 아무리 해봐야 소용없다. 만족할 때까지 이 과정을 반복하고, 모든 변경 후 성능을 측정하자.

Comments