아이템 67. 최적화는 신중히 하라

wisdom·2023년 3월 8일
0

Effetctive Java

목록 보기
67/80
post-thumbnail

최적화 이야기를 하기에 앞서, 다음의 격언들을 보자.

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

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

최적화를 할 때는 다음 두 규칙을 따르라.
첫 번째, 하지 마라.
두 번째, (전문가 한정) 아직 하지 마라. 다시 말해, 완전히 명백하고 최적화되지 않은 해법을 찾을 때까지는 하지마라.

- M.A 잭슨[Jackson75]

이 격언들은 자바가 탄생하기 20년에 나온 것으로 최적화의 어두운 진실을 보여준다.

최적화는 좋은 결과보다는 해로운 결과로 이어지기 쉽다. 빠르지도 않고, 제대로 동작하지도 않으면서, 수정하기 어려운 소프트웨어를 탄생시키는 것이다.

견고한 구조를 희생하지 말자

성능 때문에 견고한 구조를 희생하지 말자. 빠른 프로그램보다는 좋은 프로그램을 작성하자.
좋은 프로그램이지만 원하는 성능이 나오지 않는다면 그 아키텍처 자체가 최적화할 수 있는 길을 안내해줄 것이다.
좋은 프로그램은 정보 은닉 원칙을 따르므로 개별 구성요소의 내부를 독립적으로 설계할 수 있다. 따라서 시스템의 나머지에 영향을 주지 않고도 각 요소를 다시 설계할 수 있다.

설계 단계에서 성능을 염두에 두자

그렇다고 프로그램을 완성할 때까지 성능 문제를 무시하라는 뜻이 아니다.
아키텍처의 결함이 성능을 제한하는 상황이라면 시스템 전체를 다시 작성하지 않고는 해결하기 불가능할 수 있다. (구현상의 문제는 나중에 최적화해서 해결할 수 있지만)

따라서 설계 단계에서 성능을 반드시 염두에 두어야 한다. 설계 시 어떻게 성능을 고려할 수 있을까?

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

API를 설계할 때 성능을 주는 영향을 고려하자.
public 타입을 가변으로 만들면(내부 데이터를 변경할 수 있게 만들면), 불필요한 방어적 복사를 수없이 유발할 수 있다.
또한, 컴포지션으로 해결할 수 있음에도 상속 방식으로 설계한 public 클래스는 상위 클래스에 영원히 종속되며 그 성능 제약까지도 물려받게 된다.
인터페이스가 있는데 굳이 구현 타입을 사용하는 것도 좋지 않다. 특정 구현체에 종속되어, 나중에 더 빠른 구현체가 나오더라도 이용하지 못하게 된다.

신중하게 설계하여 깨끗하고 명확하고 멋진 구조를 갖춘 프로그램을 완성한 다음에야 최적화를 고려해볼 차례가 된다.

성능 측정

각각의 최적화 시도 전후로 성능을 측정하자.

측정 결과를 보면 시도한 최적화 기법이 성능을 눈에 띄게 높이지 못하거나 더 나빠지는 경우도 많다. 이는 프로그램에서 시간을 잡아먹는 부분을 추측하기 어렵기 때문이다. 느릴거라 짐작한 부분이 사실은 성능에 별다른 영향을 주지 않는 곳이라면 시간만 허비한 꼴이 된다. 일반저긍로 90%의 시간을 단 10%의 코드에서 사용한다는 사실을 기억해두자.

프로파일링 도구(profiling tool)는 최적화 노력을 어디에 집중해야 할지 찾는 데 도움이 된다. 개별 메서드의 소비 시간과 호출 횟수 같은 런타임 정보를 제공하여, 집중할 곳은 물론 알고리즘을 변경해야 한다는 사실을 알려주기도 한다.

JMH (Java Microbenchmark Harness)도 언급해둘 만한 도구다. 자바 코드의 상세한 성능을 알기 쉽게 보여주는 마이크로 벤치마칭 프레임워크다.

최적화 시도 전후의 성능 측정은 성능 모델이 덜 정교한 자바에서 중요성이 크다. 또한 자바의 성능 모델은 구현 시스템, 릴리스, 프로세서마다 차이가 있다. 따라서, 프로그램을 여러 가지 자바 플랫폼이나 여러 하드웨어 플랫폼에서 구동한다면 최적화의 효과를 그 각각에서 측정해야 한다.


📌 핵심 정리

빠른 프로그램을 작성하려 안달하지 말자. 좋은 프로그램을 작성하다 보면 성능은 따라오게 마련이다.
하지만 시스템을 설계할 때, 특히 API, 네트워크 프로토콜, 영구 저장용 데이터 포맷을 설계할 때는 성능을 염두에 두어야 한다.
시스템 구현을 완료했다면 이제 성능을 측정해보라. 충분히 빠르면 그것으로 끝이다. 그렇지 않다면 프로파일러를 사용해 문제의 원인이 되는 지점을 찾아 최적화를 수행하라. 가장 먼저 어떤 알고리즘을 사용했는지 살펴보자. 알고리즘을 잘못 골랐다면 다른 저수준 최적화는 아무리 해봐야 소용이 없다. 만족할 때까지 이 과정을 반복하고, 모든 변경 후에는 성능을 측정하라.

profile
백엔드 개발자

0개의 댓글