[Server] 진짜 중복과 가짜 중복의 구분(중복 여부를 판단하는 기준)
1. 진짜 중복과 가짜 중복의 구분(중복 여부를 판단하는 기준)
[ 진짜 중복과 가짜 중복 ]
개발을 하다 보면 특정 기능에 대한 변경이 다른 기능에도 영향을 주게 되고, 이러한 사이드이펙트로 인해 시스템에 문제가 발생하는 경우가 자주 있다. 당연하게도 문제가 생긴 기능을 빠르게 복구하는 것이 가장 중요하겠지만, 이러한 문제가 생긴 근본적인 원인을 찾는 것 또한 중요하다. 대게 어떠한 기능에 대한 변경이 의도하지 않은 사이드이펙트를 유발하는 것은 단일 책임 원칙(SRP, Single Responsibility Principle)을 위반하기 때문일 것이다.
예를 들어 다음과 같이 배송 주소를 저장하는 ShippingAddress 라는 클래스가 존재하며, ShippingAddress 객체는 집 주소와 회사 주소를 관리하는 상황이라고 하자. 그리고 배송 주소는 255자를 넘지 말아야 한다는 정책이 존재한다고 하면, 이러한 비즈니스 정책에 대한 검증을 객체가 생성되는 시점에 진행할 수 있다.
data class ShippingAddress(
val homeAddress: String,
val companyAddress: String,
) {
init {
if (isAddressTooLong(homeAddress)) {
throw IllegalArgumentException("home address is too Long")
}
if (isAddressTooLong(companyAddress)) {
throw IllegalArgumentException("company address is too Long")
}
}
private fun isAddressTooLong(address: String): Boolean {
return address.length > 255
}
}
이때 주소지가 너무 긴지를 검사하는 isAddressTooLong 메서드는 2번 호출되고 있는 상황이다. 그렇다면 isAddressTooLong는 SRP를 위반하는 것일까 아닐까?
[ SRP에 대한 사실과 오해 ]
일단 먼저 SRP가 무엇이고 어떠한 의미를 지니는지부터 살펴볼 필요가 있다. 로버트 마틴은 SOLID 원칙 중에서 그 의미가 가장 전달되지 못한 원칙으로 SRP(Single Responsibility Principle, 단일 책임 원칙)를 뽑았다. 그리고 SRP는 “하나의 일만 해야한다”는 의미가 아니라 "단일 모듈은 변경의 이유가 하나, 오직 하나뿐 이여야 한다."는 것이라고 설명했다.
그렇다면 isAddressTooLong 메서드는 변경의 이유가 하나일까? 혹은 변경의 이유가 여러 개라서 SRP를 위반하는 상황일까? 해당 메서드가 SRP를 위반하는지는 비즈니스 정책에 따라 다를 것이다. 만약 집 주소와 회사 주소가 비즈니스적으로 동일한 주소라는 범주에 속하며, 주소지 길이를 1000자로 늘려달라는 요구사항이 들어왔을 때 모두 변경되어야 한다면 SRP를 준수하고 있는 것이다. 반면에 집 주소와 회사 주소가 비즈니스적으로 구분된 영역이며, 집 주소를 1000자로 늘려달라는 요구사항이 개별적으로 들어오는 상황이라면 SRP를 위반하는 상황이라고 볼 수 있다. 이러한 경우에는 다음과 같이 메서드를 분리하는 것이 적합한 상황이 될 수도 있다.
data class ShippingAddress(
val homeAddress: String,
val companyAddress: String,
) {
init {
if (isHomeAddressTooLong()) {
throw IllegalArgumentException("home address is too Long")
}
if (isCompanyAddressTooLong()) {
throw IllegalArgumentException("company address is too Long")
}
}
private fun isHomeAddressTooLong(): Boolean {
return homeAddress.length > 255
}
private fun isCompanyAddressTooLong(): Boolean {
return companyAddress.length > 255
}
}
[ 중복 여부를 판단하는 기준 ]
비즈니스를 고려하지 않고 위의 코드를 보면, 문자열 길이가 255가 넘는지를 검사하는 동일한 로직으로 보일 것이기 때문에 (가짜) 중복으로 해석될 수 있다. 하지만 우리가 작성한 코드들은 비즈니스 가치를 창출하기 위한 코드들이므로, 비즈니스적인 맥락을 고려하지 않으면 안 된다. 이렇듯 비즈니스적으로 다른 정책이며 코드는 비슷하게 보이지만 실질적인 의미가 다른 중복을 가짜 중복, 비즈니스적으로 동일한 정책이라서 중복에 해당하는 부분을 진짜 중복으로 구분할 수 있다. 이렇듯 중복이라는 것은 진짜 중복과 가짜 중복이라는 2가지의 내재적 개념을 갖는다.
따라서 해당 코드가 여러 개의 변경의 이유를 가지며 SRP를 위반하는지 혹은 중복에 해당하는 코드라서 중복을 제거해야 하는지 등을 판단하려면, 진짜 중복인지 가짜 중복인지를 먼저 구분해야 한다. 그리고 이를 위해서는 작성된 코드의 글자들 그 자체가 아니라 코드 이면의 비즈니스적인 부분도 반드시 함께 고려되어야 한다. 그렇기 때문에 개발자 역시 비즈니스를 잘 이해하고 있어야 불필요한 사이드이펙트를 예방할 수 있고, 비즈니스를 의도대로 문제 없이 구현할 수 있을 것이다.