단순 설계
Simple Design
개념
지금 필요한 것까지만 구조를 만들고, 나중에 필요해지면 그때 구조를 다시 뽑는 쪽을 택하는 설계 원칙입니다.
등장 배경
설계를 잘한다는 말은 오래 미래를 대비한다는 말과 붙어 있었습니다. 요구가 바뀔 테니 바뀔 자리를 미리 열어 두는 것이 실력이라고 여겼습니다.
문제는 그 예측이 잘 맞지 않는다는 점입니다. 태오가 결제 기능을 만들 때 결제 수단을 나중에 여럿 붙일 수 있게 층을 하나 두었습니다. 2년이 지난 지금도 결제 수단은 카드 하나입니다. 그동안 그 코드를 읽은 사람은 쓰이지 않는 층을 지나가야 했고, 새로 온 사람은 그 구조가 왜 있는지 이해하는 데 이틀을 썼습니다.
더 나쁜 경우도 있습니다. 결제 수단이 실제로 추가됐는데 미리 만든 층이 그 모양에 맞지 않는 것입니다. 정기 결제를 붙일 때 필요한 것은 수단을 바꾸는 구조가 아니라 주기와 청구를 다루는 구조였습니다. 미리 만든 것은 쓰지도 걷어 내지도 못해 남았습니다.
여기서 나온 판단이 하나입니다. 틀릴 확률이 높은 예측에 지금 비용을 치르는 대신, 지금 아는 것까지만 만들고 나중에 고치기 쉽게 두는 편이 싸다는 것입니다. 단순 설계는 그 판단을 실천 규칙으로 만든 것입니다.
작동 방식
단순한지 판단하는 기준이 네 개 있고, 적힌 순서가 곧 우선순위입니다. 앞의 기준이 뒤의 기준보다 먼저입니다.
- 모든 테스트를 통과합니다. 동작하지 않는 코드는 짧아도 단순한 것이 아닙니다. 첫 자리인 이유는 나머지 셋이 코드를 고치는 일을 요구하기 때문입니다. 테스트가 없으면 고치는 것이 무서워지고, 무서우면 구조가 굳습니다.
- 의도가 드러납니다. 읽는 사람이 이 코드가 무엇을 하려는지 알 수 있어야 합니다. 이름이 하는 일과 다르거나, 조건문 세 겹 안에 규칙이 숨어 있으면 이 기준에 걸립니다.
- 중복이 없습니다. 같은 규칙이 두 곳에 있으면 한쪽만 고치는 일이 생깁니다. 다만 겉모양이 닮은 것과 같은 규칙인 것은 다릅니다. 우연히 닮은 코드를 묶으면 한쪽만 바뀔 때 더 나빠집니다.
- 요소 수가 가장 적습니다. 위 셋을 지키면서 클래스와 함수와 층의 개수가 최소인 상태입니다. 순서가 마지막인 것이 중요한데, 개수를 줄이려고 의도를 흐리거나 중복을 남기면 거꾸로 간 것입니다.
실천은 두 동작으로 이뤄집니다. 지금 필요한 것만 만드는 것과, 필요해진 순간에 구조를 뽑아내는 것입니다. 뒤쪽이 리팩터링이고, 동작은 그대로 두고 구조만 바꾸는 작업을 말합니다. 결제 수단이 실제로 둘이 되는 날 그때의 두 가지 모양을 보면서 공통을 뽑으면, 상상으로 만든 층보다 맞는 것이 나옵니다.
이 두 동작은 테스트에 기대고 있어 테스트 주도 개발과 함께 쓰입니다. 테스트를 먼저 써 두면 구조를 바꿔도 동작이 같은지 바로 확인되고, 그래서 구조를 자주 바꿀 수 있습니다. 설계 시점을 필요해질 때로 옮기는 일은 되돌릴 수 있을 때만 성립합니다.
쓰이는 곳
요구가 자주 바뀌는 자리에 맞습니다. 사용자 반응으로 방향을 고치는 초기 제품, 몇 주 단위로 우선순위가 바뀌는 팀입니다. 예측이 맞을 확률이 낮은 만큼 미리 만든 구조가 버려질 확률도 높습니다.
반대로 미리 정해야 하는 자리가 있습니다. 나중에 바꾸는 비용이 지금 정하는 비용보다 훨씬 큰 것들입니다.
- 외부에 공개한 API — 쓰는 쪽이 이미 붙어 있으면 모양을 바꿀 때 그쪽도 함께 고쳐야 합니다.
- 데이터 구조 — 이미 쌓인 데이터를 옮기는 작업이 붙습니다. 100만 행이 들어간 뒤 열 구성을 바꾸면 이전 작업과 중단 시간이 생깁니다.
- 보안 경계 — 권한을 어디서 확인할지는 나중에 끼워 넣기 어렵습니다. 뒤늦게 넣으면 확인이 빠진 경로가 남습니다.
- 되돌릴 수 없는 외부 약속 — 계약서에 적힌 응답 형식이나 파일 규격이 여기 들어갑니다.
이 넷을 가르는 기준은 되돌리기 비용의 비대칭입니다. 코드 안의 구조는 틀렸다고 알게 된 다음에 고쳐도 하루면 되고, 데이터 구조는 두 주가 됩니다. 그래서 같은 팀에서도 코드는 단순하게 가고 데이터 구조는 미리 그리는 방식이 함께 쓰입니다.
이 원칙이 기술 부채를 줄인다고 단정하기는 어렵습니다. 기술 부채는 빨리 가려고 미뤄 둔 정리가 쌓인 비용입니다. 안 쓸 구조를 만들지 않아 한쪽 부채는 막지만, 필요해진 순간에 리팩터링을 하지 않으면 다른 쪽이 쌓입니다.
실무 용례
"지금은 카드만 있으니 인터페이스 안 빼고 그냥 쓰죠. 둘 되면 그때 뽑고요."
예측으로 추상을 만들지 말고 실제 두 번째 경우를 보고 정하자는 제안입니다.
"이 추상 층 쓰는 곳이 한 군데예요. 걷어 내도 될 것 같습니다."
쓰이지 않는 구조를 정리하자는 말입니다.
"데이터 스키마는 단순 설계 대상이 아니에요. 이건 미리 정합시다."
되돌리기 비용이 큰 자리는 다르게 다루자는 지적입니다.
페이지덱에서 이 원칙이 가장 자주 나오는 자리는 코드 리뷰입니다. 태오가 자주 쓰는 질문이 하나 있는데, 이 구조를 지금 쓰는 곳이 몇 군데냐는 것입니다. 한 군데면 층을 만들지 않고 그냥 씁니다.
민서가 이 방식에 불편해한 적이 있습니다. 화면 컴포넌트를 나중에 재사용할 것 같은데 매번 그때 뽑자고 하니 같은 코드를 두 번 쓰게 되는 것처럼 느껴졌습니다. 그래서 규칙을 정했습니다. 두 번째로 같은 것이 필요해지면 그때 뽑고, 그전에는 뽑지 않습니다. 두 번째 사례가 있으면 무엇이 같고 다른지가 보여서 뽑은 결과가 오래 갑니다.
흔한 오해
설계를 하지 않는 것으로 읽는 경우가 가장 많습니다. 미리 만들지 않는다는 말이 생각하지 않는다는 말처럼 들립니다. 하지만 네 기준 중 셋이 구조에 관한 것이고, 지키려면 계속 판단해야 합니다. 중복인지 우연히 닮은 것인지 가르는 일과 의도가 읽히는 이름을 고르는 일은 층을 미리 쌓는 것보다 더 자주 하는 판단입니다. 설계 총량이 아니라 설계 시점이 뒤로 옮겨 갑니다.
코드가 짧으면 단순하다고 보는 것도 흔합니다. 요소 수가 기준에 들어 있으니 짧은 쪽이 이긴다고 읽힙니다. 하지만 그 기준은 네 번째이고, 앞의 세 기준을 지킨 다음에 적용됩니다. 조건을 한 줄에 몰아넣어 짧게 만든 코드는 의도가 안 드러나므로 두 번째 기준에서 이미 탈락합니다. 단순하다는 말은 읽기 쉽다는 뜻에 가깝고, 짧다는 것과는 자주 어긋납니다.
같이 보면 좋은 페이지
- 익스트림 프로그래밍
이 원칙이 어느 방법론의 실천법인지 먼저 봅니다
- 페어 프로그래밍
같은 방법론의 다른 실천법을 함께 확인합니다
마지막 업데이트 2026-09-16