본문 바로가기
Study OR Book/Book

[이펙티브 코틀린] 아이템19: knowledge를 반복하여 사용하지 말라

by Baest 2025. 1. 15.

 

이 책의 저자가 생각하는 프로그래밍의 가장 큰 규칙은 아래와 같다.

프로젝트에서 이미 있던 코드를 복사해서 붙여넣고 있다면, 무언가가 잘못된 것이다.

 

이번 챕터의 제목인 'knowledge를 반복하여 사용하지 말라'는 위의 내용을 저자의 방식으로 표현한 것이다.

위 규칙은 DRY 규칙, WET 안티패턴, SSOT 등으로도 불린다.

위 규칙을 확실하게 적용하려면, 언제 왜 이 이야기가 나오는지 이해해야한다.

 

knowledge

프로그래밍에서 knowledge 는 넓은 의미로 '의도적 정보'를 뜻한다.

프로젝트를 진행할 때 정의한 모든 것이 knowledge가 될 수 있다. 

예를 들어 알고리즘의 작동 방식, UI 형태, 우리가 원하는 결과 등 모두 의도적 정보이자 knowledge 이다.

 

우리 프로그램에서 중요한 knowledge를 크게 두 가지 뽑는다면, 아래와 같다.

1) 로직(logic): 프로그램이 어떠한 식으로 동작하는지와 프로그램이 어떻게 보이는지

2) 공통 알고리즘(common algorithm): 원하는 동작을 하기 위한 알고리즘

 

1) 과 2) 사이의 가장 큰 차이점은 무엇일까?

정답은 시간의 변화이다.

비즈니스 로직은 시간이 지나면서 계속 변하지만 공통 알고리즘은 한 번 정의되면 이후 크게 변하지 않는다.

 

 

모든 것은 변화한다

프로그래밍에서 유일하게 유지되는 것은 '변화한다는 속성'이라는 말이 있다.

모든 것은 변화하고, 우리는 이에 대비해야 한다. 변화할 때 가장 큰 적은 knowledge가 반복되어 있는 부분이다.

 

여러 종류의 추상화를 표현할 수 있는 수많은 솔루션이 있으며, 이를 활용하면 반복을 줄일 수 있다.

 

 

언제 코드를 반복해도 될까?

이 파트에서는 추출을 통해 knowledge 반복을 줄이면 안 되는 상황을 이야기하고 있다.

 

예를 들어 독립적인 2개의 안드로이드 프로젝트가 있을 때, 빌드 설정이 비슷할 것이라고 생각하고 이를 추출해서 knowledge 반복을 줄일 수 있다고 볼 수도 있다.

하지만 두 애플리케이션은 독립적이기 때문에 한 쪽의 구성만 변경이 필요할 수도 있을 것이다.

 

코드를 추출하는 이유는 변경을 쉽게 만들기 위함인데, 위와 같이 신중하지 못한 추출은 변경을 더 어렵게 만든다.

 

개발자가 결정을 쉽게 하기 위한 유용한 방법을 소개해 주는데, 그 방법은 '비즈니스의 규칙이 다른 곳에서 왔는지 확인'하는 방법이다.

다른 곳에서 왔다면, 독립적으로 변경될 가능성이 높다.

 

잘못된 코드 추출로부터 우리를 보호할 수 있는 규칙도 있는데, 단일 책임 원칙(Single Responsibillity Principle, SRP) 이다.

 

 

단일 책임 원칙

코드를 추출해도 되는지 확인할 수 있는 원칙으로 SOLID 원칙 중 하나인 단일 책임 원칙이 있다.

 

단일 책임 원칙: 클래스를 변경하는 이유는 단 한가지여야 한다.

 

만약 서로의 업무와 분야에 대해 잘 모르는 개발자들이 있다고 가정했을 때, 개발자들이 같은 코드를 변경하는 것은 굉장히 위험한 일이다.

 

책에서 들고 있는 예시를 간단히 설명하자면 아래와 같다.

 

- 어떤 대학에서 Student 라는 클래스를 가지고 있다.

- 이 클래스는 장학금 관련 부서, 인증 관련 부서에서 사용하고 있다.

- 두 부서에서 해당 클래스에 qualifiesForScholarship (장학금 관련 부서의 프로퍼티), isPassing(인증 관련 부서의 프로퍼티) 프로퍼티를 추가했다.

- 두 프로퍼티는 직전 학기 성적 기반으로 계산되며, 개발자는 두 프로퍼티를 한 번에 계산하는 calculatePointsFromPassedCourses 함수를 만들었다.

- 그런데 요구사항이 변경되어 장학금 관련 프로퍼티에 수정이 필요했고, 해당 역할을 수행 중인 calculatePointsFromPassedCourses 를 수정했다.

- 하지만 이 과정에서 isPassing 가 함께 수정되어 인증 관련 오류가 발생하게 되었다.

 

만약 StudentIsPassingValidator와 StudentQualifiesForScholarshipValidator 클래스를 구분했다면, 이와 같은 혼선을 막을 수 있었을 것이다.

 

코틀린의 확장 함수를 활용하면, 두 함수는 Student 클래스 아래에 두면서 동시에 각각의 부서가 관리하는 서로 다른 모듈 파일에 배치할 수도 있다.

 

// accreditations 모듈
fun Student.qualifiesForScholarshop(): Boolean {
	/*...*/
}


// scholarship 모듈
fun Student.calculatePointsFromPassedCourses(): Boolean {
	/*...*/
}

 

 

추가적으로 두 결과를 계산하는 함수를 만들 수 있다.

다만 헬퍼 함수는 private 함수로 만들지 않고, 아래 두 가지 방법으로 만드는 것이 일반적이다.

 

1. 두 부서에서 모두 사용하도록 public 함수로 만든다. 하지만 공통 부분은 두 부서에서 모두 사용하므로, 함부로 수정해서는 안된다.

2. 헬퍼 함수를 각각 부서의 모듈에 만든다. (2개)

 

위 긴 예시에 대한 설명이 말하고자 하는 바는 아래와 같다.

 

- 서로 다른 곳에서 사용하는 knowledge는 독립적으로 변경할 가능성이 많다. 따라서 비슷한 처리를 하더라도, 완전히 다른 knowledge로 취급하는 것이 좋다.

- 다른 knowledge는 분리해 두는 것이 좋다. 그렇지 않으면, 재사용해서는 안 되는 부분을 재사용하려는 유혹이 발생할 수 있다.

 

정리

- 공통 knowledg가 있다면, 이를 추출해서 변화에 대비하는 것이 좋다.

- 여러 요소에 비슷한 부분이 있는 경우, 변경이 필요할 때 실수가 발생할 수 있으니 추출하는 것이 좋다.

- 의도하지 않은 수정을 피하려면 또는 다른 곳(부서 등)에서 조작하는 부분이 있다면, 분리해서 사용하는 것이 좋다.

- 정보 시스템 설계는 예술의 영역과 비슷하기 때문에 수많은 시간과 많은 연습이 필요하다.