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

최적화에 대한 명언

맹목적인 어리석음을 포함해 그 어떤 핑계보다 효율성이라는 이름 아래 행해진 컴퓨팅 죄악이 더 많다 (심지어 효율을 높이지도 못하면서)

- 윌리엄 울프(Wulf72)

(전체의 97% 정도인) 자그마한 효율성은 모두 잊자. 섣부른 최적화가 만약의 근원이다. - 도널드 크누스(Knuth74)

최적화를 할 때는 다음 두 규칙을 따르라.

첫 번째, 하지마라.
두 번째, (전문가 한정) 아직 하지 마라. 다시 말해, 완전히 명백하고 최적화되지 않은 해법을 찾을 때까지는 하지 마라.
- M.A 잭슨 (Jackson75)

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

프로그램을 설계할 때 생각해야 할 점

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

  • 좋은 프로그램이지만 원하는 성능이 나오지 않는다면 그 아키텍처 자체가 최적화할 수 있는 길을 안내해줄 것이다.
  • 좋은 프로그램은 정보 은닉(캡슐화) 원칙을 따르므로 개별 구성요소 내부를 독립적으로 설계할 수 있다.
  • 따라서 시스템의 나머지에 영향을 주지 않고도 각 요소를 다시 설계할 수 있다.
  • 구현상의 문제는 나중에 최적화 할 수 있지만, 아키텍처의 결함이 성능을 제한한다면 시스템을 다시 작성해야 하기 때문이다.
  • 따라서 설계 단계에서 성능을 반드시 염두하자

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

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

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

  • 가변 객체를 사용하여 내부데이터를 변경할 수 있게 만들면 불필요한 방어적 복사를 유발할 수 있다.
  • 컴포지션으로 해결할 수 있는 경우에도 상속을 이용하면 상위클래스에 영원히 종속되고, 성능 제약까지 물려받는다
  • 인터페이스도 있는데 굳이 클래스 타입으로 사용하면, 차후 개선된 구현체를 사용하기 어려워진다.

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

  • API를 왜곡하도록 만든 성능 문제는 해당 플랫폼이나 아랫단 소프트웨어의 다음 버전에서 사라질 수 있다.
  • 왜곡된 API를 지원하는 데 따르는 고통은 영원하다

프로파일링 도구를 적극 활용하자

  • 프로파일링 도구는 최적화 노력을 어디에 집중해야 할지 찾는 데 도움을 준다.
  • 개별 메서드의 소비 시간과 호출 횟수 같은 런타임 정보를 제공하여 개발자의 수고를 덜어준다.
  • JMH도 알아야 하는 도구이다. 프로파일러는 아니지만 자바 코드의 상세한 성능을 알기 쉽게 보여주는 마이크로 벤치마킹 프레임워크다.

정리

  • 빠른프로그램을 작성하려 하지 말고 좋은 프로그램을 작성하려 노력하자. 성능은 따라오기 마련이다.
  • 시스템을 설계할 때 API, 네트워크 프로토코르 영구 저장용 데이터 포맷을 설계할 때는 성능을 염두하자
  • 시스템 구현을 완료했으면 측정해보고 충분히 빠르면 최적화를 하지 마라
  • 성능 측정 시에는 프로파일링 도구를 이용해 문제의 원인이 되는 지점을 찾아 최적화하자
  • 알고리즘을 잘못 골랐다면, 저수준 최적화는 의미가 없다.
  • 만족할 만한 성능이 나올 때까지 위의 과정을 반복하고, 변경 후에는 성능 측정을 꼭하자

참고

  • Effective Java 3rd Edition - Item 67. 최적화는 신중히 하라