Hanbit the Developer

Effective Kotlin | 4장. 추상화 설계 본문

Mobile/Kotlin

Effective Kotlin | 4장. 추상화 설계

hanbikan 2023. 6. 18. 14:51

아이템 26: 함수 내부의 추상화 레벨을 통일하라

올바른 예시:

fun makeCoffee() {
	boilWater()
	brewCoffee()
	pourCoffee()
}

잘못된 예시:

fun makeCoffee() {
	// boil water
	val water = findWater()
	val kettle = findKettle()
	kettle.boil(water)

	brewCoffee()
	pourCoffee()
}

아이템 27: 변화로부터 코드를 보호하려면 추상화를 사용하라

추상화 할 수 있는 방법은 다음과 같다:

  • 상수로 추출한다.
  • 동작을 함수로 래핑한다.
  • 함수를 클래스로 래핑한다.
  • 인터페이스 뒤에 클래스를 숨긴다.
  • 보편적인 객체를 특수한 객체로 래핑한다.

다만 추상화가 과도하면 코드가 복잡해지기 때문에 다음과 같은 기준으로 균형을 맞춰야 한다:

  • 팀의 크기
  • 팀의 경험
  • 프로젝트의 크기
  • feature set
  • 도메인 지식

아이템 28: API 안정성을 확인하라

프로그래밍에서 안정적이고 최대한 표준적인 API를 선호하는 이유:

  1. unstable하기 때문에 API가 자주 변경된다면 여러 코드를 수동으로 업데이트 해야 한다.
  2. 사용자가 새로운 API를 배워야 한다.

그럼에도 불구하고 좋은 API를 한번에 설계하기 어렵기 때문에 적절한 변경도 필요하다.

API 또는 API 일부가 불안정하다면 이를 알려야 한다.

시멘틱 버저닝

MAJOR.MINOR.PATCH(ex: 2.44.2)

  • MAJOR: 호환되지 않는 수준의 API 변경
  • MINOR: 이전 변경과 호환되는 기능을 추가
  • PATCH: 간단한 버그 수정

Annotation

  • @Experimental: 해당 요소는 안정적이지 않다는 것을 알림
  • @Deprecated: 직접적인 대안이 있다면 ReplaceWith를 붙일 수도 있음(IDE가 자동 전환)

아이템 29: 외부 API를 랩(wrap)해서 사용하라

안전하다고 명시되어 있어도 신뢰할 수 없는 경우, 이 불안정한 API를 과도하게 사용해선 안 된다. 따라서 이를 wrap해서 사용한다.

장점은 다음과 같다:

  • 문제 발생 시 wrapper만 변경하면 된다.(코드 변경이 쉽다.)
  • 프로젝트 스타일에 맞춰 API 형태를 조정할 수 있다.

단점은 다음과 같다:

  • wrapper를 따로 정의해야 한다.
  • 다른 개발자가 프로젝트를 다룰 때 어떤 wrapper들이 있는지 따로 확인해야 한다.
  • wrapper는 내부에서만 유효하므로 문제가 생겨도 stack overflow 등에 질문할 수 없다.

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

아이템 30: 요소의 가시성을 최소화하라

장점:

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

아이템 31: 문서로 규약을 정의하라

KDoc 주석으로 의도를 명시하라.

함수나 클래스 이름만을 예측할 수 없는 사항들에 대해 추가적인 설명이 필요하다.

규약

규약을 정의하여, 클래스의 오사용을 방지하고 사용자는 내부 구현을 알지 않아도 된다.

규약을 정의하는 방법:

  • 이름: sum()이라는 이름만으로 문서를 볼 필요도 없게 만든다.
  • 주석과 문서
  • 타입

주석을 써야 할까?

[클린 코드] 이후 주석을 읽지 않고도 읽을 수 있는 코드가 인기가 많아졌다.

단, 어느쪽이든 극단적인 것은 좋지 않으므로 ‘적절히’ 사용해야 한다.

KDoc 형식

주석으로 함수를 문서화할 때 사용되는 공식적인 형식이며 KDoc 마크다운 형식으로 작성한다.

/**
* Hello world!
*/

주석의 구성 요소는 다음과 같다:

  • 요약 설명
  • 상세 설명
  • 태그
    • @param <name>
    • @return
    • @constructor
    • @receiver: 확장 함수의 리시버를 문서화한다.
    • @property <name>
    • @throws <class>, @exception <class>
    • @sample <identifier>
    • @see <identifier>
    • @author
    • @since: 요소에 대한 버전을 지정한다.
    • @supress: 지정 시 만들어지는 문서에서 해당 요소가 제외된다. 외부에서 사용되지만 공식 API에 포함할 필요가 없는 요소에 지정한다.

관련된 요소들에 링크를 걸 때는 대괄호를 사용한다.(ex: @see [Fragment])

링크 대상에 대한 추가 설명을 입력하고 싶을 때는 대괄호를 두 번 연속해서 사용한다.(ex: [this element with custom description][Element])

Dokka: 공식적인 코틀린 문서 생성 도구

아이템 32: 추상화 규약을 지켜라

규약은 단순한 합의이기 때문에 위반될 수 있다. 무언가를 할 수 있다고 해도 그것을 해도 괜찮다는 것이 아니므로 규약을 지켜야 한다.

상속된 규약

클래스를 상속하거나 인터페이스를 구현할 때 규약을 반드시 지켜야 한다.