[Spring] 02-2. 회원 도메인 설계 및 개발

지찬우·2022년 12월 19일
0

Spring

목록 보기
6/27
post-thumbnail

이 시리즈는 인프런 강의(김영한 님의 ‘스프링 핵심 원리 - 기본편’)로 공부하며 혼자 기록하고, 사람들과도 공유할 수 있도록 작성하는 글이다. 최대한 추가적인 정보는 공식 홈페이지, 문서를 보며 얻을 예정이다.
(개인적인 생각과 이해가 들어가 있기 때문에 저의 ‘무식함’이 있을 수 있습니다😜 혹시라도 이 글을 보게 되시는 분이 계시다면 잘못된 부분 댓글로 많이 알려주시면 너무 감사하겠습니다!!)

GitHub Repository : https://github.com/jcw1031/spring-core-study


🙋🏻 회원 도메인 설계 및 개발

🧐 요구사항 분석

앞으로 진행할 예제의 전체적인 요구사항은 다음과 같다. 우리는 개발자이고, 기획자가 우리에게 와서 요구사항을 제시한 것이다.

[ 회원 ]

  • 회원을 가입하고 조회할 수 있다.
  • 회원은 일반VIP 두 가지 등급이 있다.
  • 회원 데이터는 자체 DB를 구축할 수 있고, 외부 시스템과 연동할 수 있다. (미확정)

[ 주문과 할인 정책 ]

  • 회원은 상품을 주문할 수 있다.
  • 회원 등급에 따라 할인 정책을 적용할 수 있다.
  • 할인 정책은 모든 VIP는 1000원을 할인해주는 고정 금액 할인을 적용한다. (나중에 변경될 수 있다.)
  • 할인 정책은 변경 가능성이 높다. 회사의 기본 할인 정책을 아직 정하지 못했고, 오픈 직전까지 고민을 미루고 싶다. 최악의 경우 할인을 적용하지 않을 수 있다. (미확정)

요구사항을 살펴보면, 회원 데이터나 할인 정책 같은 부분은 아직 미확정인 상태이다. 그래서 앞에서 배웠던 ‘역할과 구현을 분리해라’를 적용하여 객체 지향 설계를 해 볼 것이다. 인터페이스를 먼저 만들고 구현체를 언제든지 변경할 수 있도록 설계하면 된다.


📃 회원 도메인 설계

설계 단계에서 그림은 개념적으로 크게 3가지가 그려진다.

  • 도메인 협력 관계
  • 클래스 다이어그램
  • 객체 다이어그램

회원 도메인 협력 관계

도메인 협력 관계는 기획자들도 볼 수 있는 그림이다.


회원 클래스 다이어그램

클래스 다이어그램은 도메인 협력 관계를 바탕으로 개발자가 구체화하여 설계한 것이다. 실제 서버를 실행시키지 않고 클래스들만 분석하여 그릴 수 있다.


회원 객체 다이어그램

위에 있는 클래스 다이어그램은 MemberRepository의 구현체로 MemoryMemberRepository가 사용될지, DbMemberRepository가 사용될지 알 수 없다. 따라서 이 객체 다이어그램을 사용하여 실제 서버가 실행되어 사용하게 되는 객체를 나타낸다.


🛠️ 회원 도메인 개발

이제 회원 클래스 다이어그램을 기반으로 개발을 시작해 보자.

김영한 님께서 자주 하시는 얘기가 있다. ‘백문이 불여일타’. 그냥 보고 듣기만 하지 말고, 직접 코드를 손으로 쳐보는 것을 강조하신다. 그래서 나도 직접 쳐보며 진행하고 있고, 코드 블록이 아닌 화면을 캡처하여 코드를 올릴 것이다.

또한 원래 예외 처리를 해야 하지만 예제의 핵심이 아니기 때문에 그 부분은 생략하고 진행한다.


패키지 생성

원래는 패키지를 여러 개로 나누어 클래스와 인터페이스를 만드는 것이 구조적으로 좋다. 하지만 예제가 복잡해지기 때문에 그냥 한 패키지에 생성하기로 한다.

CoreApplication이 포함되어 있는 패키지 안에 ‘member’ 패키지를 생성한다. 이제 이 패키지에 회원 도메인 클래스(또는 인터페이스)들을 생성할 것이다.


회원 엔티티

이제는 회원 엔티티 클래스를 생성해 보자. 그전에 회원의 등급을 나타내는 Grade를 열거형(Enum)으로 생성한다.

나는 사실 열거형을 들어보기만 했지 사용해 보거나 공부해 본 적이 없다. 그래서 오늘 이 글을 쓰고 한 번 공부해 볼 생각이다. 사실 잘 몰라도 강의를 듣는 데 크게 지장이 없을 것 같지만(하다 보면 대충 감을 잡을 수도 있을 것 같다..!) 그래도 모르고 사용하는 것보다는 알고 사용하는 게 좋을 것 같다. 나의 무지함이 부끄럽다🫣

(member 패키지 내에 Grade 생성)


Grade 열거형을 생성하고, 요구사항에 ‘회원은 일반과 VIP 두 가지 등급이 있다.’라고 했으니 다음과 같이 BASIC과 VIP를 입력하여 놓는다.


다음은 회원 엔티티 Member를 생성하자. 마찬가지로 member 패키지 내에 생성한다.


요구사항에 나와있지는 않지만 회원은 id이름, 등급을 갖는다. 아래와 같이 멤버 변수를 선언한다.


이제 생성자를 만든다. 아래의 단축키를 사용하면 생성자를 편리하게 입력할 수 있다.

MacOS : + N
Windows : Alt + Insert


Constructor를 클릭하고 모든 멤버 변수를 선택한 후에 Enter를 누르면 아래와 같이 자동으로 생성자가 입력된다. 아주 편하다 ^^


이제 getter와 setter도 만들어 준다. getter와 setter를 통해 Member 객체의 멤버 변수의 값을 가져오거나, 값을 세팅할 수 있다. 아래처럼 getter와 setter도 간단하게 만들 수 있다.(위의 단축키 사용)

사실 setter를 사용하는 것은 좋은 방법이 아닌 걸로 알고 있었지만 아마 초보자들을 위한 예제이기 때문에 이렇게 하시는 것 같다!


getter와 setter를 모두 만들었다.


회원 저장소

이제는 회원의 저장소를 만들어보자. 저장소는 먼저 인터페이스를 만들고 그 후에 클래스로 구현하도록 한다.


회원 저장소 인터페이스

회원 저장소 인터페이스 MemberRepository를 member 패키지에 생성한다.


요구사항에서 회원은 가입조회가 가능하다고 했다. 그럼 저장소에 회원을 저장하는 메서드검색하는 메서드가 필요하다. 아래와 같이 추상 메서드를 만든다.

save() : 회원 저장
findById() : 회원 검색(id를 통해 검색)


메모리 회원 저장소 구현체

인터페이스에 있는 추상 메서드들을 구현해 줄 클래스가 필요하다. MemberRepository 인터페이스의 추상 메서드들을 구현할 MemoryMemberRepository를 생성한다.


MemberRepository의 구현 클래스이므로 implements MemberRepository를 코드에 추가한다. 그럼 추상 메서드들을 구현하라고 경고문이 뜬다. 아래 단축키를 사용하면 ‘Quick-fixes’ 기능을 편리하게 사용할 수 있다. Implement methods를 선택한다.

MacOS : + Enter
Windows : Alt + Enter


짜잔~ 자동으로 인터페이스의 추상 메서드를 구현하는 부분이 입력된다. 굉장히 편리하다.


우선 메서드들을 구현하기 전에, 메모리 저장소이므로 회원을 저장할 Map을 만들어 주도록 한다.

메모리에 저장되는 것이기 때문에 서버를 껐다 키면 모든 데이터가 날아가게 된다. 이 방법은 개발용(테스트용)으로만 사용된다. 또한 동시성 이슈 때문에 HashMap이 아닌 ConcurrentHashMap을 사용해야 하지만 설명이 너무 길어지므로 HashMap으로 진행하신다고 한다.


생성한 Map을 통해 함수를 구현해 보자. save()는 회원을 저장하는 기능이므로, put()을 사용해 Map에 id를 key로, Member를 value로 저장해준다.

findById()는 id를 통해 회원을 검색하는 기능이므로, get()을 사용해 key(id)를 통해 회원 객체를 가져온다.


회원 서비스

다음은 서비스 부분을 만들어보자. 저장소와 마찬가지로 인터페이스를 만들고 구현체 클래스를 만든다.


회원 서비스 인터페이스

member 패키지 내에 회원 서비스 MemberService 인터페이스를 생성한다.


회원 서비스는 두 가지 기능이 필요하다. 회원가입과 회원 조회 기능이다. 회원가입 기능의 join()회원 조회 기능의 findMembe() 두 개의 추상 메서드를 만든다.


회원 서비스 구현체

인터페이스를 만들었으므로, 회원 서비스 구현체 MemberServiceImpl 클래스를 생성한다.

관례상 구현체가 하나만 존재하면 인터페이스 이름 뒤에 ‘Impl’(Implement)을 붙인다.


아까 MemoryMemberRepository를 만들 때와 마찬가지로 implements MemberService를 추가하고, 회원 서비스 인터페이스의 추상 메서드들을 구현하도록 한다.


추상 메서드를 구현하기 전에, 서비스에서 가입을 하고 회원을 조회하려면 아까 만들어 놓은 저장소 MemberRepository를 사용해야 한다. 구현체는 MemoryMemberRepository를 생성해서 사용한다.

아마 익숙한 코드일 것이다. SOLID를 공부할 때 OCP와 DIP를 설명할 때 사용됐었다.


이제 이 memberRepository를 통해 회원가입과 조회 메서드를 구현해 보자. 회원가입은 save(), 조회는 findById()를 사용한다.


회원 엔티티와 회원 저장소, 그리고 회원 서비스를 모두 만들었다.


현재 인터페이스와 클래스 사이의 관계는 다음과 같다고 보면 된다.

원래 화살표는 상속 관계를 표시하는 용도이지만, 이해를 위해 점선은 구현체를 표현하고 실선은 의존관계를 나타내보았다.


지금까지 요구사항을 기반으로 회원 도메인을 설계하고 개발까지 해보았다. 확실히 스프링 입문 강의를 듣고 진행하니 훨씬 이해도 잘 되고 익숙해서 좋은 것 같다. 만약 처음 시작하는 분이 계신다면 해당 강의를 먼저 듣고 따라 해보면 이해도가 높아질 것 같다.

다음 시간에는 지금까지 만든 회원 도메인을 실행해 보고 테스트 코드를 작성해 볼 예정이다.

profile
좋은 개발자가 되자.

0개의 댓글