앞에서 설명한 것들을 예제로 보면서 이해하는 것이 목표
이번 예제는 순수한 자바코드(스프링X)를 이용해서 개발해보기!
특정 요구사항이 변경되었을 때, SOLID를 잘 지키면서 변경이 될까? OCP / DI반영이 어떻게 잘 이루어지나
를 몸소 느껴보기
- 프로젝트 생성
- 비즈니스 요구사항과 설계
- 회원 도메인 설계
- 회원 도메인 개발
- 회원 도메인 실행과 테스트
- 주문과 할인 도메인 설계
- 주문과 할인 도메인 개발
- 주문과 할인 도메인 실행과 테스트
설계부분만 따로 먼저 정리
프로젝트 생성
마찬가지로 여기를 이용해서 프로젝트 생성
이 때, Dependencies는 선택하지 않는다.
프로젝트를 켜고 보면, starter와 테스트관련만 있는 것을 볼 수 있다.
Preference > gradle > Build and run, Run tests using
gradle에서 IntelliJ로 변경
나중에 스프링으로 변경할 것이기 때문에, 스프링으로 스타트만 하고 사용하지는 않을 것
비즈니스 요구사항과 설계
의뢰인(?)에게서 이런 요구사항을 받았다고 생각하기
즉, 2가지로 나눠볼 수 있다 (회원/주문과 할인)
회원
- 회원을 가입하고 조회할 수 있다.
- 회원은 일반과 VIP 두 가지 등급이 있다.
- 회원 데이터는 자체 DB를 구축할 수 있고, 외부 시스템과 연동할 수 있다. (미확정) → 여러가능성 외주가능, 자체 db 등등
주문과 할인 정책
- 회원은 상품을 주문할 수 있다.
- 회원 등급에 따라 할인 정책을 적용할 수 있다.
- 할인 정책은 모든 VIP는 1000원을 할인해주는 고정 금액 할인을 적용해달라. (나중에 변경 될 수 있다.)
- 할인 정책은 변경 가능성이 높다. 회사의 기본 할인 정책을 아직 정하지 못했고, 오픈 직전까지 고민을 미루고 싶다. 최악의 경우 할인을 적용하지 않을 수 도 있다. (미확정)
요구사항을 보면 회원 데이터, 할인 정책 같은 부분은 지금 결정하기 어려운 부분이다. 그렇다고 이런 정책이 결정될 때 까지 개발을 무기한 기다릴 수 도 없다. 우리는 앞에서 배운 객체 지향 설계 방법이 있지 않은가!
인터페이스를 만들고 구현체를 언제든지 갈아끼울 수 있도록 설계하면 된다. 그럼 시작해보자.
> 참고: 프로젝트 환경설정을 편리하게 하려고 스프링 부트를 사용한 것이다. 지금은 스프링 없는 순수한 자바로만 개발을 진행한다는 점을 꼭 기억하자! 스프링 관련은 한참 뒤에 등장한다.
여기는 요구사항이라서 김영한님 내용을 그대로 가져왔다
웹 애플리케이션의 계층관계
서비스, 레포지토리(저장소), 도메인이 무엇인지 정리하고 넘어가자
회원 도메인 설계
이제 개발자 입장에서 구조를 생각해보자
회원 도메인 협력 관계 (기획자도 알아볼 수 있는 용도)
일단 요구사항을 토대로, 회원(클라이언트)는 가입 / 회원 조회 서비스를 사용할 수 있어야 한다.
데이터를 어디에 어떻게 저장해 둘 지에 대해서는 정해진 바가 없기 때문에 "인터페이스"를 사용해서 역할만을 지정해 둔다.
메모리 회원 저장소(구현체1) : 매우 간단한 자바 코드로 구성된 메모리 저장소로, 휘발성 저장소이며, 구현이 매우 간단하고 가벼워 테스트와 임시로 많이 활용된다.
그 외, DB(구현체2)나 외부 시스템 연동(구현체2)은 가능성이 있으므로 열어둔다. (인터페이스의 강점!)
위에 이해를 기반으로 회원 클래스에 대한 다이어그램을 구성해보자
회원 클래스 다이어그램 (개발자가 인터페이스/구현체를 고려해서 구성한 것)
MemberService 또한, 인터페이스로 역할을 구현해두고, 구현체(Implement)를 만든다.
회원 저장소에 대해서도 다음과 같이 인터페이스와 구현체로 구성한다.
이는 실제 서버를 실행하지 않고, 클래스만 분석해서 볼 수 있도록 한눈에 보여주는 그림이다.
특정 역할(인터페이스)에 대해 어떤 구현체를 적용할지는 동적으로 서버가 실행될 때 결정되는 사항들이다. → 이는 클래스 다이어그램만으로 판단하기 어렵다 (객체 다이어그램의 필요성)
회원 객체 다이어그램
실제 개발 협력관계를 고려해야한다. 즉, 단순 클래스가 아니라 객체가 되었을 때, ( 해당 역할(인터페이스)에 어떤 구현체가 실제로 선택되어서 서버에 올라가 돌아가는가 까지 고려한 것)
실제 서버에 올라오면 객체 간의 메모리 참조를 고려해야한다.
객체가 특정 메소드를 실행했을 때, 해당 메소드가 실행시 의존(다른 객체를 참조해야만 실행가능한 것들)관계를 고려해야한다.
클라이언트가 요구하는 것은 회원 서비스를 의존하며, 회원서비스는 회원 저장소에 저장된 데이터를 참고해서 진행되므로, 의존관계는 다음과 같다.
주문과 할인 도메인 설계
주문과 할인 요구사항은 다음과 같다.
주문과 할인
- 회원은 상품을 주문할 수 있다.
- 회원 등급에 따라 할인 정책을 적용할 수 있다.
- 할인 정책은 모든 VIP는 1000원을 할인해주는 고정 금액 할인을 적용해달라. (나중에 변경 될 수 있다.)
- 할인 정책은 변경 가능성이 높다. 회사의 기본 할인 정책을 아직 정하지 못했고, 오픈 직전까지 고민을 미루고 싶다. 최악의 경우 할인을 적용하지 않을 수 도 있다. (미확정)
역할만을 이용해 정리한 그림
주문 생성 : 클라이언트가 (주문에 필요한 정보를 가지고 - 회원id, 상품명, 상품가격 ) 주문을 한다
- 이 부분은 원래 회원처럼 상품 객체들을 만들어야 하지만, 간단하게 하기위해서 그렇게 하지 않아서 상품id가 없으므로, 그냥 상품에 대한 정보를 직접 넘긴다
회원 조회 : 회원 id를 이용해서, 회원조회(회원 저장소 필요) 하여, 회원 등급을 알아낸다( 등급에 따라 할인정책이 다르기 떄문)
할인 적용 : 회원의 등급을 가지고, 어떤 할인 정책에 적용될 수 있는지(할인 정책 필요) 알아낸다
주문 결과 반환 : 주문 결과(할인 결과 포함)를 클라이언트에 반환한다.
- 이 또한, 주문 결과를 따로 db에 저장하는 것이 원칙이지만, 간단하게 하기 위하여 생략한다. 단순히 주문 결과 객체를 반환하기로
역할과 구현체 까지 고려한 전체 그림 (기획자도 이해할 수 있도록)
역할과 구현을 분리한다!
회원 저장소 계획을 떠올린다.
*정액 할인 정책 : 가격에 상관없이 특정 금액을 할인해 주는 정책 (현재 요구사항)
* 정률 할인 정책 : 가격에 비례하여 특정 %만큼 할인해 주는 정책
역할과 구현을 분리하면, 다음과 같이 여러가지 방법에 따른 할인 방법을 구현해두고, 갈아끼우기만 하면 유연하게 변경이 가능하다.
특히, 할인정책은 아직 요구사항이 완전하지 않으므로 필수적이다
주문 도메인 클래스 다이어그램 (좀더 개발에 집중된 그림)
주문 도메인 객체 다이어그램
이는 동적인 관계를 나타낸 것으로, 어떤 구현체를 사용하느냐에 따라 동적으로 변경된다.
런타임에 결정되기 때문에 동적이다.
협력 관계를 그대로 재사용 할 수 있다는 것은
주문 서비스 구현체가 회원 저장소 역할과 할인 정책 역할을 의존하는데,
회원 저장소 역할이 Memory 구현체이든 DB구현체로 변경되든 주문 서비스 구현체는 영향을 전혀 받지 않고, 계속 의존관계를 유지할 수 있다는 의미
(마찬가지로, 할인 정책 역할 또한 정률할인 구현체를 사용하든, 정액 할인 구현체를 사용하든, 계속 의존관게를 유지 가능하다)
'Backend > Spring' 카테고리의 다른 글
[Spring] 순수 자바 예제 3) - 주문/할인 도메인 개발&테스트 (0) | 2021.09.22 |
---|---|
[Spring] 순수 자바 예제 2) - 회원 도메인 개발&테스트 (0) | 2021.09.22 |
[Spring] 최종 개념 정리 (0) | 2021.09.19 |
[Spring] 객체 지향 설계 원칙 - SOLID (0) | 2021.09.19 |
[Spring] 객체 지향 프로그래밍 (0) | 2021.09.18 |