최적화의 어두운 진실
최적화는 해로운 결과로 이어지기 쉽다.
빠르지도, 제대로 동작하지도 않고, 수정하기도 어려운 소프트웨어를 탄생시킬 수 있다.
성능 때문에 견고한 구조를 희생하지 말자.
빠른 프로그램보다는 좋은 프로그램을 작성하라.
좋은 프로그램은 정보 은닉 원칙을 따르므로, 구성요소의 각 내부를 독립적으로 재설계 가능하다(Item15)
.
.
책에서는 "모든 사람이 마음 깊이 새겨야 할 최적화 격언 세 개"를 소개하고 있다.
이 격언들은 자바가 탄생하기 20년 전에 나온 것으로, 최적화의 어두운 진실을 이야기해준다.
(맹목적인 어리석음을 포함해) 그 어떤 핑계보다 효율성이라는 이름 아래 행해진 컴퓨터 죄악이 더 많다(심지어 효율을 높이지도 못하면서).
─ 윌리엄 울프
(전체의 97% 정도인) 자그마한 효율성은 모두 잊자. 섣부른 최적화가 만악의 근원이다.
─ 도널드 크누스
최적화를 할 때는 다음 두 규칙을 따르라.
첫 번째, 하지 마라.
두 번째, (전문가 한정) 아직 하지 마라. 다시 말해, 완전히 명백하고 최적화되지 않은 해법을 찾을 때까지는 하지 마라.
─ M. A. 잭슨
.
.
또한 만일 최적화를 시도한다면, 각각의 최적화 전후로 성능을 측정해야 한다. 아마 측정 결과에 놀랄 때가 많을 텐데, 시도한 최적화 기법이 성능을 눈에 띄게 높이지 못하는 경우 or 더 나빠지게 할 때가 많을 것이다. 프로그램에서 성능이 나쁜 부분을 추측하기는 어렵다. 시간을 허비하지 말자.
설계시 반드시 성능 문제를 고민하라
아키텍처의 결함이 성능을 제한하고 있다는 것이 발견되면, 시스템 전체를 재작성하지 않고는 해결하기 불가능할 수 있다. 또한 설계의 기본 틀을 변경하려다보면 꼬인 구조가 되어 유지보수하기 어려워질 수 있다. 따라서 설계 단계에서 성능을 반드시 염두에 두어야 한다.
1. 성능을 제한하는 설계를 피하라
완성 후 변경하기 가장 어려운 설계 요소는 "컴포넌트끼리, 혹은 외부 시스템과의 소통 방식이다" 예를 들면 API, 네트워크 프로토콜, 영구 저장용 데이터 포맷 등이 대표적이다. 이런 설계 요소들은 완성 후에는 변경하기 어렵거나 불가능할 수 있으며, 동시에 시스템 성능을 심각하게 제한할 수 있다.
(└> 이거 아직 무슨 이야기인지 느낌이 안 온다!)
2. API를 설계할 때 성능에 주는 영향을 고려하라.
∨ public 타입을 가변으로 만들어 내부 데이터를 변경할 수 있게 만들면 불필요한 방어적 복사를 수없이 유발할 수 있다(Item50)
java.awt.Component 클래스의 getSize 메서드가 예시이다. 이 API 설계자는 getSize가 Dimension 인스턴스를 반환하도록 했다. 이때 Dimension은 가변으로 설계했으니 getSize를 호출하는 모든 곳에서 Dimension 인스턴스를 방어적으로 복사하느라 새로 생성해야만 한다. 이걸 다르게 설계해본다면, Dimension을 불변(Item17)로 만드는 것이 가장 이상적일 것이다. 아니면 getSize를 getWidth와 getHeight로 나누는 방법도 있다.
∨ 컴포지션으로 해결할 수 있음에도 상속 방식으로 설계한 public 클래스는 상위 클래스에 영원히 종속되며 그 성능 제약까지도 물려받게 된다(Item18)
∨ 인터페이스도 있는데 굳이 구현 타입을 사용하지 말자. 특정 구현체에 종속되면 더 빠른 구현체가 나오더라도 이용하지 못한다(Item64)
프로파일링 도구라는 것?
프로파일링 도구는 어느 코드에서 최적화 노력을 해야하는지 찾는 데 도움을 준다. 각 메서드의 소비 시간, 호출 횟수 등 런타임 정보를 제공하여 어느 메서드 개선에 집중해야 하는지 알려준다. 예를 들면 시간이 거듭제곱으로 증가하는 알고리즘이 숨어 있다면, 찾아서 교체할 수 있다. (알고리즘을 잘못 골랐다면 다른 저수준 최적화는 아무리 해도 소용 없다.)
시스템 규모가 커질수록 '건초더미에서 바늘찾기'처럼 프로파일러가 더 중요해진다.
자바에서 성능 측정의 중요성
자바의 성능 모델은 C, C++ 등에 비해 정교하지 않다. 기본 연산에 드는 상대적인 비용을 덜 명확하게 정의하고 있다. 즉 프로그래머가 작성하는 코드와 CPU에서 수행하는 명령 사이의 '추상화 격차'가 커서, 최적화로 인한 성능 변화를 일정히 예측히기가 그만큼 더 어렵다. 구현 시스템, 릴리스, 프로세서마다 차이가 있다. 프로그램을 여러 가지 자바 플랫폼, 하드웨어 플랫폼에서 구동한다면, 최적화의 효과를 각각 측정해야 한다. 자바 소프트웨어 스택 요소들은 복잡해지고 있고, 자바가 수행되는 하드웨어 종류도 무척 다양해졌다.
그러한 여러 요소가 얽혀서, 측정의 중요성이 커졌다.
'JAVA > Effective Java' 카테고리의 다른 글
[이펙티브 자바] public 클래스에서는 public 필드가 아닌 접근자 메서드를 사용하라 ─ 4장:클래스와 인터페이스:Item16 (0) | 2023.10.25 |
---|---|
[이펙티브 자바] 클래스와 멤버의 접근 권한을 최소화하라 ─ 4장:클래스와 인터페이스:Item15 (1) | 2023.10.24 |
[이펙티브 자바] 네이티브 메서드는 신중히 사용하라 ─ 9장:일반적인 프로그래밍 원칙:Item66 (0) | 2023.10.22 |
[이펙티브 자바] 리플렉션보다는 인터페이스를 사용하라 ─ 9장:일반적인 프로그래밍 원칙:Item65 (0) | 2023.10.21 |
[이펙티브 자바] 객체는 인터페이스를 사용해 참조하라 ─ 9장:일반적인 프로그래밍 원칙:Item64 (0) | 2023.10.21 |