기능 중심 설계는 변화에 취약하다.
기능은 자주 바뀐다.
회사 정책, 마케팅 전략, 외부 도구 등장 등 이유는 다양하다.
기능 중심으로 구조를 짜면, 변화에 약해진다.
기능 중심 설계는 절차 흐름을 코드에 직접 녹인다.
하나가 바뀌면 연쇄적으로 다른 부분도 수정해야 한다.
비즈니스 규칙은 여기저기 흩어지고, 재사용성이나 확장성도 떨어진다.
예시: 기능 중심 설계의 흐름
초기 요구사항:
"사용자가 버튼을 누르면 쿠폰을 발급하고, 그걸 문자로 보낸다."
if (user.clickedButton) {
const coupon = createCoupon(user.id);
sendSms(user.phone, coupon.code);
logIssuedCoupon(user.id, coupon.code);
}
문제 없음. 간단하고 잘 동작함.
기능 변경 1: VIP만 쿠폰, 일반은 포인트
정책 변경 → 조건문 추가 → 분기 복잡도 상승
if (user.clickedButton) {
if (user.isVip) {
const coupon = createCoupon(user.id);
sendSms(user.phone, coupon.code);
logIssuedCoupon(user.id, coupon.code);
} else {
givePoints(user.id, 1000);
sendSms(user.phone, "1000포인트가 지급되었습니다");
}
}
기능 변경 2: 문자 → 카카오톡, 쿠폰 유효기간 사용자별 적용
조건 분기, 메시지 방식, 쿠폰 정책 등 점점 섞임
→ 코드 복잡도 증가
→ 테스트 어려워짐
→ 유지보수 어려움
따라서 이러한 문제를 피하기 위해서는, 상대적으로 안정적인 것을 중심으로 구조를 짜는 것이 바람직하다.
그중 하나가 바로 도메인 모델이다.
구조적 해결책: 도메인 모델
도메인 모델은 사용자가 프로그램을 사용하는 대상 영역에 관한 지식을 선택적으로 단순화하고, 의식적으로 구조화한 형태를 말한다.
도메인: 소프트웨어가 다루는 현실 세계의 영역
모델: 현실을 단순화·구조화한 것
예:
- 금융 도메인 모델 → 계좌, 이체, 거래, ...
- 게임 도메인 모델 → 캐릭터, 몬스터, 아이템, ...
- 헬스장 도메인 모델 → 회원, 이용권, 환불규정, ...
도메인 모델이 안정적인 이유
도메인 모델은 비즈니스의 ‘본질’을 표현한다.
UI나 정책처럼 자주 바뀌지 않는다.
예:
병원에선 ‘환자’, ‘의사’, ‘진료’ 같은 개념이 오랫동안 유지됨
은행의 ‘계좌’, ‘이체’, ‘잔액’도 마찬가지
→ 구조가 고정되므로 정책이 바뀌어도 내부 객체 구성은 유지 가능
추가적으로, 도메인의 개념과 관계가 코드 속에 반영되어 있기에, 도메인을 이해하고 있는 다른 사람들이 해당 코드를 보더라도 빠르게 파악하기에도 좋다
도메인 모델 설계 간단 예시
핵심 모델 분리
- User: 이벤트에 참여
- RewardPolicy: 보상 판단
- NotificationService: 보상 전달
변화 대응
- VIP만 쿠폰, 일반은 포인트 → RewardPolicy 인터페이스를 채택한 두가지 객체[쿠폰, 포인트] 생성
- 문자 → 카카오톡 → NotificationService 인터페이스를 채택한 객체[카카오톡] 생성
- 사용자별 쿠폰 유효기간→ Reward 내부 로직 확장
→ 핵심 흐름은 그대로. 정책만 바꾸면 됨
도메인 모델의 세 가지 측면 (도널드 노먼의 이론 기반)
구분 | 의미 |
사용자 모델 | 사용자가 제품(도메인)을 어떻게 이해하고 있는지 |
디자인 모델 | 설계자가 제품(도메인)을 어떻게 설계했는지 |
시스템 이미지 | 사용자가 실제로 보고 조작하는 시스템의 모습 |
- 세 모델이 일치할수록 좋은 소프트웨어
- 설계자는 디자인 모델을 기반으로 만든 시스템 이미지가 사용자 모델을 정확하게 반영하도록 노력해야 한다.
기능도 결국 중요하다
시스템이 존재하는 이유는 기능을 제공하기 위해서다.
도메인 모델이 구조의 안정성과 표현력을 책임진다면,
기능은 사용자와 시스템 사이의 인터랙션을 주도한다.
기능 요구사항을 잘 정의하려면, 단순히 “무엇을 한다”가 아니라
누가(사용자) 어떤 목표를 가지고 시스템과 어떻게 상호작용하는지를 봐야 한다.
이런 흐름을 텍스트로 정리한 것이 바로 *유스케이스(Use Case)*다.
유스케이스의 가치
유스케이스는 사용자 목표를 중심으로
시스템의 기능 요구사항을 이야기처럼 풀어낸다.
각각 흩어져 있는 기능들을,
“왜 이 기능이 필요한가?”, “무슨 목표를 이루기 위한 흐름인가?”라는 관점에서
문맥 속에 묶어주는 역할을 한다.
유스케이스 예제
헬스장 이용권 환불 금액 계산 유스케이스
헬스장 도메인에서, 시스템은 회원이 이용권을 중도 해지할 경우 환불 받을 수 있는 금액을 계산해주는 기능을 제공해야 한다.
아래 예시는 환불 금액 계산과 관련된 사용자의 목표를 만족시킬 수 있는 간단한 유스케이스의 예다.
유스케이스명: 중도 해지 환불 금액을 계산한다
일차 액터: 헬스장 회원
주요 성공 시나리오:
1. 회원이 자신이 구매한 헬스장 이용권을 선택한다.
2. 시스템은 선택한 이용권의 상세 정보를 보여준다.
3. 회원은 오늘 기준으로 이용권을 해지할 경우 환불받을 수 있는 금액 계산을 요청한다.
4. 시스템은 환불 규정에 따라 계산된 금액을 사용자에게 제공한다.
확장:
3a. 사용자는 특정 해지 일자를 직접 입력할 수 있다.
유스케이스의 5가지 핵심 특성
- 유스케이스는 텍스트다.
- UML 다이어그램이 아니라, 글로 서술하는 상호작용 흐름
- 유스케이스는 단일 시나리오가 아니다.
- “오늘 해지” vs “다음 달 해지”처럼 시나리오 묶음
- 기능 목록이 아니다.
- 독립된 기능이 아니라 사용자 목표를 달성하는 흐름
- UI 정보는 포함하지 않는다.
- 어떤 버튼을 누른다는 등의 UI 요소는 배제
- UI는 자주 바뀌므로 유스케이스는 기능 중심으로만 기술
- 내부 설계 정보를 포함하지 않는다.
- 클래스, 메서드, DB 설계 등은 배제
- 오직 사용자의 목표를 달성하기 위한 흐름만 포함
도메인 모델 + 유스케이스 + 책임 주도 설계 + 객체지향 흐름 정리
- 도메인 모델을 활용해 소프트웨어 객체 정의
시스템을 구성하는 주요 객체 개념을 정의한다.
(예: User, Coupon, NotificationService 등) - 시스템 객체를 거대한 자율 객체로 간주
사용자로부터 메시지를 받아 기능을 수행하는 책임을 가진 객체로 둔다.
이 객체가 유스케이스를 처리한다. - 시스템의 큰 책임을 더 작은 책임으로 분해
(예: 사용자 요청 수신 → 쿠폰 발급 → 보상 전송 등) - 각 책임을 수행할 객체를 선택
도메인 모델에서 해당 책임을 처리하기에 적절한 객체를 소프트웨어 객체로 선택한다.
(예: Coupon, NotificationService 등) - 객체 간 메시지 흐름 설계
선택된 객체들이 책임을 수행하도록 어떤 메시지[메세지이름, 인자]를 주고받을지 정의한다. - 객체 구현
클래스 구현 및 속성/메서드 정의를 통해 실제 동작 가능하게 만든다.
※ 본 글은 『객체지향의 사실과 오해』(조영호 저) 6장을 기반으로 학습 목적으로 요약한 글입니다.
※ 이 글은 책의 내용을 요약한 것으로, 원문 없이 읽을 경우 오해의 여지가 있을 수 있습니다. 정확한 이해를 위해 원서의 정독을 권장합니다.
'개발 관련 지식' 카테고리의 다른 글
Clean Architecture 정리 - 1부 소개 (0) | 2025.05.11 |
---|---|
객체지향의 사실과 오해 정리 - 7장. 역할, 책임, 협력 관점에서 본 객체지향 (0) | 2025.05.06 |
객체지향의 사실과 오해 정리 - 5장. 책임과 메세지 (0) | 2025.04.26 |
객체지향의 사실과 오해 정리 - 4장. 역할, 책임, 협력 (0) | 2025.04.23 |
객체지향의 사실과 오해 정리 - 3장. 타입과 추상화 (0) | 2025.04.21 |