이 책에서 모든 사람이 마음 깊이 새겨야 할 최적화 격언 3개를 소개해주었다.
그 어떤 핑계보다 효율성이라는 이름 아래 행해진 컴퓨팅 죄악이 더 많다 - 윌리엄 울프
전체의 97% 정도인 자그마한 효율성은 모두 잊자. 섣부른 최적화가 만악의 근원이다. - 도널드 크누스
최적화를 할 때는 다음 두 규칙을 따르라.
1. 하지 마라
2. (전문가 한정) 아직 하지 마라. 다시 말해, 완전히 명백하고 최적화되지 않은 해법을 찾을 때까지는 하지 마라 - M.A. 잭슨
이 격언들은 자바가 탄생하기 20년 전에 나온 것으로, 최적화는 좋은 결과보다는 해로운 결과로 이어지기 쉽고, 섣불리 진행하면 특히 더 그렇다는 것을 알려준다.
성능 때문에 견고한 구조를 희생하지 말자.
빠른 프로그램보다는 좋은 프로그램을 작성하자.
설계 단계에서 고려할 점
구현상의 문제는 나중에 최적화해 해결할 수 있지만, 아키텍처의 결함이 성능을 제한하는 상황이라면 시스템 전체를 다시 작성하지 않고는 해결하기 불가능할 수 있다. 따라서 설계 단계에서 성능을 반드시 염두에 두어야 한다.
1. 성능을 제한하는 설계를 피하라.
- 완성 후 변경하기가 가장 어려운 설계요소 : 컴포넌트 혹은 외부 시스템과의 소통방식 (API, 네트워크 프로토콜, 영구 저장용 데이터 포맷)
- 이러한 설계 요소는 완성 후에는 변경하기 어렵거나 불가능하다.
2. API를 설계할 때는 성능에 주는 영향을 고려하라
- public 타입을 가변으로 만들면 불필요한 방어적 복사를 수없이 유발할 수 있다.
- 컴포지션으로 해결할 수 있음에도 상속 방식으로 설계한 public 클래스는 상위 클래스에 영원히 종속된다.
- 인터페이스를 두고 구현 타입을 사용하면 해당 구현체에 종속되어 나중에 더 좋은 구현체가 나오더라도 이용하지 못한다.
이처럼 신중하게 설계하여 깨끗하고 명확한 멋진 구조를 갖춘 프로그램을 완성한 다음에 최적화를 고려해볼 차례가 된다.
컴포지션
컴포지션(Composition)은 클래스 A가 클래스 B를 멤버 변수로 가지는 경우를 의미한다. 이러한 관계는 클래스 A가 클래스 B의 객체를 사용하거나 조작하는 것을 의미하는데, 클래스 A는 클래스 B에 의존(dependency)하며, 클래스 B는 클래스 A에 의해 구성(composed)되는 관계다.
예를 들어, 자동차 클래스와 엔진 클래스를 구성했을 때, 자동차는 엔진을 가지고 있으므로 자동차 클래스는 엔진 클래스를 멤버 변수로 갖게 된다.
class Engine {
//...
}
class Car {
private Engine engine;
public Car() {
this.engine = new Engine(); // 컴포지션: Car 클래스가 Engine 클래스를 포함하고 있음
}
//...
}
최적화 검증
- 시도한 최적화 기법이 성능을 눈에 띄게 높이지 못하는 경우가 많고, 심지어 더 나빠지게 할 때도 있다.
- 일반적으로 90%의 시간을 단 10%의 코드에서 사용하는데, 우리는 프로그램에서 시간을 잡아먹는 부분을 추측하기 어렵다.
- 자바에서는 기본 연산에 드는 상대적인 비용을 덜 명확하게 정의하여 프로그래머가 작성하는 코드와 CPU에서 수행하는 명령 사이의 추상화 격차가 크다.
- 따라서 최적화로 인한 성능 변화를 일정하게 예측하기가 어렵다.
프로파일링 도구
- 최적화 노력을 어디에 집중해야 할지 찾는데 도움을 준다.
- 개별 메서드의 소비 시간, 호출 횟수 같은 런타임 정보와 알고리즘을 변경해야 한다는 사실까지 알려준다.
결론
- 빠른 프로그램을 작성하려 안달하지 말자.
- API, 네트워크 프로토콜, 영구 저장용 데이터 포맷을 설계할 때는 성능을 염두에 두자.
- 시스템 구현을 완료했다면 성능을 측정해보고 충분히 빠르면 그걸로 끝내자.
- 그렇지 않다면 프로파일러를 사용해 문제의 원인이 되는 지점을 찾아 최적화를 수행하자.
- 알고리즘을 잘못 골랐다면 다른 저수준 최적화는 아무리 해봐야 소용이 없다.
'Java > Effective Java' 카테고리의 다른 글
[Effective Java] Item 69. 예외는 진짜 예외 상황에만 사용하라 (0) | 2023.08.05 |
---|---|
[Effective Java] Item 68. 일반적으로 통용되는 명명 규칙을 따르라 (0) | 2023.08.04 |
[Effective Java] Item 66. 네이티브 메서드는 신중히 사용하라 (0) | 2023.07.30 |
[Effective Java] Item 65. 리플렉션보다는 인터페이스를 사용하라 (0) | 2023.07.30 |
[Effective Java] Item 64. 객체는 인터페이스를 사용해 참조하라 (0) | 2023.07.30 |