도당탕탕
Item67 : 최적화는 신중히 하라 본문
다음 최적화 격언 3가지를 소개한다.
1. (맹목적인 어리석음을 포함해) 그 어떤 핑계보다 효율성이라는 이름 아래 행해진 컴퓨팅 죄악이 더 많다.
(심지어 효율을 높이지도 못하면서)
-- 윌리엄 울프 --2. (전체의 97% 정도인) 자그마한 효율성은 모두 잊자. 섣부른 최적화가 만악의 근원이다.
-- 도널드 크누스 --3. 최적화를 할 때는 다음 두 규칙을 따르라.
첫 번째, 하지 마라. 두 번째, (전문가 한정) 아직 하지 마라.
다시 말해, 완전히 명백하고 최적화되지 않은 해법을 찾을 때까지는 하지 마라.
-- M. A. 잭슨
이 격언들은 자바가 탄생하기 20년전에 나온 것으로, 최적화의 어두운 진실을 이야기해 준다. 최적화는 좋은 결과보다는 해로운 결과로 이어지기 쉽고, 섣불리 진행하면 특히 더 그렇다. 빠르지도 않고 제대로 동작하지도 않으면서 수정하기는 어려운 스프트웨어를 탄생시키는 것이다.
성능 최적화
그렇다면 성능 최적화를 하지 말라는 것일까? 그건 아니다. 성능 최적화를 하기전 다음 내용을 한번 보자.
- 성능 때문에 견고한 구조를 희생하지 말자. 빠른 프로그램보다는 좋은 프로그램을 작성하라.
- 좋은 프로그램을 작성하다보면 정보은닉 원칙을 따르므로 개별 구성요소의 내부를 독립적으로 설계할 수 있다.
- 따라서 시스템의 나머지에 영향을 주지 않고도 각 요소를 다시 설계할 수 있다.
- 그렇다고 성능 문제를 무시하라는 뜻이 아니고, 완성된 설계의 기본 틀을 변경하려다 보면 유지보수하거나 개선하기 어려운 꼬인 구조의 시스템이 만들어지기 때문에 염두에 두고 프로그램을 작성하라는 뜻이다.
- 성능을 제한하는 설계는 피하라.
- 완성후 변경하기가 가장 어려운 설계 요소는 컴포넌트끼리, 혹은 외부 시스템과의 소통 방식이다. (API, 네트워크 프로토콜, 영구 저장용 데이터 포맷 등)
- 이런 설계 요소들은 완성후에는 변경하기 어렵거나 불가능할 수 있으며, 동시에 시스템 성능을 심각하게 제한할 수 있다.
- API를 설계할 때 성능에 주는 영향을 고려하라.
- public을 사용하여 내부 데이터를 변경할 수 있게 만들면 불필요한 방어적 복사를 수없이 유발할 수 있다.
- 또한 컴포지션으로 해결할 수 있음에도 상속방식을 사용하면 상위 클래스에 영원히 종속되어 성능 제약을 일으킬 수 있다.
- 그리고 인터페이스도 있는데 굳이 구현 타입을 사용하여 나중에 더 좋은 구현체를 사용 못하는 경우가 있기 때문에 인터페이스를 사용하는 것이 좋다.
- 성능을 위해 API를 왜곡하는 건 매우 안 좋은 생각이다.
- API 설계가 성능에 주는 영향은 현실적인 문제지만, 다행히 잘 설계된 API는 성능도 좋은 게 보통이다.
- 하지만 API를 왜곡하도록 만들면, 이전 API가 성능 문제는 해당 플랫폼이나 아랫단 소프트웨어의 다음 버전에서 변경 시 해당 왜곡된 API는 고통이 영원히 따라갈 것이다.
신중하게 설계하여 깨끗하고 명확하고 멋진 구조를 갖춘 프로그램을 완성한 다음에야 최적화를 고려해볼 차례가 된다. 물론 성능에 만족하지 못할 경우에 한정된다. 또한 일반적으로 90%의 시간을 성능에 별다른 영향을 주지 않는 곳에 투자하기 때문에 시간을 많이 허비할 수 있다.
프로파일링 도구
프로파일링 도구는 최적화 노력을 어디에 집중해야 할지 찾는 데 도움을 준다. 이런 도구는 개별 메소드의 소비 시간과 호출 횟수 같은 런타임 정보를 제공하여, 집중할 곳은 물론 알고리즘을 변경해야 한다는 사실을 알려주기도 한다. 이렇게 간단히 성능을 튜닝시킬 수 있다.
자바에서 성능 최적화
최적화 시도 전후의 성능 측정은 C와 C++같은 전통적인 언어에서도 중요하지만, 성능 모델이 덜 정교한 자바에서는 중요성이 더욱 크다. 자바는 다양한 기본 연산에 드는 상대적인 비용을 덜 명확하게 정의하고 있다.
다시 말해, 프로그래머가 작성하는 코드와 CPU에서 수행하는 명령 사이의 추상화 격차가 커서 최적화로 인한 성능 변화를 일정하게 예측하기가 그만큼 어렵다. 그래서인지 최적화와 관련해 일부만 맞거나 터무니없는 미신들이 떠돌아다닌다.
자바의 성능 모델은 정교하지 않을뿐더러 구현 시스템, 릴리스, 프로세스마다 차이가 있다. 우리의 프로그램을 여러 가지 자바 플랫폼이나 여러 하드웨어 플랫폼에서 구동한다면 최적화의 효과를 그 각각에서 측정해야 한다. 그러다 보면 다른 구현 혹은 하드웨어 플랫폼 사이에서 성능을 타협해야 하는 상황도 마주할 것이다.
정리
프로세서부터 가성머신과 라이브러리, 그리고 자바가 수행되는 하드웨어 종류도 무척 다양해졌기 때문에 이런 모든 요소가 하나로 얽혀 프로그램의 성능 예측이 어렵다. 물론 그에 비해 측정의 중요성도 커졌다.
하지만 빠른 프로그램을 작성하려 안달하지 말자. 좋은 프로그램을 작성하다 보면 성능은 따라오게 마련이다.
그리고 시스템을 설계할 때, API, 네트워크 프로토콜, 영구 저장용 데이터 포맷을 설계할 때는 성능을 염두에 두어야 한다. 시스템을 구현했다면 그때 성능 측정을 해보자. 충분히 빠르면 그걸로 끝이다. 그렇지 않다면 프로파일러를 사용해 문제의 원인이 되는 지점을 찾아 최적화를 수행하자.
'JAVA' 카테고리의 다른 글
Item69 : 예외는 진짜 예외 상황에만 사용하라 (0) | 2023.01.20 |
---|---|
Item68 : 일반적인 네이밍 컨벤션을 따르라 (2) | 2023.01.19 |
Item66 : Native method를 현명하게 사용하라. (0) | 2023.01.18 |
Item65 : 리플렉션보다는 인터페이스를 사용하라 (0) | 2023.01.18 |
Item64 : 인터페이스로 객체들을 참조하라. (0) | 2023.01.17 |