JAVA/Effective Java

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

꾸준함. 2024. 3. 19. 22:55

최적화 관련 명언

`(맹목적인 어리석음을 포함해) 그 어떤 핑계보다 효율성이라는 이름 아래 행해진 컴퓨팅 죄악이 더 많다(심지어 효율을 높이지도 못하면서).`

- 윌리엄 울프

 

`(전체의 97% 정도인) 자그마한 효율성은 모두 잊자. 섣부른 최적화가 만악의 근원이다.`

- 도널드 크누스

 

`첫 번째, 하지 마라.

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

- M.A 잭슨

 

떠오르는 명언

 

정리하자면 최적화는 주로 해로운 결과를 초래할 가능성이 높으며, 특히 섣불리 진행할수록 더 그럴 확률이 높습니다.

따라서 최적화를 진행하기 전에 많은 요소를 고려한 뒤 진행해야 합니다.

 

프로그램을 설계할 때 고려해야 할 요소

 

1. 빠른 프로그램보다는 좋은 프로그램을 작성하자

 

  • 좋은 프로그램이지만 원하는 성능이 나오지 않을 경우 해당 아키텍처 자체가 최적화할 수 있는 길을 알려줄 것
    • 우수한 프로그램은 캡슐화 원칙을 준수하여 각 구성 요소를 독립적으로 설계할 수 있으므로, 이로 인해 나머지 시스템에 영향을 주지 않으면서 개별 요소를 재설계할 수 있음

 

  • 구현상의 문제는 추후에 최적화할 수 있지만, 아키텍처의 결함이 성능을 제한할 경우 시스템을 다시 작성해야 함
    • 완성된 설계의 기본 틀을 변경하려다 보면 유지보수하거나 개선하기 어려운 꼬인 구조의 시스템이 만들어지기 쉬움
    • 설계 과정에서 반드시 성능을 고려하여 진행해야 함

 

2. 성능을 제한하는 설계를 피하자

 

  • 완성 후 변경하기가 가장 어려운 설계 요소는 컴포넌트끼리 혹은 외부 시스템과의 소통 방식
    • 완성 후에는 변경하기 어렵거나 불가능하고, 동시에 시스템 성능을 제한할 수 있음
    • ex) API, 네트워크 프로토콜, 영구 저장용 데이터 포맷, etc.

 

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

 

  • 아이템 50에서 다루었다시피 가변 객체를 사용하여 내부 데이터를 변경할 수 있게 만들면 불필요한 방어적 복사를 유발할 수 있음
  • 아이템 18에서 다루었다시피 컴포지션으로 해결할 수 있는 경우에도 상속을 이용하면 상위 클래스에 영원히 종속되고, 성능 제약까지 물려받을 수 있음
  • 아이템 64에서 다루었다시피 인터페이스가 존재하는데 굳이 구현체를 사용하면, 차후 개선된 구현체로 교체하기 어려워져 유연성이 떨어짐
  • API 설계가 성능에 주는 영향의 대표적인 예시가 java.awt.Component 클래스의 getSize 메서드
    • API 설계자는 해당 메서드가 Dimension 인스턴스를 반환하도록 결정했고 Dimension은 가변으로 설계했으므로 getSize()를 호출하는 모든 곳에서 Dimension 인스턴스를 방어적 복사
    • Dimension을 불변으로 만들거나 getSize() 메서드를 getWidth()와 getHeight()로 분리해 가변 객체가 아닌 기본 타입 값들을 각각 반환하는 방식으로 설계했다면 방어적 복사를 수행하지 않아도 되었을 것

 

방어적 복사 수행

 

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

 

  • API를 왜곡하도록 만든 성능 문제는 해당 플랫폼이나 아랫단 소프트웨어의 다음 버전에서 사라질 수 있음
  • 왜곡된 API를 지원하는 것에 수반되는 고통은 영원함

 

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

 

  • 시도한 최적화 기법이 측정 결과 성능을 드라마틱하게 높이지 못하거나 심지어 악화시키는 경우가 많음
    • 주원인은 프로그램에서 시간을 잡아먹는 부분을 추측하기가 어렵기 때문
    • 프로파일링 도구는 최적화 노력을 어디에 집중해야 할지 찾는데 도움이 됨
    • 개별 메서드의 소비 시간과 호출 횟수 같은 런타임 정보를 제공하여 개발자의 수고를 덜어줌
    • 프로파일러는 아니지만 JMH도 알아야 하는 도구이며 이는 자바 코드의 상세한 성능을 알기 쉽게 보여주는 마이크로 벤치마킹 프레임워크

 

https://github.com/melix/jmh-gradle-plugin

 

GitHub - melix/jmh-gradle-plugin: Integrates the JMH benchmarking framework with Gradle

Integrates the JMH benchmarking framework with Gradle - melix/jmh-gradle-plugin

github.com

 

https://gist.github.com/msievers/ce80d343fc15c44bea6cbb741dde7e45

 

[Spring, JMH] Howto integrate JMH benchmarks with Spring

[Spring, JMH] Howto integrate JMH benchmarks with Spring - [Spring, JMH] Howto integrate JMH benchmarks with Spring.md

gist.github.com

 

참고

이펙티브 자바

반응형