Home Item67 (최적화는 신중히 하라)
Post
Cancel

Item67 (최적화는 신중히 하라)

최적화는 신중히 하라

우선 최적화에 관한 격언 3가지를 보자.

  • (맹목적인 어리석음을 포함해) 그 어떤 핑계보다 효율성이라는 이름 아래 행해진 컴퓨팅 죄악이 더 많다. - 윌리엄 울프 -
  • 자그마한 효율성은 모두 잊자. 섣부른 최적화가 만악의 근원이다. - 도널드 크누스 -
  • 최적화를 할 때는 다음 두 규칙을 따르라
    • 첫 번째, 하지 마라
    • 두 번째, (전문가 한정) 아직 하지 마라. 다시 말해, 완전히 명백하고 최적화되지 않은 해법을 찾을 때까지는 하지 마라.
    • -M.A. 잭슨

이 격언들은 Java가 탄생하기 20년 전에 나온 것으로, 최적화의 어두운 진실을 이야기해준다.

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

빠른 프로그램보다는 좋은 프로그램을 작성하라

성능 때문에 견고한 구조를 깨뜨릴 필요가 없다.

좋은 프로그램이지만 원하는 성능이 나오지 않는 경우 그 아키텍처 자체가 최적화할 수 있는 길을 안내해줄 것이다.

좋은 프로그램은 정보 은닉 원칙을 따르므로 개별 구성요소의 내부를 독립적으로 설계할 수 있다.

따라서 시스템의 나머지에 영향을 주지 않고도 각 요소를 다시 설계할 수 있어 구조는 그대로, 성능은 개선하는 방향을 모색할 수 있다.

그러나 이 말이 프로그램을 완성할 때까지 성능 문제를 무시하라는 말은 아니다.

구현상의 문제는 추후 해결할 수 있지만, 아키텍처의 결함이 성능을 제한하는 상황이라면 시스템 전체를 다시 작성해야 해결이 가능할지도 모른다.

완성된 설계의 기본 틀을 변경하려다보면 유지보수하거나 개선하기 어려운 꼬인 구조의 시스템이 만들어지기 쉽기 때문이다.

따라서 설계 단계에서 성능을 반드시 염두에 두어야 한다.

성능을 제한하는 설계를 피하라

완성 후 변경하기가 가장 어려운 설계 요소는 컴포넌트끼리, 혹은 외부 시스템과의 소통 방식이다.

API, 네트워크 프로토콜, 영구 저장용 데이터 포맷 등이 대표적이다.

예를 들어 흔히 우리가 겪을 수 있는 상황을 보자.

웹 애플리케이션에서 외부 서비스와 REST API를 통해 데이터를 주고 받는다. 이 때 만약 API의 형식이나 동작이 변경되면, 이를 사용하던 클라이언트도 함께 변경되어야 한다.

따라서 변경이 힘들고 신중하게 계획되어야 하는 것이다.

이런 설계 요소들은 완성 후에 변경이 어려움으로 설계 시 시스템 성능을 고려해야 한다. 그렇지 않으면 변경하기 어려운 요소에서 시스템 성능을 심각하게 제한할 수 있다.

API를 설계할 때 성능에 주는 영향을 고려하라

위에서 했던 얘기와 일맥상통하다.

API를 만들 때 public 타입을 가변으로 만들면 불필요한 방어적 복사를 수없이 많이 유발할 수 있다.

비슷하게 컴포지션으로 해결할 수 있음에도 상속 방식으로 설계한 public 클래스는 영원히 상위 클래스에 종속되며 그 성능의 제약까지도 물려받게 된다.

적합한 인터페이스가 있는데, 구현 타입을 사용하는 것도 문제다. 추후 더 빠른 구현체가 나타나면 이용하지 못하게 된다.

상황이 적합하다면

  • public 타입을 가변으로 만들지 말자
  • 상속보다 컴포지션을 사용하라
  • 구현체 대신 인터페이스를 사용해 참조하라

성능을 위해 API를 왜곡하지는 말자

잘 설계된 API는 보통 성능도 좋다.

따라서 성능을 위해 API를 왜곡하면 안된다.

API를 왜곡하도록 만든 그 성능 문제는 해당 플랫폼이나 아랫단 소프트웨어의 다음 버전에서 사라질 수도 있지만, 왜곡된 API와 이를 지원하는 데 따르는 고통은 영원히 이어진다.

신중하게 설계해 명확한 구조를 갖춘 프로그램을 완성한 뒤에야 최적화를 고려해볼 수 있다. (성능에 만족하지 못할 경우 고려.)

최적화 시도 전후로 성능을 측정하라.

스트림 병렬화(아이템48)를 다룰 때 했던 이야기이다.

최적화를 했다고 어떤 경우에도 다 성능이 좋아지지는 않는다.

시도한 최적화 기법이 성능을 눈에 띄게 높이지 못하는 경우가 많고, 오히려 나빠지게 할 때도 있다.

이러한 원인이 발생하는 이유는 프로그램에서 시간을 잡아먹는 부분을 추측하기 어렵기 때문이다.

따라서 최적화 시도 전후로 성능을 측정해보고, 실제로 성능이 개선되는 지 확인해보아야 한다.

정리

성능보다는 우선 안전하고 깨끗한 구조를 가진 프로그램을 만드는 것이 중요하다.

설계부터 성능을 고려해야 하는 것은 맞지만, 성능을 위해 명확한 구조를 깨뜨릴 필요는 없다.

프로그램이 모두 구현된 뒤 성능을 측정해보자. 만약 충분히 빠르다면 그걸로 됐다.

만약 그렇지 않은 경우 문제가 되는 지점을 찾아 최적화를 수행하면 된다. 최적화를 수행하고 난 뒤에는 성능 비교를 꼭 해봐야 한다. 최적화를 했다고 성능이 개선된다는 보장이 있지는 않다.

This post is licensed under CC BY 4.0 by the author.

Item66 (네이티브 메서드는 신중히 사용하라)

Item68 (일반적으로 통용되는 명명규칙을 따르라)