소프트웨어 설계란 무엇인가?
게시일: 2025년 12월 12일 | 원문 작성일: 1992년 10월 | 저자: Jack W. Reeves | 원문 보기
핵심 요약
1992년에 쓰인 이 고전적 에세이는 소스 코드가 곧 소프트웨어 설계라는 혁명적 주장을 펼칩니다. 30년 이상이 지난 지금도 많은 개발자들이 이 통찰을 이해하지 못하고 있어요.
- 소스 코드 = 설계 문서 — 프로그래밍은 ‘구현’이 아니라 ‘설계’ 활동이에요. 우리가 만드는 진짜 결과물은 코드입니다.
- 컴파일 = 제조 — 컴파일러와 링커가 실제 ‘제조’ 공정을 수행해요. 소프트웨어는 제조 비용이 거의 공짜인 셈이죠.
- 테스트 = 설계 검증 — 테스트와 디버깅은 품질 검사가 아니라, 설계를 다듬는 핵심 활동이에요.
- 설계/구현 분리는 허구 — 설계와 구현을 인위적으로 분리하는 워터폴 방법론의 근본적 문제를 지적합니다.
• • •
들어가며: 진짜 소프트웨어 설계는 어디에?
소프트웨어 개발의 역사에서 끊임없이 반복되는 질문이 있어요. “소프트웨어 개발을 진정한 공학 분야처럼 만들 수는 없을까?” 이 질문에 답하려면 먼저 다른 공학 분야가 어떻게 작동하는지 살펴봐야 해요.
전통적인 공학 분야에서 최종 산출물은 설계 문서예요. 건축가는 건물을 직접 짓지 않죠. 그들은 청사진을 만들고, 그 청사진대로 건설 노동자들이 건물을 ‘제조’합니다. 전자공학도 마찬가지예요. 회로 설계자는 회로도를 만들고, 공장이 그 설계대로 칩을 생산하죠.
그렇다면 소프트웨어에서 이런 의미의 ‘설계 문서’는 무엇일까요? 많은 사람들이 UML 다이어그램, 아키텍처 문서, 요구사항 명세서 같은 것들을 떠올려요. 하지만 정말 그럴까요?
“소프트웨어 문서 중에서 진정한 공학적 설계의 기준을 충족하는 것은 오직 소스 코드뿐이다.”
저자 Jack Reeves는 대담한 주장을 던져요. 소스 코드야말로 진짜 소프트웨어 설계라고요. 프로그래밍은 소프트웨어를 ‘만드는’ 활동이 아니라 ‘설계하는’ 활동이에요.
• • •
소프트웨어 제조의 경제학
이 관점에서 파생되는 가장 근본적인 통찰은 경제적인 것이에요. 만약 소스 코드가 설계이고, 컴파일과 링킹이 제조라면 어떤 일이 벌어질까요?
소프트웨어의 제조 비용은 사실상 0에 가까워요.
자동차 공장에서 설계도면대로 차를 생산하려면 엄청난 비용이 들어요. 원자재, 기계, 노동력, 공장 부지… 하지만 소프트웨어는요? 컴파일러를 한 번 돌리면 끝이에요. 복사도 거의 공짜고요.
이게 왜 중요하냐면, 기존 공학에서 대부분의 비용은 ‘제조’ 단계에서 발생하기 때문이에요. 그래서 설계 단계에 충분한 시간과 노력을 들여서 제조 단계의 오류를 최소화하는 게 합리적이죠. 설계 변경 비용 < 제조 변경 비용이니까요.
| 전통 공학 (하드웨어) | 소프트웨어 | |
|---|---|---|
| 설계 | 청사진, 회로도 | 소스 코드 |
| 제조 | 공장 생산 (비용 높음) | 컴파일/링킹 (비용 ≈ 0) |
| 설계 변경 | 상대적으로 저렴 | 상대적으로 저렴 |
| 제조 후 변경 | 매우 비쌈 | 다시 컴파일하면 됨 |
하지만 소프트웨어에서는 이 공식이 뒤집혀요. 제조 비용이 거의 없으니, 설계를 미리 완벽하게 만들어야 할 경제적 압박이 없어요. 오히려 빠르게 만들어보고, 테스트하고, 수정하는 게 더 합리적이죠.
• • •
테스트와 디버깅은 설계 활동이다
여기서 또 하나의 중요한 통찰이 나와요. 테스트와 디버깅은 설계 활동이라는 거예요.
전통적인 관점에서 테스트는 ‘품질 보증(QA)’ 활동이에요. 이미 만들어진 제품이 사양에 맞는지 검사하는 거죠. 공장에서 불량품을 걸러내는 것과 비슷해요.
하지만 소프트웨어에서 테스트가 하는 일은 달라요. 테스트는 설계의 결함을 발견하고 수정하는 과정이에요. 버그를 발견하면 우리는 소스 코드(즉, 설계)를 수정하죠. 이건 공장에서 불량품을 폐기하는 게 아니라, 청사진 자체를 고치는 것과 같아요.
“테스트와 디버깅은 본질적으로 설계 활동이다. 현실 세계에서 발견된 문제들은 시스템 전체에 걸쳐 연쇄적인 설계 변경을 요구한다.”
하드웨어 공학자들도 프로토타입을 만들고 테스트해요. 하지만 그건 대량 생산 전에 설계를 검증하기 위한 거예요. 프로토타입 제작 비용이 높기 때문에 이 과정은 제한적이죠.
반면 소프트웨어에서는 ‘프로토타입 제작’(컴파일)이 거의 공짜예요. 그래서 빌드-테스트-수정의 반복적 설계가 가장 자연스럽고 효율적인 방식이 됩니다.
• • •
복잡성의 문제
소프트웨어 설계가 비싼 진짜 이유는 복잡성 때문이에요. 소스 코드가 설계이고 제조 비용이 0에 가깝다 보니, 소프트웨어 설계는 다른 어떤 공학 분야보다 훨씬 더 복잡해지는 경향이 있어요.
상용 소프트웨어는 수십만 줄, 때로는 수백만 줄의 코드로 이루어져 있어요. 이건 건물 청사진이나 회로도와는 차원이 다른 복잡성이에요. 아이러니하게도, 이 복잡성이 커지는 이유 자체가 ‘제조 비용이 낮기 때문’이에요. 코드 한 줄 추가하는 비용이 거의 없다 보니, 기능을 더하고 또 더하게 되거든요.
이런 복잡성 때문에, 상위 수준의 설계(아키텍처)를 아무리 잘 해도 실제 코딩 단계에서 예상치 못한 문제들이 쏟아져 나와요. 그리고 이 문제들은 종종 상위 설계 자체를 변경해야만 해결될 수 있죠.
설계를 코딩 전에 ‘완성’한다는 것은 불가능해요.
• • •
왜 이게 중요한가: 방법론의 문제
이 관점은 소프트웨어 개발 방법론에 대한 근본적인 비판으로 이어져요.
워터폴(Waterfall) 방법론은 요구사항 분석 → 설계 → 구현 → 테스트 → 유지보수라는 순차적 단계를 가정해요. 각 단계를 완료하고 나면 다음 단계로 넘어가고, 이전 단계로 돌아가는 건 비용이 많이 든다고 봐요.
하지만 소스 코드가 설계라면, 이 가정 자체가 틀렸어요. ‘설계’와 ‘구현’을 분리하는 건 허구예요. 프로그래머가 코드를 작성할 때, 그건 ‘구현’이 아니라 ‘설계’를 하고 있는 거예요.
“모든 것이 설계 작업이다 — 코딩, 테스트, 디버깅, 아키텍처 계획 모두 서로 연결되어 있다. 이 단계들을 인위적으로 분리하려는 시도는 더 나은 소프트웨어 개발을 방해할 뿐이다.”
돌이켜 보면, 이 통찰은 훗날 등장한 애자일(Agile) 방법론의 이론적 근거가 된 셈이에요. 반복적 개발, 지속적 통합, 테스트 주도 개발 같은 실천들은 모두 ‘코드가 곧 설계’라는 현실을 받아들인 접근법이죠.
• • •
C++의 등장과 설계 언어
저자가 이 글을 쓴 1992년은 C++가 급부상하던 시기였어요. Reeves는 C++의 인기를 이 관점에서 설명해요.
C++가 인기를 얻은 이유는 고수준의 설계 개념을 표현하면서도 실행 가능한 코드로 남아있기 때문이에요. 클래스, 상속, 다형성 같은 객체지향 개념들은 설계 수준의 추상화를 제공해요. 동시에 이것들은 컴파일러가 직접 처리할 수 있는 실제 코드이기도 하죠.
다시 말해, C++는 ‘상위 설계’와 ‘상세 설계’를 하나의 매체에서 표현할 수 있게 해줬어요. 별도의 설계 문서 없이도 코드 자체가 설계를 담을 수 있게 된 거죠. (오늘날 TypeScript, Rust, Kotlin 같은 현대 언어들이 추구하는 것도 본질적으로 같은 방향이에요.)
• • •
실천적 함의
이 관점을 받아들이면, 소프트웨어 개발 방식에 대한 몇 가지 실천적 결론이 도출됩니다:
- 코딩을 설계 활동으로 인정하라 — 프로그래머는 단순한 ‘타자수’가 아니라 설계자예요. 그들에게 설계 결정권을 주어야 해요.
- 테스트를 설계 검증으로 보라 — 테스트는 ‘완성 후 확인’이 아니라 ‘설계 중 확인’이에요. 더 일찍, 더 자주 테스트해야 해요.
- 표현력 있는 언어를 사용하라 — 언어가 더 높은 수준의 추상화를 지원할수록, 설계 의도를 코드에 더 잘 담을 수 있어요.
- 반복적 개선을 받아들여라 — 설계는 한 번에 완성되지 않아요. 빌드-테스트-수정의 사이클을 통해 점진적으로 다듬어져야 해요.
- 코드 외부의 문서는 보조 도구일 뿐 — UML 다이어그램이나 아키텍처 문서는 유용하지만, 진짜 설계는 코드에 있어요. 문서가 코드와 동기화되지 않으면 문서가 틀린 거예요.
• • •
마치며
Jack Reeves의 이 에세이는 1992년에 쓰였지만, 그 통찰은 30년 이상이 지난 오늘날에도 유효해요. 아니, 어쩌면 더 중요해졌는지도 몰라요.
여전히 많은 조직들이 ‘설계 문서를 먼저 완성하고 구현은 나중에’라는 환상을 좇고 있어요. ‘시니어가 설계하고 주니어가 구현한다’는 분업도 이 관점에서는 의문이에요. 코딩이 곧 설계라면, 코드를 작성하는 사람이 설계 결정을 내리는 사람이니까요.
소프트웨어에서 설계와 구현의 구분은 허구예요.
이 사실을 받아들이면, 우리는 더 현실적인 기대를 갖게 되고, 더 효과적인 방법론을 채택하게 되며, 궁극적으로 더 나은 소프트웨어를 만들 수 있어요.
저자 소개: Jack W. Reeves는 소프트웨어 엔지니어로, 이 에세이는 원래 1992년 가을 C++ Journal에 기고되었습니다. 이후 2005년 developer.* magazine에 재게재되며 널리 알려졌습니다.
참고: 이 글은 소프트웨어 공학의 고전으로, 후대의 애자일 방법론과 지속적 개발(Continuous Development) 접근법에 이론적 토대를 제공했습니다.
원문: What Is Software Design? - Jack W. Reeves, C++ Journal (1992년 가을)
생성: Claude (Anthropic)