[EffectiveJava] item67 - 최적화는 신중히 하라
10 Jul 2023이 책에서는 최적화에 대한 세가지 격언을 소개한다.
(맹목적인 어리석음을 포함해) 그 어떤 핑계보다 효율성이라는 이름 아래 행해진 컴퓨팅 죄악이 더 많다.(심지어 효율을 높이지도 못하면서)
ㅡ 윌리엄 울프
(전체의 97% 정도인) 자그마한 효율성은 모두 잊자. 섣부른 최적화가 만악의 근원이다.
ㅡ 도널드 크누스
최적화를 할 때는 다음 두 규칙을 따르라.
첫 번째, 하지마라
두 번째, (전문가 한정) 아직 하지 마라. 다시 말해, 완전히 명백하고 최적화 되지 않은 해법을 찾을 때까지는 하지 마라.
ㅡ 도널드 크누스
최적화의 함정
최적화는 좋은 결과보다는 해로운 결과로 이어지기 쉽고, 섣불리 진행하면 특히 더 그렇다.
성능 때문에 견고한 구조를 희생하지말자. 빠른 프로그램보다는 좋은 프로그램을 작성하라.
좋은 프로그램은 정보 은닉 원칙을 따르므로 개별 구성요소의 내부를 독립적으로 설계할 수 있다. 따라서 시스템의 나머지에 영향을 주지 않고도 각 요소를 다시 설계할 수 있다.
최적화 전에 고려할 점
구현상의 문제는 나중에 최적화해 해결할 수 있지만, 아키텍처의 결함이 성능을 제한하는 상황이라면 시스템 전체를 다시 작성하지 않고는 해결하기 불가능할 수 있다.
따라서 설계 단계에서 성능을 반드시 염두에 두어야 한다.
성능을 제한하는 설계를 피하라.
완성 후 변경하기가 가장 어려운 설계 요소는 바로 컴포넌트끼리, 혹은 외부 시스템과의 소통 방식이다. API, 네트워크 프로토콜, 영구 저장용 데이터 포맷 등이 대표적이다.
API를 설계할 때 성능에 주는 영향을 고려하라.
public 타입을 가변으로 만들면, 내부 데이터를 변경할 수 있게 만들어지기 때문에 불필요한 방어적 복사를 수없이 유발할 수 있다.
컴포지션으로 해결할 수 있음에도 상속 방식으로 설계한 public 클래스는 상위 클래스에 영원히 종속되며 그 성능 제약까지도 물려받게 된다. 인터페이스가 아닌 특정 구현체에 종속된다면, 나중에 더 빠른 구현체가 나오더라도 이용하지 못하게 된다.
API의 설계 결정
잘 설계된 API는 성능도 좋은 게 보통이다. 그러니 성능을 위해 API를 왜곡하는 건 매우 안 좋은 생각이다.
최적화를 할 때 고려할점
이제 신중하게 설계하여 깨끗하고 명확하고 멋진 구조를 갖춘 프로그램이 완성된 후에야 최적화를 고려해볼 차례가 된다.
성능 측정
위의 잭슨이 소개한 최적화 규칙중 하나를 더 추가한다면 “각각의 최적화 시도 전후로 성능을 측정하라”가 될것이다.
주로 프로그램에서 시간을 잡아먹는 부분을 추측하기가 어렵기 때문에, 시도한 최적화 기법이 성능을 눈에 띄게 높이지 못하는 경우가 많고, 심지어 더 나빠지게 할 때도 있다.
느릴거라 짐작한 부분이 사실은 성능에 별다른 영향을 주지 않는 곳이라면 시간만 허비한 꼴이 된다.
프로파일링 도구(profiling pool)
프로파일링 도구는 최적화 노력을 어디에 집중해야 할 지 찾는 데 도움을 준다.
이런 도구는 개별 메서드의 소비 시간과 호출 횟수 같은 런타임 정보를 제공하여, 집중할 곳은 물론 알고리즘을 변경해야 한다는 사실으 알려주기도 한다.
시스템 규모가 커질수록 프로파일러가 더 중요해진다.
최적화 시도 전후의 성능 측정
최적화 시도 전후의 성능 측정은 C와 C++ 같은 전통적인 언어에서도 중요하지만,성능 모델이 덜 정교한 자바에서는 중요성이 더욱 크다.
자바는 다양한 기본 연산에 드는 상대적인 비용을 덜 명확하게 정의하고 있다. 코드와 ‘CPU’에서 수행하는 명령 사이이 ‘추상화 격차’가 커서 최적화로 인한 성능 변화를 일정하게 예측하기가 어렵다.
자바 성능 모델
자바 성능 모델은 정교하지 않을뿐더러 구현 시스템, 릴리스, 프로세서 마다 차이가 있다. 프로그램을 여러가지 자바 플랫폼이나 여러 하드웨어 플랫폼에서 구동한다면 최적화의 효과를 그 각각에서 측정해야 한다.
프로세서 부터 가상머신과 라이브러리, 그리고 자바가 수행되는 하드웨어 종류도 무척 다양해졌다. 이런 모든 요소가 하나로 얽혀 자바 프로그램의 성능 예측이 어려워 지지만, 그에 비례해 측정의 주요성도 커졌다.