잘 설계된 소프트웨어는 현재 요구사항을 넘어서 나중에 읽고 고치기 쉬운 구조를 남긴다

프로그램이 잘 설계되었는지를 묻는 가장 쉬운 방법은 “지금 잘 돌아가는가?”라고 묻는 것이다. 하지만 그 질문만으로는 부족하다. 오늘 잘 돌아가도, 한 달 뒤 작은 변경 하나에 전체가 흔들리면 그 설계는 오래 버티기 어렵다.
잘 설계된 소프트웨어는 현재 요구사항을 충족할 뿐 아니라, 읽기 쉽고, 바꾸기 쉽고, 테스트하기 쉬운 구조를 남긴다.
1. 먼저 현재 요구사항을 제대로 해결해야 한다
아무리 우아한 구조라도 지금 필요한 기능과 성능을 충족하지 못하면 좋은 설계라고 보기 어렵다. 이 기준은 가장 기본이지만 자주 잊힌다.
좋은 설계는 미래 대비만 하는 구조가 아니라, 먼저 현재 문제를 정확히 푼다. 즉 설계의 첫 조건은 현실 적합성이다.
2. 자주 바뀌는 결정은 바깥으로 새지 않게 숨겨야 한다
파나스가 말한 정보 은닉은 지금도 가장 강한 기준 가운데 하나다. 저장소 구현, 외부 API 세부 규약, 점수 계산 공식, 파일 포맷 같은 결정은 시간이 지나며 자주 바뀐다. 이런 세부 사항이 시스템 전체에 퍼져 있으면 변경 비용이 폭발한다.
그래서 잘 설계된 소프트웨어는 변경 가능성이 큰 결정을 경계 뒤에 숨긴다. 이 원칙만 지켜도 결합도가 크게 내려간다.
3. 읽기 쉬워야 유지보수가 가능하다
코드는 한 번 쓰고 끝나지 않는다. 훨씬 더 자주 읽히고 고쳐진다. 그래서 가독성은 미적 취향이 아니라 유지보수 비용과 직결된 속성이다.
읽기 쉬운 구조는 보통 이런 특징을 가진다.
- 이름이 역할을 설명한다.
- 함수가 한 가지 책임에 집중한다.
- 흐름이 과하게 꼬여 있지 않다.
- 예외 처리와 정상 흐름이 구분된다.
즉 좋은 설계는 멋진 추상화보다도 읽는 사람의 부담을 낮춘다.
4. 변경이 쉬워야 좋은 설계다
소프트웨어는 결국 바뀐다. 기능 추가, 정책 변경, 외부 시스템 교체, 성능 요구 변화가 계속 들어온다. 그래서 설계 품질은 처음 구현의 아름다움보다, 변경 비용에서 더 잘 드러난다.
이 점에서 리팩터링은 마무리 작업이 아니라 설계의 일부다. 구조를 조금씩 다듬어 코드가 계속 변경을 견딜 수 있게 만드는 과정이기 때문이다.
5. 과잉 설계를 피해야 오래 간다
잘 설계된 소프트웨어는 단순해야 한다. 여기서 단순함은 기능이 적다는 뜻이 아니라, 필요 이상의 추상화와 확장을 미리 집어넣지 않는다는 뜻이다.
Fowler의 YAGNI가 강조하듯, 아직 필요하지 않은 일반화는 미래 대비처럼 보이지만 실제로는 현재 복잡성만 키우기 쉽다. 좋은 설계는 모든 가능성을 선반에 올려두는 구조가 아니라, 지금 필요한 것을 명확하게 만들고 변화가 오면 다시 다듬을 수 있는 구조다.
핵심 정리
잘 설계된 소프트웨어는 지금 요구사항을 푸는 데서 출발하지만, 거기서 끝나지 않는다. 자주 바뀌는 결정을 숨기고, 읽기 쉽게 만들고, 변경 비용을 낮추고, 과잉 설계를 피해야 오래 간다.
즉 좋은 설계의 기준은 “지금 동작한다”를 넘어선다. “나중에 다시 읽고 고치기 쉬운가”까지 가야 비로소 좋은 설계라고 부를 수 있다.