✨ WIL은 왜 쓰는 걸까?
매주 배운 걸 기록하거나, 돌아보지 않으면 금방 잊히곤 합니다.
그래서 루프팩에서는 기술적인 개념 + 내가 느낀 점을 글로 정리해보는 습관을 만들어 갈 거예요.
그냥 단순히 회고가 아니라, 아래와 같이 학습하고, 체화한 흐름을 나만의 언어로 써보는 게 핵심이에요.
📌 무엇을 중점적으로 학습했는지
📌 어떤 것이 특히 헷갈렸는지
📌 결국 어떻게 이해하게 됐는지
이번 주에 새로 배운 것 + 이런 고민이 있었어요
1. 소프트웨어 설계 문서 작성
이번 주 과제는 이커머스 프로젝트의 설계 문서 4종을 작성하는 것이었다.
파일명 내용
| 01-requirements.md | 유저 시나리오 기반 기능 정의, 요구사항 명세 |
| 02-sequence-diagrams.md | 시퀀스 다이어그램 최소 2개 이상 (Mermaid 기반 작성 권장) |
| 03-class-diagram.md | 도메인 객체 설계 (클래스 다이어그램 or 설명 중심) |
| 04-erd.md | 전체 테이블 구조 및 관계 정리 (ERD Mermaid 작성 가능) |
| 01 | 02 | 03 | 04 |
| 요구사항 명세 | 시퀀스 다이어그램 | 클래스 다이어그램 | ERD |
부끄럽지만 현재 회사에서는 설계 문서 없이 바로 개발에 들어가는 경우가 많았어서 경험이 많이 없었다.
설계 문서를 작서하는 과정은 요구사항 분석부터 ERD까지, 코드를 작성하기 전에 "무엇을 왜 만드는가"를 정리하는 과정이었다.
2. 정책 결정이 설계를 좌우한다
요구사항 문서에는 적혀있지 않지만, 개발하려면 반드시 결정해야 하는 것들이 있었다.
▸ 삭제 정책 - Soft Delete vs Hard Delete
| 도메인 | 결정 | 이유 |
| 좋아요 | Soft Delete | 이력 추적, 재등록 시 복원 |
| 브랜드/상품 | Soft Delete | 주문 스냅샷 참조, 복구 가능 |
| 주문 | 삭제 불가 | 기록 보존 필수 |
▸ 멱등성 - 중복 요청 처리
좋아요를 이미 누른 상태에서 다시 누르면? 에러를 반환할지, 그냥 200 OK를 반환할지 결정이 필요했다.
클라이언트 입장에서 "좋아요 상태가 되어있으면 OK"이므로 멱등성 보장(200 OK)으로 결정했다. 취소도 마찬가지로, 이미 취소된 상태면 에러 없이 200 OK를 반환한다.
▸ 부분 주문 - 재고 부족 처리
5개 상품을 주문했는데 2개만 재고가 있으면? 전체 실패 vs 부분 주문 중 부분 주문 허용을 선택했다. 응답에 주문된 상품과 제외된 상품 목록을 함께 포함하기로 했다.
이런 정책 결정들이 이후 시퀀스 다이어그램, 클래스 설계, ERD에 직접적으로 영향을 미치는 걸 체감했다.
3. 시퀀스 다이어그램으로 트랜잭션 경계 잡기
Mermaid로 시퀀스 다이어그램을 작성하면서 "언제 락을 잡고, 언제 풀 것인가"가 가장 핵심적인 질문이라는 걸 알게 됐다.
▸ 주문 생성 흐름
SELECT FOR UPDATE → 재고 확인/분류 → 재고 차감 → 쿠폰 검증 → 주문 생성 → 쿠폰 사용 처리
이 모든 과정을 하나의 트랜잭션으로 묶으면 정합성은 보장되지만, 락 보유 시간이 길어진다는 트레이드오프가 있었다. 현재 규모에서는 단일 트랜잭션이 적합하지만, 트래픽이 늘면 쿠폰 검증을 트랜잭션 밖으로 빼는 방안도 고려해야 한다.
▸ 브랜드 삭제 시 연쇄 처리
브랜드를 삭제하면 해당 브랜드의 상품들도 함께 Soft Delete 되어야 한다. 상품 먼저 삭제 → 브랜드 삭제 순서로 하나의 트랜잭션 안에서 처리하도록 설계했다.
4. 클래스 다이어그램과 레이어 아키텍처
1주차에 학습한 레이어 구조를 이번에 직접 설계에 적용했다.
| Controller | Facade | Service | Repository |
| 요청/응답, DTO | 도메인 간 조합 | 단일 도메인 로직 | 영속성 처리 |
▸ Facade의 역할이 명확해졌다
Service는 자기 도메인만 알면 되고, 여러 도메인을 조합하는 건 Facade의 책임이다. 예를 들어 OrderFacade가 ProductService, CouponService, OrderService를 조합하는 구조다.
▸ Entity에 비즈니스 로직 넣기
Product.decreaseStock(), Like.restore() 같은 메서드로 불변식을 Entity 내부에서 보장하는 방식이 인상 깊었다. 회사에서는 서비스 레이어에 모든 로직을 넣고 있었는데, 확실히 Entity에 행위가 있으니 응집도가 높다고 느꼈다.
5. ERD와 인덱스 설계
▸ FK 제약 없이 애플리케이션 검증
ERD 작성 시 FK 제약 없이 애플리케이션에서 검증하는 방식을 선택했다. Soft Delete와의 호환성, 운영 유연성을 위한 결정이다.
▸ 인덱스는 쿼리 기반으로
"이 쿼리가 실제로 실행될 때 어떤 인덱스를 타는가?"를 고민했다.
| 인덱스 | 대상 쿼리 | 목적 |
| uk_likes_user_product | 좋아요 중복 확인 | 동시 요청 방어 |
| idx_orders_created_at | 기간별 주문 조회 | 범위 검색 최적화 |
| idx_products_brand_id | 브랜드별 상품 조회 | 연쇄 삭제에도 활용 |
앞으로 실무에 써먹을 수 있을 것 같은 포인트
1. 코드 전에 정책부터 결정하기. Soft Delete인지 Hard Delete인지, 멱등성을 보장할 건지 말 건지 - 이런 정책을 먼저 정리하면 구현할 때 흔들림이 없다. 이번 주 경험으로 "정책 결정 → 설계 → 구현" 순서의 가치를 확실히 느꼈다.
2. 복잡한 로직은 시퀀스 다이어그램으로 먼저 검증하기. 코드로 바로 들어가기 전에 한 번 그려보면 트랜잭션 경계, 에러 분기가 눈에 보이기 때문에 설계 실수를 사전에 잡을 수 있다.
아쉬웠던 점 & 다음 주에 해보고 싶은 것
API 규격을 제대로 읽지 않아서 문서를 처음부터 다시 작성한 게 가장 아쉽다. 요구사항을 꼼꼼히 읽고 시작하는 습관이 필요하다.
또 쿠폰 도메인을 추가로 설계했는데, 원래 요구사항 범위를 넘어서는 건지 판단이 필요한 부분이었다. 범위 관리(scope management)에 대한 감각을 키워야겠다고 느꼈다.
다음 주는 이번에 작성한 설계 문서를 기반으로 실제 코드 구현에 들어간다. 1주차의 TDD + 2주차의 설계를 합쳐서, 설계대로 동작하는 코드를 만들어보는 게 목표다.
'Project' 카테고리의 다른 글
| [루프백] 1주차 WIL(What I Learned) (0) | 2026.02.08 |
|---|