강의를 들으며 생각 정리
프로젝트 생성
스프링 부트 스타터 사이트로 이동해서 스프링 프로젝트를 생성한다.
- Project : 일반적으로 Gradle Project를 사용한다.
- Project Metadata
- Group : 그룹 이름
- Artifact : 프로젝트 이름
Spring Boot version, Java version 등은 현재 상황에 맞게 설정한다.
비즈니스 요구사항과 설계
강의에서는 회원 관리 정책과 주문과 할인 정책 두 가지 메커니즘을 사용했다.
만약 요구사항을 받았는데, 회원 데이터는 어떻게 관리할지, 할인 정책은 어떤식으로(정액, 정률) 선택할지 결정하기 어려운 상황일 때가 있다. 이 때 개발은 무기한 기다리는 것이 아닌 앞서 배운 객체 지향 설계 방법을 통해 개발을 진행할 수 있다. -> 쉽게 말해 역할 별로 인터페이스를 만들고 구현체를 언제든지 갈아 끼울 수 있도록 설계하면 된다.
도메인 설계
회원 도메인 요구사항이 다음과 같다고 가정한다.
- 회원을 가입하고 조회할 수 있다.
- 회원은 일반과 VIP 두 가지 등급이 있다.
- 회원 데이터는 자체 DB를 구축할 수 있고, 외부 시스템과 연동할 수 있다. (미확정)
첫 번째와 두 번째 요구사항은 해당 기능을 구현할 수 있는 메소드들을 추가함으로써 간단히 해결할 수 있다. 중요한 것은 세 번째 요구사항이다. 회원 저장소를 자체 DB를 구축할 것인지, 외부 시스템을 연동할 것인지 아직 확정 되지 않았기 때문에 회원 저장소 인터페이스에 각 저장소 구축 방법을 번갈아 끼울 수 있도록 개발을 하는 것이 좋다.
이제 본격적인 도메인 설계를 해본다.
도메인 협력 관계
개발자 뿐만 아니라 기획자들도 볼 수 있게 기능 별로 정리한 다이어그램이다. 중요한 점은 미확정인 회원 저장소에 대해 여러 저장소들을 갈아 끼울 수 있다는 부분이다. 이는 앞서 말했듯이 회원 저장소를 인터페이스로 만들어 여러 저장소(구현체)들이 이를 종속하게 하는 방법이 있다. 또한 회원 서비스처럼 구현체가 하나만 필요할 것 같다 하더라도 앵간하면 인터페이스로 만드는 것이 확장성 측면에서도 좋다고 생각한다.
클래스 다이어그램
도메인 협력 관계를 기반으로 개발자가 어떤식으로 구현할 것인지 상세하게 그린 다이어그램이다. 회언 서비스와, 회원 저장소(리포지터리)를 인터페이스로 만들고 각 인터페이스를 구현하는 구현체들을 설계한다.
객체 다이어그램
클래스 다이어그램 뿐만 아니라 객체 다이어그램도 중요하다. 이는 개발 시 실제로 어떤 구현체를 사용할지 나타내는 다이어그램이다. 클래스 다이어그램에서 회원 저장소에 대해 메모리 저장소를 사용할지 DB 저장소를 사용할지 미확정인 상황에서 프로그램 실행시 메모리 회원 저장소를 사용한다고 했을 때, 위 그림처럼 나타낼 수 있다.
도메인 개발
전체 코드는 깃허브에 저장해 놓았다. 다음은 개발 시 주의 했던 부분들을 기록해 나간다.
저장소
- 일단 메모리 회원 저장소를 사용할 텐데 이를 private static HasMap을 사용함으로써 여러 접근에 대해서 회원 관리를 유지시켜준다.
<member/MemoryMemberRepository.java>
private static Map<Long,Member> store=new HashMap<>();
테스트
- member/MemberApp.java 처럼 애플리케이션 로직에서 테스트하는 방법도 있지만 이보다 JUni test를 사용하는 습관을 들이는 것이 좋다. 또한 스프링을 계속 찍어내는 통합테스트보다 각 로직별로 단위테스트를 진행하는 것이 빠르고 편리하기 때문에 단위테스트를 잘 만드는 것이 매우 중요하다.
도메인 설계의 문제점
- OCP, DIP 위반
member/MemberServiceImpl.java
public class MemberServiceImpl implements MemberService {
private final MemberRepository memberRepository = new
MemoryMemberRepository();
public void join(Member member) {
memberRepository.save(member);
}
public Member findMember(Long memberId) {
return memberRepository.findById(memberId);
}
}
위 코드는 회원 서비스 역할의 구현체이다.
이 코드의 설계상 문제점은 무엇일까? : 회원리포지토리를 할당 받는 부분을 보면 회원리포지토리의 인터페이스에만 의존한다고 생각할 수 있지만 new MemoryMemberRepository() 부분에서 회원리포지토리의 구현체에까지 의존한다는 것을 볼 수가 있다.(DIP 위반) 만약 DB 저장소를 사용해야 하는 경우라면 직접 회원서비스의 구현체의 코드를 수정해야 한다.(OCP 위반).
정리하자면 의존관계가 인터페이스 뿐만 아니라 구현까지 모두 의존하는 문제점이 있다. 이를 해결하기 위해 다음 포스팅부터 객체 지향 원리를 적용하는 법을 알아본다.
'java > spring' 카테고리의 다른 글
[Spring] 컴포넌트 스캔 (0) | 2021.01.08 |
---|---|
[Spring] 싱글톤 컨테이너 (0) | 2021.01.08 |
[Spring] 스프링 설정하기, 스프링 컨테이너와 스프링 빈 (0) | 2021.01.08 |
[Spring] 스프링 핵심 원리 이해2 - 객체 지향 원리 적용 (0) | 2021.01.06 |
[Spring] 객체 지향 설계와 스프링 (0) | 2021.01.03 |