knowledge를 반복하여 사용하지 말라.

필자가 말하는 큰 규칙은 다음과 같습니다.

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

흔히 말하는 DRY규칙(Don’t Repeat Yourself), WET안티패턴(개발자는 타이핑을 좋아하느모, 많은 사람의 시간을 낭비하게 만들거나 같은 코드를 두 번씩 작성한다.)을 의미합니다.

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

ex) 알고리즘의 작동방식, UI의 형태, 우리가 원하는 결과 등 코드, 설정, 템플릿 등으로 표현이 가능.

  1. 로직: 프로그램이 어떠한 식으로 동작하는지와 프로그램이 어떻게 보이는지
  2. 공통 알고리즘: 원하는 동작을 하기 위한 알고리즘.

위 두가지의 큰 차이점은 시간에 따른 변화를 뜻한다. 비즈니스 로직은 시간이 지남에따라 계속해서 변하지만 공통 알고리즘은 한 번 정의된 이후에는 크게 변하지 않는다.

모든것은 변화한다.

프로그래밍에서 유일하게 유지되는 것은 ‘변화한다는 속성’이라는 말이 있다. 10년 20년이 지난 프로그램을 확인해보면 모든 프로젝트의 라이브러리, 아키텍처, 설계가 많이 변화했다.

변화하는 이유 중 몇가지를 확인해보면

  1. 회사가 사용자의 요구 또는 습관을 더 많이 알게 되었다.
  2. 디자인 표준이 변화했다.
  3. 플랫폼, 라이브러리, 도구 등이 변화해서 이에 대응해야 한다.

이러한 변화를 대비해야하며 가장 큰 적이 여러 부분에 반복되어 있는 코드 즉, kwnoledge이다.

간단하게 생각한다면 모두 찾고 모두 변경하면 됩니다. 하지만 이러한 과정에서 실수가 발생할 수도 있으며, 무엇보다 귀찮습니다. 일부를 빼먹거나 과거에 다른 방식으로 이미 변경된 경우 이는 큰 문제가 됩니다.

ex) 범용적인 버튼의 UI 변경, DB내 테이블 이름의 변경 등

이는 확장성을 막고 쉽게 문제를 만듭니다.

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

얼픽보면 knowledge의 반복처럼 보이지만 실질적으로는 다른 경우. 신중하지 못한 추출은 변경을 더 어렵게 만들어버린다.

ex) 독립적인 2개의 Android App이 있을때 빌드 도구설정이 비슷할 것이므로, 이를 추출해서 반복을 줄일 수 있다고 생각하지만 두 앱은 독립적이라 일부만 구성 변경이 필요할 수도 있다.

이를 가늠하는 방법으로

  1. 변경될 가능성이 높은지, 혹은 따로 변경될 가능성이 높은지로 어느정도 결정할 수 있다.
  2. 비즈니스 규칙이 다른 곳 즉 다른 소스코드에서 왔는지 확인 - 다른 곳에서 왔다면, 독립적으로 변경될 가능성이높다.

잘못된 코드 추출로부터 우리를 보호하는 규칙이 바로 SRP(단일책임 원칙)이다.

단일 책임 원칙

코드를 추출해도 되는지를 확인하는 원칙으로 SOLID 원칙 중 하나인 단일 책임 원칙이 있다. ( 클래스를 변경하는 이유는 단 한 가지여야 한다.)

Clean Arcitecture의 예시로 두 액터가 같은 클래스를 변경하는 일은 없어야 한다. 액터란 변화를 만들어내는 존재, 가령 서로의 업무와 분야에 대해서 잘 모르는 개발자들을 의미한다.

ex)

  1. 어느 대학에서 Student라는 클래스를 가지고 있다.
  2. 해당 클래스는 장학금을 관리하는 부서와 인증과 관련된 부서에서 모두 사용한다.
  3. 장학금을 관리하는 부서에서 학생이 장학금을 받을 수 있는 포인트를 가지고 있는지를 나타내는 관련 프로퍼티를 만들어냄
  4. 인증 관련 부서에서 인증을 통과했는지 여부를 나타내는 프로퍼티를 만들어냄
  5. 위 두 프로퍼티 모두 이전학기 성적을 기반으로 계산됨.
  6. 보다 편하게 하기 위해 이를 한꺼번에 계산하는 함수 하나를 만들어냄
  7. 장학금 관련 요구사항이 변경되며 계산식이 달라짐.
  8. 다른 개발자가 함수 구현부를 변경하면서 두 프로퍼티가 같이 사용된다고 생각해서 두 프로퍼티의 계산식을 같이 변경함.
  9. 버그 발생.

위 예시처럼 개발자는 해당 함수가 활용되는 다른 부분도 확인했지만 해당 함수가 자신이 맡은 일(장학금 관련) 이외의 책임을 가지는 것을 예측하지 못할 수 있다.

두 가지의 책임이 위치적(파일 또는 클래스)으로 가까우므로 합쳐서 개발하는 경우가 있지만 이러한 문제를 방지하려면, 처음부터 책임에 따라 다른 클래스로 구분하거나 혹은 코틀린의 확장 함수를 활용해 각각의 책임을 가지는 서로 다른 모듈 파일에 배치함으로써 책임을 분리할 수 있다.

두 결과를 게산하는 추가적인 함수를 만드는 경우(Helper funciton)을 만드는 경우

  1. 두 곳에서 모두 사용하는 일반적인 public 함수로 헬퍼 함수를 만든다. 공통 부분은 두 부서에서 모두 사용하므로, 이를 함부로 수정해서는 안되게 규약을 정한다.
  2. 헬퍼 함수를 각각의 부서 모듈에 따라 2개 만든다.

위 예시들을 보며 단일 책임 원칙은 두 가지의 사실을 알 수 있다.

  • 서로 다른 곳(위 예시에서는 서로 다른 부서) 에서 사용하는 knowlege는 독립적으로 변경할 가능성이 높다. 따라서 비슷한 처리를 하더라도 완전히 다른 knowledge로 취급하는 것이 좋다.
  • 다른 knowledge는 분리해 두는 것이 좋다. 그렇지 않으면, 재사용해서는 안 되는 부분을 재사용하려는 유혹이 발생한다.

정리

모든 것은 변화하며 따라서 공통 knowledge가 있다면, 이를 추출해서 이러한 변화에 대비해야 한다.

여러 요소에서 비슷한 부분이 있는 경우 변경이 필요한 경우 실수가 발생할 수 있다. 이런 부분은 추출하는 것이 좋다. 의도하지 않은 수정을 피하거나 다른 곳(이전 예의 경우 부서)에서 조작하는 부분이 있다면, 분리해서 사용하는 것이 좋다.

많은 개발자가 ‘Don’t Repeat Yourself’를 지키기 위해 비슷해 보이는 코드는 모두 추출하려는 경향이 있지만 극단적인 것은 언제나 좋지 않다.