본문 바로가기
책/이펙티브 코틀린

2부 코드설계 > 4장 추상화 설계

by 정선한 2022. 9. 27.
728x90
반응형
2부 코드설계 > 4장 추상화 설계 > 함수 내부의 추상화 레벨을 통일하라.
2부 코드설계 > 4장 추상화 설계 > 변화로부터 코드를 보호하려면 추상화를 사용하라.
2부 코드설계 > 4장 추상화 설계 > API 안정성을 확인하라.
2부 코드설계 > 4장 추상화 설계 > 외부 API를 랩(wrap)해서 사용하라.
2부 코드설계 > 4장 추상화 설계 > 요소의 가시성을 최소화하라.
2부 코드설계 > 4장 추상화 설계 > 문서로 규약을 정의하라.
2부 코드설계 > 4장 추상화 설계 > 추상화 규약을 지켜라.
 

1. 책에서 기억하고 싶은 내용

추상화 : 컴퓨터 과학에서 추상화(abstraction)는 복잡한 자료, 모듈, 시스템 등으로부터 핵심적인 개념 또는 기능을 간추려 내는 것을 말한다. 조금 간단하게 표현하면, 추상화는 복잡성을 숨기기 위해 사용되는 단순한 형식을 의미하는 것으로 예로는 인터페이스를 들 수 있다.

추상화 레벨 통일

- 추상화 레벨 통일(SLA : Single Level of Abstraction) 
컴퓨터 과학이 높은 레벨과 낮은 레벨을 확실하게 구분하고 있는 것처럼, 함수도 높은 레벨과 낮은 레벨을 구분해서 사용해야 한다는 원칙이 있다.
- 함수는 간단해야 한다. 이는 '함수는 작아야 하며, 최소한의 책임만을 가져야 한다.'라는 이반적인 규칙이다. 또한 어떤 함수가 다른 함수보다 복잡하다면 일부 부분을 추출하여 추상화하는 것이 좋다.
- 추상화 계층이라는 개념은 함수보다 높은 레벨에서도 적용할 수 있다. 추상화를 구분하는 이유는 서브시스템의 세부 사항을 숨김으로써 상호 운영성과 플랫폼 독립성을 얻기 위함이다. 이는 문제 중심으로 프로그래밍한다는 의미입니다.
이러한 개념은 모듈 시스템을 설계할 때도 중요합니다. 모듈을 분리하면 계층 고유의 요소를 숨길 수 있습니다. 
- 계층화가 잘 된 프로젝트는 어떤 계층 위치에서 코드를 보아도, 일관적인 관점을 얻을 수 있습니다.
- 별도의 추상화 계층을 만드는 것은 프로그래밍에서 일반적으로 사용되는 개념입니다. 이는 knowledge를 체계화하고, 서브시스템의 세부 사항을 숨김으로써 상호 운영성과 플랫폼 독립성을 얻게 합니다. 함수, 클래스, 모듈 등의 다양한 방식을 통해서 추상화를 분리합니다. 이때 각각의 레이어가 너무 커지는 것은 좋지 않습니다. 

변화로부터 코드를 보호

- 추상화는 많은 것을 숨길 수 있는 테크닉이다. 생각할 것을 어느 정도 숨겨야 개발이 쉬워지는 것도 사실이지만 너무 많은 것을 숨기면 결과를 이해하는 것 자체가 어려워진다.
추상화가 너무 많으면 코드를 이해하기 어렵다. 추상화가 많은 코드를 보면, 이해하기 어렵다는 생각 때문에 코드를 제대로 읽기도 전에 두려움에 사로잡힐 수 있다.
추상화를 이해하려면 예제를 살펴보는 것이 좋다. 요소를 사용하는 방법을 보여주는 단위 테스트와 문서의 예제는 추상화가 어떻게 사용되는지 확실하게 보여준다. 예제없이 추상화를 설명하면 이해하기도 어렵고 오해하기도 쉽다.
@관련 예제 참고자료 추가조사
- 추상화는 단순하게 중복성을 제거해서 코드를 구성하기 위한 것이 아니다. 추상화는 코드를 변경해야 할 때 도움이 된다. 따라서 추상화를 사용하는 것은 굉장히 어렵지만, 이를 배우고 이해해야 한다. 다만 추상적인 구조를 사용하면 결과를 이해하기 어려우므로 추상화를 사용할 때의 장점과 단점을 모두 이해하고, 프로젝트 내에서 그 균형을 찾아야 한다. 추상화가 너무 많거나 너무 적은 상황 모두 좋은 상황이 아니다.

API 안정성 확인

프로그래밍에서는 안정적이고 최대한 표준적인 API를 선호한다.
API (Application Programming Interface)

  • 개발자는 안정적인 라이브러리로 업데이트를 해야 한다.
  • 새로운 API를 배워야 한다. (오래된 지식은 보안 문제를 발생시킨다.)

우리는 API의 안정성에 대해 알아야 한다. 또한 안정적이라고 생각했던 API의 변경사항에도 충분히 대응해야 한다.
API 제작자와의 충분한 커뮤니케이션이 중요하다. (버전 이름, 문서, 어노테이션을 꼭 확인)

외부 API 랩(wrap)

불안정한 API를 과도하게 사용하는 것은 굉장히 위험하기 때문에 혹시라도 사용하게 된다면 로직과 직접적인 결합을 시키지 않아야 한다.
그래서 많은 프로젝트들은 불안정하다고 판단되는 외부 라이브러리 API를 wrap 하여 사용한다.

장점

  • 문제가 있다면 warpper만 변경하면 되므로, API 변경에 쉽게 대응이 가능하다.
  • 프로젝트의 스타일에 맞추어 API 형태를 조정할 수 있다.
  • 특정 라이브러리에서 문제가 발생하면, wrapper을 수정하여 다른 라이브러리를 사용하도록 코드를 쉽게 변경할 수있다.
  • 필요한 경우 쉽게 동작을 추가하거나 수정할 수 있다.

단점

  • wrapper를 따로 정의해야 한다.
  • 다른 개발자가 프로젝트를 다룰 때, 어떤 wrapper들이 있는지 확인해야 한다.
  • wrapper는 프로젝트 내부에서만 유효하므로, 문제가 생겼을 때 스스로 해결해야 한다. 아무도 답을 알려줄 수 없음.

일반적으로 라이브러리 사용자가 많을수록 안정적이다.

요소의 가시성 최소화

  • 인터페이스가 작을수록 이를 공부하고 유지하는 것이 쉽다.
  • 최대한 제한이 되어있어야 변경하기 쉽다.
  • 클래스의 상태를 나타내는 프로퍼티가 노출되어 있다면, 클래스가 자신의 상태를 책임질 수 없다.
  • 가시성이 제한되면 API의 변경을 쉽게 추적할 수 있다.

일반적으로 코틀린에서는 구체 접근자의 가시성을 제한해서 모든 프로퍼티를 캡슐화하는 것이 좋다.
서로서로 의존하는 프로퍼티가 있을 때는 객체 상태를 보호하는 것이 더 중요하다.

예) mutableLazy Delegate를 구현할 때 initialized가 true라면 값의 초기화가 이루어지고, 이때의 값은 T타입이라는 것을 예상할 수 있다. 이때 initialized의 setter가 노출되어서는 안 된다.
이것이 노출되면 예상하지 못한 변경에 의한 예외가 발생한다. (코드의 신뢰성 저하)

가시성이 제한될수록 클래스의 변경을 쉽게 추적할 수 있으며, 프로퍼티의 상태를 더 쉽게 이해할 수 있다. 이는 동시성(concurrency)을 처리할 때 중요하다.

  • 상태 변경은 병렬 프로그래밍에서 문제가 된다. 그래서 많은 것들을 제한할 수록 코드는 안전해진다.

내부적인 변경 없이 작은 인터페이스를 유지하고 싶다면, 가시성(visibility)을 제한하면 된다.
기본적으로 클래스와 요소를 외부에 노출할 필요가 없다면, 가시성을 제한해서 외부에서 접근할 수 없게 만드는 것이 좋다.
가시성 제한은 가시성 한정자(visibility modifier)를 활용해서 구현한다.

class member

  • public(default) : 어디에서나 볼 수 있다.
  • private : 클래스 내부에서만 볼 수 있다.
  • protected : 클래스와 서브클래스 내부에서만 볼 수 있다.
  • internal : 모듈 내부에서만 볼 수 있다.

top level

  • public(default) : 어디에서나 볼 수 있다.
  • private : 같은 파일 내부에서만 볼 수 있다.
  • internal : 모듈 내부에서만 볼 수 있다.

모듈과 패키지를 혼동하는 개발자들이 있는데 그 의미는 전혀 다르다. 코틀린에서의 모듈이란 함께 컴파일되는 코틀린 소스를 의미한다.

module

  • Gradle source set
  • Maven project
  • IntelliJ IDEA module
  • Ant task 한 번으로 컴파일 되는 file set

internal의 사용은 모듈이 다른 모듈에 의하여 사용될 가능성이 있어 공개하고 싶지 않은 요소를 숨겨야 할 때 사용한다.
protected의 사용은 요소가 상속을 위해 설계되어있고 클래스와 서브클래스에서만 사용하도록 만들 때 사용한다.
private의 사용은 동일한 파일 또는 클래스에서만 요소를 사용하도록 만들 때 사용한다. 코틀린은 지역적으로만 사용되는 요소에 대하여 private로 만드는 것이 좋다는 컨벤션을 제공한다.

이러한 규칙은 data model class, DTO에는 적용하지 않는 것이 좋다. (데이터를 저장하도록 설계된 클래스)
데이터를 저장하도록 설계된 클래스는 숨겨야할 이유가 없다.

문서

규약

어떤 행위를 설명하면 사용자는 이를 일종의 약속으로 취급하여 이를 기반으로 자유롭게 예측을 조정한다.
이처럼 예측되는 행위를 요소의 규약(contract of an element)이라고 부른다. 현실의 규약처럼 규약의 당사자들은 서로 상대방이 규약을 안정적으로 지킬 거라 믿는다.
규약이 적절하게 정의되어 있다면, 클래스를 만든 사람은 클래스가 어떻게 사용될지 걱정하지 않아도 된다.
따라서 규약만 지킨다면 원하는 부분을 마음대로 수정할 있다. 서로가 규약을 존중한다면, 독립적으로 작업해도 모든 것이 정상적으로 작동한다.

추상화 규약

규약은 개발자들의 단순한 합의이기 때문에 한쪽에서 규약을 위반할 수도 있다.
또한 기술적으로 모든 부분에서 이런 규약 위반이 발생할 수 있다. 프로그램을 안정적으로 유지하고 싶다면, 규약을 지켜야 하며 만약 규약을 수밖에 없다면 이를 문서화해야 한다.

728x90
반응형