코드로 관리해야 하는 이유
팀원이 새로 들어온 경우 팀마다 개발하는 환경과 절차가 있기 때문에 이를 알려줘야 한다.
수동
가장 단순한 방법으로는 사람이 붙어서 알려주는 방식이 있다.
이는 아래와 같은 단점이 있다.
1. 시간과 인력의 비효율
2. 누락과 실수에 취약
문서화
다른 방법으로는 개발 환경과 절차를 문서로 관리하는 것이다.
이는 아래와 같은 단점이 있다.
1. 매번 전파 필요
2. 동기화 보장 어려움
3. 문서 오류에 취약
코드 관리
다른 방법으로는 코드로 관리하는 것이다.
보통 버전 관리 도구로 코드를 관리하기 때문에 다음과 같은 장점이 있다.
1. 버전 관리 가능
2. 자연스럽게 최신화
3. 실수 여지 최소화
4. 함수나 변수를 사용해서 재사용 가능
도구와 문법
카카오에서는 코틀린과 스프링을 사용하고 있고 이와 관련된 도구를 사용하고 있다.
린터
코드 정적 분석기로 잠재적 오류를 검출한다.
카카오에서는 kotlin 전용 도구인 detekt를 사용하고 있고 yml 파일을 통해 설정이 가능하다.
아래 설정을 통해 enum class의 이름은 upper camel case로 검사하고
enum entry의 이름은 upper snake case로 검사한다.
naming:
EnumNaming:
active: true
포매터
코드 스타일을 자동으로 정리해준다.
카카오에서는 kotlin 전용 도구인 ktfmt를 사용하고 있고 개별 설정을 최소화해서 사용하고 있다.
ktfmt {
kotlinLangStyle()
}
타입 제약
sealed interface는 하위 타입의 범위를 컴파일 타임에 한정할 수 있는 문법이다.
sealed interface를 구현하는 하는 타입은 같은 모듈 또는 같은 파일에서만 정의 가능하다.
아래에서 Result의 type이 SUCCESS인지 FAILURE 2가지 있는 것을 확인할 수 있고
SUCCESS인지 FAILURE인지에 따라 사용하는 필드와 null 처리 해야하는 필드가 존재하는 것을 확인할 수 있다.
enum class ResultType {
SUCCESS,
FAILURE
}
data class Result(
val type: ResultType,
val data: String?,
val error: Throwable?
)
하지만 sealed class를 사용해서 아래처럼 정의하면
Result를 구현하는 타입은 Success와 Failure 2가지뿐이고
위와 비교했을 때 컴파일 타임에 타입을 더 강력하게 제약해주는 것을 확인할 수 있다.
sealed interface Result
data class Success(val data: String): Result
data class Failure(val error: Throwable): Result
타입을 제약해주는 또 다른 문법이 있다.
value class는 값의 의미를 타입을 고정해주는 문법이다.
userId와 orderId는 모두 Long 타입이기 때문에 서로 섞여도 컴파일 타임에 문제를 파악할 수 없다.
하지만 아래처럼 value class를 사용해서 정의하면 섞이는 것을 컴파일 타임에 방지할 수 있다.
@JvmInline
value class UserId(val value: Long)
@JvmInline
value class OrderId(val value: Long)
fun findUser(userId: UserId) {
...
}