소프트웨어는 분석-설계-구현-테스트를 한 번만 도는 것이 아니라 계속 되감기며 만들어진다
소프트웨어 개발 과정을 설명할 때 흔히 분석 → 설계 → 구현 → 테스트라는 순서를 말한다. 이 설명 자체는 틀리지 않다. 다만 현실에서 문제는, 많은 사람이 이 순서를 한 번만 쭉 가는 직선 공정으로 받아들인다는 데 있다.
실제 개발은 그보다 훨씬 반복적이다. 요구를 이해하고, 작은 설계를 만들고, 구현해 보고, 테스트와 피드백을 받은 뒤 다시 앞 단계로 돌아간다. 애자일 선언문이 “계획을 따르는 것보다 변화에 대응하는 것”을 더 중시한다고 밝힌 이유도 여기에 있다.
분석 단계에서 중요한 것은 “무엇을 만들지”만이 아니라 “무엇을 아직 만들지 않을지”다
분석은 아이디어를 길게 쓰는 단계가 아니다. 더 실용적인 질문은 이쪽에 가깝다.
- 누가 이 기능을 왜 쓰는가
- 지금 꼭 필요한 시나리오는 무엇인가
- 이번 반복에서 제외할 것은 무엇인가
처음부터 모든 요구를 받아 적으면 대부분 스코프가 커진다. 그래서 분석의 실력은 추가보다 제외에서 더 잘 드러난다.
설계는 완벽한 청사진보다 “다음 한 조각을 구현할 수 있는 구조”면 충분하다
설계 단계도 자주 오해된다. 모든 것을 미리 확정해야 한다고 생각하면 설계 문서만 커지고 실제 검증은 늦어진다. 현실적인 설계는 오히려 작아야 한다.
- 데이터가 어디를 통과하는가
- 책임은 어느 모듈에 둘 것인가
- 무엇을 먼저 얇게 구현해 검증할 것인가
즉 설계의 목적은 미래를 전부 맞히는 것이 아니라, 다음 구현 단계를 덜 위험하게 만드는 것이다.
구현은 “코드를 쓰는 단계”이면서 동시에 분석과 설계를 검증하는 단계다
구현을 시작하면 많은 가정이 깨진다. 처음에는 간단해 보이던 요구가 실제 코드에서는 복잡하게 드러나기도 하고, 반대로 필요할 줄 알았던 추상화가 전혀 필요 없다는 사실이 드러나기도 한다.
그래서 구현은 설계의 하위 단계가 아니라 검증 단계이기도 하다. Martin Fowler가 정리한 YAGNI, 즉 지금 필요하지 않은 것은 만들지 말라는 원칙도 이 지점을 겨냥한다. 너무 이른 일반화는 구현보다 상상을 앞세우게 만들기 쉽다.
테스트는 맨 마지막 검수보다 “되감기 장치”에 가깝다
테스트를 마지막 품질 검사처럼만 생각하면 개발이 느려진다. 더 현실적인 역할은 되감기 장치다.
- 구현한 기능이 정말 요구와 맞는가
- 설계가 과했거나 부족하지 않았는가
- 에지 케이스를 놓치지 않았는가
- 다음 변경이 들어와도 안전하게 고칠 수 있는가
즉 테스트를 하면 버그를 찾는 동시에, 분석과 설계 단계의 오해도 다시 발견하게 된다.
실제 흐름은 작은 반복으로 보는 편이 더 맞다
GitHub flow가 보여 주는 가벼운 브랜치-리뷰-병합 흐름도 결국 이 반복을 작게 유지하려는 접근이다. 큰 덩어리를 오래 붙잡지 않고, 작은 변경을 만들고, 검토하고, 반영하는 쪽이 피드백을 빠르게 돌리기 쉽다.
현실적인 개발 흐름은 보통 이런 식이다.
- 요구를 아주 작게 자른다.
- 그 조각에 필요한 최소 설계를 한다.
- 구현한다.
- 테스트와 리뷰를 통해 다시 되감는다.
- 다음 조각으로 넘어간다.
이 흐름을 이해하면 “왜 개발은 늘 앞 단계로 돌아가는가”가 이상하게 느껴지지 않는다. 원래 그렇게 만들어지는 것이기 때문이다.
핵심 정리
소프트웨어는 분석-설계-구현-테스트를 한 번 직선으로 통과해서 완성되는 제품이 아니다. 실제로는 작은 단위를 반복하며, 구현과 테스트를 통해 앞 단계의 가정을 계속 수정해 나가는 순환 구조에 가깝다.
그래서 좋은 개발 프로세스의 핵심도 거창하지 않다. 스코프를 작게 자르고, 지금 필요한 만큼만 설계하고, 구현과 테스트를 통해 계속 되감는 것. 그 반복이 쌓여 소프트웨어가 된다.