순수 자바 프로젝트로 도메인 설계와 구현 - 2
1. 새로운 할인 정책 개발
악덕 기획자 : (서비스 오픈 직전) 정률 할인으로 변경하고 싶어요
순진 개발자 : 그래서 내가 말했었잖아....(이건 나쁜 소통의 예시이다..)
악덕 기획자 : 에자일 소프트웨어 개발 선언 몰라요?
https://agilemanifesto.org/iso/ko/manifesto.html
우리는 문제없다. DiscountPolicy의 구현체 RateDiscountPolicy만을 만들면 된다.
Service 쪽 코드는 전혀 건드리지 않아도 된다. 라는게 우리 생각이였다.
하지만 다시 잘 생각해보면 그건 착각이였음을 알게 된다. 우리가 지키지 않은 원칙이 하나 있다.
DIP 원칙을 지키지 않았다.
코드를 보면 추상체에게만 의존해야하는데 구현체에도 의존을 하고 있다!
그래서 DIP 원칙을 지키지 않아 OCP를 위반하게되었다.
FixDiscountPolicy를 바꾸는 순간 ServiceImpl을 바꿔야 하는 상황이 되어버린 것이다.
그러면 ServiceImpl이 Policy의 구현체에 의존하지 않도록 하려면 어떻게 해야 할까?
ServiceImpl에 구현체를 누군가가 생성하고 주입해주면 된다.
이렇게 하여 DIP가 완성되었다.
객체를 생성하고 연결하는 역할(AppConfig)와 실행하는 역할(MemberServiceImpl)이 명확히 분리되었다.
비지니스 로직만 작성하면 되는 것이다.
Service 구현체의 입장에서는 의존관계를 외부에서 주입해주는 것 같다고 해서 DI(Dependency Injection)(의존관계 주입)이라고 한다.
2. 관심사의 분리
애플리케이션을 하나의 공연이라고 생각해보자.
각각의 인터페이스를 배역(배우 역할)이라고 생각해보자.
인터페이스의 구현체는 레오나르도 디카프리오와 같은 배우라고 생각해보자.
로미오와 줄리엣 공연에서 레오나르도 디카프리오가 남자주인공이라고 하자.
이때, 여자주인공은 누가 정하면 될까? 감독이 정하면 될 것이다.
레오나르도 디카프리오가 여자주인공을 섭외해야되는 책임을 가졌을까?
그렇다면 프리오가 배우도 하고, 감독도 해야하는 것이다.
프리오는 너무 힘들어할 것이다. 현실에서는 보통 그렇게 하지 않는다. 배우는 자신의 배역에만 집중하면 된다.
섭외는 공연기획자가 하면 된다.
지금 우리의 코드 상황이 딱 그렇다. Service의 구현체가 Policy의 구현체를 직접 결정하고 있다!
이는 관심사의 분리가 제대로 되지 않은 것이다.
그러면 이제 프리오의 부담을 덜어주자. 공연 기획자가 섭외를 하는 방식으로 코드를 바꿔보자.
Service의 구현체는 의존관계에 대한 고민은 외부에 맡기고 실행에만 집중하면 된다.
3. AppConfig와 정률 할인정책 적용
구성 정보에서 역할과 구현을 명확하게 분리
공연기획자 AppConfig의 등장으로 SRP와 DIP와 OOP를 전부 만족
SRP : 단일책임원칙(Single Responsibility Principle)
한 클래스는 하나의 책임만 가져야 한다.
구현 객체를 생성하고 연결하는 책임은 AppConfig가 담당한다.
클라이언트 객체는 실행하는 책임만 담당한다.
DIP : 의존관계 역전 원칙
프로그래머는 추상화에 의존해야지, 구체화에 의존하면 안된다. 의존성 주입은 이 원칙을 따르는 방법 중 하나이다.
OCP (Open/Closed Principle)
소프트웨어 요소는 확장에는 열려 있으나 변경(수정)에는 닫혀 있어야 한다.
애플리케이션을 사용 영역과 구성 영역으로 나누었다.
소프트웨어 요소를 새롭게 확장해도 사용 영역에 대한 변경은 닫혀 있다.
추상화와 다형성을 이용하여, 새로운 기능을 추가할 때 기존 코드를 수정하지 않음을 가능하게 한다.
이런 구성을 동적인 객체 인스턴스 의존 관계라고 한다.
애플리케이션 실행 시점(런타임)에 외부에서 실제 구현 객체를 생성하고
클라이언트에 전달해서 클라이언트와 서버의 실제 의존관계가 연결 되는 것을 의존관계 주입이라 한다.
loC Container, DI Container
AppConfig 처럼 객체를 생성하고 관리하면서 의존관계를 연결해 주는 것을
IoC 컨테이너 또는 DI 컨테이너라 한다.
의존관계 주입에 초점을 맞추어 최근에는 주로 DI 컨테이너라 한다.
또는 어샘블러, 오브젝트 팩토리 등으로 불리기도 한다.
4. 제어의 역전 loC(Inversion of Control)
OrderServiceImpl은 AppConfig가 어떤 구현체를 생성해서 주입해주는 지 모르는 채 묵묵히 자신의 로직을 실행한다. 제어 흐름을 직접 제어하는 것이 아니라 외부에서 관리하는 것을 제어의 역전이라고 한다.
프레임워크 vs 라이브러리
프레임워크가 내가 작성한 코드를 제어하고, 대신 실행하면 그것은 프레임워크가 맞다. (JUnit)
반면에 내가 작성한 코드가 직접 제어의 흐름을 담당한다면 그것은 프레임워크가 아니라 라이브러리다.
실행하고 제어하는 건 Junit이 한다. 라이프 사이클 속에서 프레임워크가 적절한 타이밍에 호출해주는 것.
이걸 프레임 워크라고 한다.
반면에 내가 작성한 코드가 직접 제어의 흐름을 담당한다면 프레임 워크가 아니라 라이브러리이다.
6. 스프링 적용
좋은 단축키
테스트 코드 즉시 생성(ctrl shift T) : 함수에 커서를 올리고 ctrl shift T를 누르면 그 함수에 대한 테스트 코드를 즉시 생성할 수 있다.
on demand static import(ctrl enter) : ctrl enter 해서 테스트 할때 Assertions를 static import할 수 있다.
ctrl E
ctrl alt M 중복 제거
패키지 클릭하고 show Diagram
깃 환경 구축할 때 썼던 명령어들
(순서대로 아님 한 공간에 모아둔 것 뿐)
git rm -rf --cached . (모든 추적을 제거. 기존에 추적했던 것들만 제거. 스테이징 영역만을 제거. 워킹디렉토리는 유지)
git rm -rf --cached . 는 모든 추적을 처음부터 다시하려는 것임. gitignore 초기화 하기 위함. 그걸 하더라도 워킹디렉토리에는 전부 남아있고, 이전 커밋도 남아있기 때문에 파일이 100개가 있었어도 수정된게 없다면 git add . git commit했을 때 changed to be committed가 100개여도 실제 commit 결과는 파일체인지가 0개이다.
git reset 커밋해시 (HEAD를 지정된 커밋해시로 이동, 스테이징 영역을 HEAD 상태로 되돌림. 워킹 디렉토리는 유지됨)
git reset 커밋해시 --hard (+워킹디렉토리 또한 삭제)
git reset (git add . 했는데 그 명령 취소하고 싶으면 git reset 하면 된다)
git reset HEAD~1 (git commit . 했는데 그 명령 취소하고 싶으면 git reset HEAD~1 하면 된다)
git add . (스테이징 영역에 넣기)
git commit
git commit -a (애드와 커밋 동시에)
git log --oneline
git remote add origin https://github.com/Hyeonjun0527/KYHspring.git
git push origin main
git branch sec3.domainDevelop
git branch sec4.applyDIP
git branch -a (모든 브랜치 보기)
git push --all origin (모든 로컬 브랜치 푸시)
git push origin branch1 branch2 branch3(브랜치 3개 푸시)
'백엔드 > 김영한 스프링 기본편' 카테고리의 다른 글
김영한 스프링 핵심 원리 기본 편 복습 - 5 (0) | 2025.01.12 |
---|---|
김영한 스프링 핵심 원리 기본 편 복습 - 4 (1) | 2025.01.09 |
김영한 스프링 핵심 원리 기본 편 복습 - 1 (0) | 2024.12.30 |