이번 주 루퍼스를 하며 가장 크게 느낀 건 이거였다.
요구사항 정의서 없이 만드는 개발은 결국 돌고 돌아 제자리로 돌아온다.
지금까지는 대부분 기획이 완료된 상태에서 기능만 구현해왔다.
기획자가 기능 흐름을 정리해주면, 나는 필요한 객체를 떠올리고, DB 구조를 짠 다음 곧장 코딩에 들어갔다.
그게 익숙했고, 딱히 문제라고 느끼지도 않았다.
그런데 이번 과제는 달랐다.
기획서 없이, 요구사항 정의부터 전부 직접 해야 하는 과제였다.
🧱 전형적인 커머스니까 쉬울 줄 알았다
주제는 커머스 서비스.
로그인, 상품, 장바구니, 주문, 결제, 포인트 충전 등 익숙한 기능들이라
처음엔 “쉬운 과제겠지” 싶었다. 그래서 초반엔 가볍게 접근했다.
“로그인한 사용자만 접근 가능”, “재고 초과 시 주문 불가”, “없는 상품이면 에러” 같은
기본 요구사항은 금방 정리됐다.
그런데 진짜 어려움은 실패 케이스를 정의하면서 시작됐다.
- 상품이 판매 중이 아니면 어떤 에러를 줘야 하지?
- 비로그인 사용자는 어떤 상태 코드로 막아야 하지?
- 장바구니 저장이 실패할 수도 있을까?
이런 질문이 하나둘 쌓이기 시작했고, 흐름을 단순하게 쪼개기 어려워졌다.
실패 조건을 어디까지 유효성으로 보고, 어디서부터 비즈니스 제약으로 볼지를 고민하면서
처음으로 설계에 진지하게 들어가기 시작했다.
🔍 실패 케이스를 정리하다 보니 설계가 보이기 시작했다
실패 케이스를 정의하다 보니 자연스럽게 이런 질문으로 이어졌다.
- 이건 어느 계층에서 처리해야 하지?
- 어떤 객체가 책임을 가져야 하지?
- 이 흐름은 시퀀스로 끊을 수 있을까?
이때 처음으로,
요구사항을 글로 정리하는 과정 자체가 설계를 이끈다
는 걸 실감했다.
요구사항을 문장으로 풀다 보면 흐름이 드러나고,
그걸 시퀀스 다이어그램으로 정리하면 객체 간의 책임이 명확해졌다.
🎯 고민 1. 할인 설계는 왜 이렇게 어려운가?
처음엔 할인 기능을 단순한 부가 기능으로 생각했다.
“할인도 넣어볼까?” 하는 마음으로 시작했는데, 금방 복잡해졌다.
- 회원등급 기반 할인
- 특정 카테고리 할인
- 퍼센트 vs 고정 금액
- 쿠폰 중복 여부
- 적용 시점과 우선순위…
이걸 하나의 Discount 객체에 다 넣으려니
조건 분기와 상태 변화가 얽히기 시작했고, 유지하기 어려운 구조가 됐다.
그래서 구조를 완전히 바꿨다.
- DiscountPolicy: 할인 조건과 정책 (DB 저장용)
- Discount: 실제 적용된 결과 (도메인 내 전용)
정책은 바뀔 수 있는 외부 요인이고,
결과는 특정 시점에 확정된 값이라는 기준으로 분리했다.
이 과정을 통해
정책과 결과의 책임 분리가 왜 중요한지 처음으로 실감했다.
💰 고민 2. 금액 VO – 진짜 캡슐화인가, 그냥 껍데기인가?
두 번째 고민은 금액 처리 구조였다.
처음에는 포인트 도메인엔 Balance, 주문 도메인엔 OrderAmount라는
각각의 VO를 만들었고, 내부엔 BigDecimal이 들어 있었다.
이 VO들엔 add, subtract, isEnough 같은 연산 메서드가 정의돼 있었다.
그런데 구현을 하다 보니 두 객체가 너무 비슷했다.
“이거 그냥 중복 아냐?”라는 생각이 들기 시작했다.
그래서 구조를 리팩토링했다.
- Money라는 공통 VO를 만들고
- 각 도메인에선 Money balance, Money orderAmount처럼 의미를 변수명으로 구분
이렇게 하니 중복된 로직이 제거됐고,
“금액”이라는 의미도 코드에서 훨씬 명확하게 드러났다.
그런데 다시 고민이 생겼다.
“그럼 굳이 VO로 감싸야 할까?”
“BigDecimal을 변수명만 다르게 써도 되지 않나?”
“이거 그냥 껍데기 하나 더 씌운 건 아닐까?”
이건 결국 추상화가 진짜 의미가 있는지,
아니면 단순한 구조적 겹침에 불과한지에 대한 고민이었다.
결국 내가 유지하기로 한 이유는 다음 두 가지였다:
- 금액 연산 로직을 공통으로 관리할 수 있다는 점
- 도메인 코드에서 금액 개념이 의도적으로 드러난다는 점
아직 이 구조가 실제 구현에서 얼마나 유용할지는 더 지켜봐야 한다.
하지만 의도를 명확히 표현한 구조라는 점에서 의미가 있다고 판단했다.
🧠 설계는 결국 글쓰기에서 시작된다
이번 과제를 하면서 가장 크게 느낀 건,
요구사항을 제대로 쓰면, 설계는 따라온다.
말로 설명하면 별 문제 없어 보이던 흐름도
글로 정리하면 빠진 조건, 애매한 책임, 꼬인 구조가 그대로 드러난다.
그리고 그걸 정리하기 위해 흐름도를 그리고,
시퀀스를 그리게 되고,
도메인을 나누게 되고,
결국 코드가 그 구조를 따르게 된다.
🚀 앞으로
나는 아직 설계를 잘한다고 할 순 없다.
책임 분리도 어렵고, 문서화도 서툴고, 항상 의문도 많다.
하지만 이번 루퍼스를 통해
설계란 결국 요구사항을 얼마나 명확히 정의할 수 있느냐의 문제라는 걸 알게 됐다.
요구사항을 정리하고
→ 흐름을 시각화하고
→ 책임을 분리하고
→ 코드를 구조화하는 일련의 과정.
이게 바로 내가 놓치고 있던 설계 근육이었다.
이걸 매주 반복하다 보면
나도 결국 “기능 구현만 하는 개발자”가 아니라
“설계할 줄 아는 개발자”가 될 수 있을 거란 확신이 생겼다.
'Loopers' 카테고리의 다른 글
동시성 제어, 도메인 분리를 삼킨 괴물 (4) | 2025.08.08 |
---|---|
설계는 정답이 없다고 했지만, 그래도 너무 어렵잖아 (3) | 2025.08.01 |
Loopers WIL – 2주차 (0) | 2025.07.24 |
WIL – 1주차 (TDD & 테스트 가능한 구조) (2) | 2025.07.17 |
TDD, 꼭 해야 해? (1) | 2025.07.17 |