코드 품질 개선 기법 14편: 책임을 부여하는 오직 하나의 책임 (새 탭에서 열림)
단일 책임 원칙(SRP)을 기계적으로 적용하여 클래스를 과도하게 분리하면, 오히려 시스템 전체의 복잡도가 증가하고 사양의 제약 조건을 파악하기 어려워질 수 있습니다. 코드 품질을 높이기 위해서는 개별 클래스의 응집도뿐만 아니라, 분리된 클래스들이 맺는 의존 관계와 호출자가 짊어져야 할 관리 부담을 종합적으로 고려해야 합니다. 결국 핵심적인 제약 조건을 한곳에서 관리할 수 있다면, 약간의 책임이 섞여 있더라도 초기 구현의 단순함을 유지하는 것이 더 나은 선택일 수 있습니다. **과도한 책임 분리가 초래하는 문제** * 동적으로 실행 로직이 변하는 '론치 버튼'을 구현할 때, 버튼 바인딩 책임과 로직 선택 책임을 별도 클래스로 분리하면 각 클래스는 단순해지지만 시스템 구조는 복잡해집니다. * 로직별로 별도의 바인더 인스턴스를 생성하고 `isEnabled` 상태를 통해 실행 여부를 제어하게 되면, 버튼 하나에 여러 개의 리스너가 등록되는 등 내부 동작을 추적하기 어려워집니다. * 결과적으로 "단 하나의 로직만 실행되어야 한다"는 비즈니스 제약 조건을 확인하기 위해 여러 클래스와 루프 문을 모두 훑어야 하는 비용이 발생합니다. **제약 조건의 분산과 상태 중복** * 책임을 분리하면 특정 사양이 코드 전체로 흩어지는 '책임 떠넘기기' 현상이 발생할 수 있습니다. * 예를 들어 어떤 로직이 활성화되었는지 나타내는 상태를 상위 클래스(Selector)에 추가하면, 하위 클래스(Binder)의 `isEnabled` 속성과 데이터가 중복되어 상태 불일치 문제가 생길 위험이 있습니다. * 이러한 중복은 코드의 신뢰성을 떨어뜨리며, 사양 변경 시 수정해야 할 포인트가 늘어나는 결과를 초래합니다. **의존성 비대화와 라비올리 코드(Ravioli Code)** * 세부 사항을 은닉하기 위해 의존 관계를 더 잘게 쪼개면, 이를 조합해야 하는 호출자(Caller)의 코드가 비대해지는 '갓 클래스(God Class)' 현상이 나타날 수 있습니다. * 너무 작은 단위로 쪼개진 클래스들이 서로 얽히면 전체 흐름을 파악하기 위해 수많은 파일을 오가야 하는 '라비올리 코드'가 되어 유지보수성이 저하됩니다. * 객체 지향의 핵심은 캡슐화인데, 제약 조건을 보장하는 로직을 분리해버리면 오히려 캡슐화가 깨지고 외부 의존성만 강해지는 부작용이 생깁니다. **실용적인 설계를 위한 제언** 클래스를 분할할 때는 응집도라는 단일 지표에만 매몰되지 말고, 분할 후의 의존성 그래프와 호출자의 편의성을 반드시 확인해야 합니다. 만약 특정 클래스가 내부에서 핵심 제약 조건을 깔끔하게 관리하고 있다면, 억지로 책임을 나누기보다 그 응집된 구조를 유지하는 것이 시스템 전체의 결합도를 낮추고 코드의 가독성을 높이는 길입니다.