소프트웨어 개발에서 흔히 '중복을 피하라(DRY: Don't Repeat Yourself)'는 원칙이 강조되지만, 때로는 '잘못된 추상화(wrong abstraction)'가 코드 중복보다 훨씬 더 큰 문제를 야기할 수 있습니다. 섣부른 공통화는 단기적으로는 효율적으로 보일지 몰라도, 장기적으로는 유지보수 비용을 증가시키고 코드의 유연성을 저해하는 주범이 됩니다. 개발자들은 종종 미래의 불확실한 요구사항까지 포괄하려다 과도하게 일반화된 추상화를 만들곤 합니다.
잘못된 추상화가 만들어지는 과정은 대체로 비슷합니다. 개발자가 비슷한 코드 조각을 발견하고 이를 메서드나 클래스로 추출하여 새로운 추상화를 만듭니다. 하지만 시간이 지나면서 기존 추상화와 '거의 비슷하지만 완전히 같지는 않은' 새로운 요구사항이 등장합니다. 이때 개발자는 기존 추상화를 버리기 아까워 매개변수를 추가하고 조건문을 넣어 다양한 경우를 처리하려 합니다. 이러한 시도가 반복되면서 코드는 점점 더 복잡해지고 이해하기 어려워지며, 새로운 기능을 추가할 때마다 기존 코드가 깨지기 쉬운 불안정한 상태가 됩니다. 이는 이미 들인 노력에 대한 미련 때문에 합리적이지 않은 결정을 내리는 '매몰비용 오류(sunk cost fallacy)'와도 연결됩니다.
이러한 상황에서 해결책은 잘못된 추상화를 고집하는 것이 아니라, 과감하게 뒤로 돌아가는 것입니다. 즉, 추상화된 코드를 각 호출부에 다시 인라인(inline)하여 중복을 재도입하는 것입니다. 이 과정을 통해 각 호출부에 실제로 필요한 코드만 남기고 불필요한 조건문과 매개변수를 제거할 수 있습니다. 이전 추상화를 완전히 제거한 후에야 현재 요구사항에 맞는 새로운 공통점을 다시 관찰하고, 더 적절한 추상화를 추출할 수 있습니다. 이는 후퇴가 아니라 더 나은 전진을 위한 필수적인 단계입니다.
이러한 접근 방식은 소프트웨어 설계의 유연성을 확보하고 장기적인 유지보수성을 높이는 데 중요합니다. 특히 요구사항이 빠르게 변화하는 현대 개발 환경에서는 '단일 진실 공급원(single source of truth)' 원칙을 지키면서도, 추상화가 불편해지기 시작하면 과감히 버릴 줄 아는 지혜가 필요합니다. 코드가 여러 맞춤 동작을 위해 수많은 플래그(flag)를 필요로 한다면, 이는 잘못된 추상화이거나 '단일 책임 원칙(Single Responsibility Principle)'을 위반했을 가능성이 높습니다. 따라서 추상화는 그 필요가 명확해질 때까지 기다리고, 실제로 입증된 사용 사례에 대해서만 적용하는 것이 현명합니다.