본격적으로 계좌 시스템 개발 프로젝트를 시작하겠습니다.
1편은 관련 클래스 설명과 계좌 생성 API 부분을 기준으로 진행하려고 합니다 👨💻
AccountUse Entity(계좌 사용자 엔티티)
- 앞으로 구현될 대부분의 엔티티는 createdAt 과 updatedAt 속성을 가집니다. 중복되는 부분을
처리하기 위해 EntityListeners 어노테이션을 사용하였습니다.
Account Entity(계좌 엔티티)
- Account 와 AccountUser 는 일대다 관계로 Account 부분에서 단방향으로 연결하였습니다.
테이블에서 "다 쪽이 외래키를 가진다" 원칙에 따라
Account 쪽에서 객체 그래프 탐색이 가능하도록 AccountUser 를 참조하고 있습니다.
AccountDto 클래스
- Entity 클래스와 Dto 클래스의 역할을 분리시켜서 MVC 패턴을 구현하는 방법이
각 클래스의 특징을 보장해준다는 점에서 가장 선호되는 방식입니다.
따라서 앞으로 구현 될 Service layer 에서 요청 처리 후,
바로 AccountEntity 타입으로 반환하는 것이 아니라, AccountDto 로 변환하는 과정을 거치기 위해
AccountDto 내부의 정적 메소드를 하나 구현하였습니다.
해당 메소도는 처리 된 Account Entity 타입의 객체를 AccountDto 객체로 변환하여 리턴하는 역할을 합니다.
AccountException 클래스
- Enum 타입의 ErrorCode 속성과 errorMessage 속성을 가지고 있습니다.
ErrorCode 클래스는 String description 속성을 가지고 있는데,
description 속성을 이용하여 AccountException 클래스의 errorMessage 속성을 처리하고자 합니다.
이를 위해 별도의 생성자를 두었습니다.
ErrorCode 클래스
- 해당 프로젝트 내에서 발생하는 다양한 예외 상항을 Enum 타입으로 정의했습니다.
각 ErrorCode 타입의 상수들은 각 상황에 맞는 예외 메세지(description) 을 가지고 있습니다.
계좌 생성 API 간단 설명
URL : post/account
파라미터 : 사용자 아이디, 초기 잔액
성공 응답 : 사용자 아이디, 생성된 계좌 번호, 등록 일시
정책 : 계좌 생성시 개발 편의를 위해 최신 계좌 번호 + 1 로 생성.
한명의 사용자는 10개 이상의 계좌 번호를 가지지 못함.
저장이 필요한 정보
칼럼명 | 데이터 타입 | 설명 |
---|---|---|
id | pk | 기본키 |
account user | AccountUser | 계좌 소유자 |
account number | String | 계좌 번호 |
account status | AccountStatus | 계좌 상태 |
balance | Long | 계좌 잔액 |
registeredAt | LocalDateTime | 계좌 등록 일시 |
UnregisteredAt | LocalDateTime | 계좌 해지 일시 |
createdAt | LocalDateTime | 계좌 생성 일시 |
updatedAt | LocalDateTime | 최종 수정 일자 |
요청/응답 구조
요청
{
"userId" : 1,
"initialBalance" : 100
}
응답
{
"userId" : 1,
"accountNumber" : "1234567890",
"registeredAt" : "2022-12-01T23:26:14.123121"
}
CreateAccount 클래스
- 해당 클래스는 계좌 생성 API 에 대한 요청 & 응답 관련 클래스 입니다.
특징으로는 Request & Response 클래스를 Inner 클래스로 설정하였다는 점입니다.
계좌 생성에 대한 요청 객체는 Request 가 될 것이고, 요청 처리 후 응답 객체는
Response 가 될 것입니다.
또한 여기서 주목해야할 점은 Service Layer 에서 받아온 결과의 타입인 AccountDto 로
요청자에게 리턴하는 것이 아니라, 기존에 정한 계좌 생성 컨트롤러의 반환 타입인 Response 타입으로
번한하기 위해 , 정적메소드 FromAccountDto 를 구현하였습니다.
계좌 생성 Controller
- 위에서 설명했던 것처럼, createAccount 컨트롤러의 요청 타입은 CreateAccount.Request 이며,
반환 타입은 CreateAccount.Reponse 입니다.
또한 accountService(Service Layer) 에서 처리한 결과는 1회용 결과이기에, 해당 결과를 위한
변수를 따로 두는 것이 아니라, CreateAccount.Response.FromAccountDto 메소드를 통해
Reponse 타입으로 변환 후 리턴하였습니다.
계좌 생성 Service
- accountUserRepository에서 사용자 아이디 값으로 받은 AccountUser(사용자) 를 변수로 저장합니다.
해당 사용자가 존재하지 않는다면 AccountException을 통해 에러 처리를 합니다.
혹은 해당 사용자의 계좌가 이미 10개 이상이여도 AccountException 을 발생시킵니다.
accountRepository에서 가장 최신에 저장된 계좌번호를 받아 옵니다.
새로운 계좌 번호는 정해진 정책에 따라 최신 계좌번호 + 1 이 될 것입니다.
마찬가지로 AccountDto 타입으로 반환할 것이기에, fromEntity 메소드를 통해 Account 타입을 AccountDto 로 변환하여 리턴합니다.
Controller Test
- successCreateAccount() (계좌 생성 성공)
Service Test
- createAccountSuccess() (계좌 생성 성공)
- createAccountUserNotFound() (해당 사용자 없는 경우)
- createAccountMaxAccountIs10() (해당 사용자 계좌가 10개 이상인 경우)
1) createAccountSuccess() (계좌 생성 성공)
2) createAccountUserNotFound() (해당 사용자 없는 경우)
3) createAccountMaxAccountIs10() (해당 사용자 계좌가 10개 이상인 경우)
1) 배운점
Mockito 프레임 워크 사용법을 배웠습니다 🦾
원래 테스트 코드 작성시 Spring 에서 제공하는 Junit 4 를 사용해 왔습니다.
하지만 DI(Dependency Injection) 문제 때문에 매번 테스트 코드 설계하기가 까다롭고 어렵게만 느껴졌습니다.
이번 프로젝트를 진행하면서 테스트는 어떤 방식으로 설계할까 고민하다 Mockito 테스트 프레임워크를 사용해보게 되었습니다.
Mockito 가 생소하다면 Mockito를 뿌셔봅시다 를 참조 바랍니다 🔥
Mockito 프레임워크를 신나서 사용하고 있었는데, BDD 설계 방식도 알게 되었습니다.
Mockito의 BDD 버전인 BDDMockito 를 사용하여 행위 주도 개발을 해보았습니다.
개발자라면 테스트 코드 작성은 필수적인 과정이라고 생각합니다.
BDD 개발 방식이란? (feat. BDDMockito) 을 참고 부탁드립니다 🙆🏻
2) 느낀점
비록 현재 진행중인 Account 개발 프로젝트는 그리 규모가 크지 않은 개인 프로젝트입니다.
하지만 프로젝트의 규모를 떠나서 개발시 테스트 코드 작성과 유효성 검사가 정말 중요하다는 것을 느꼈습니다.
하나의 예시로 계좌 생성 요청시 전달하는 userId 는 최소값이 1입니다.
저는 CreateAccount.Request 클래스 객체의 유효성 검사를 위해 @Min어노테이션을 사용해
최소값을 1로 설정해 놓았습니다.
요청 테스트 과정에서 실수로 userId 를 0으로 설정해 요청을 보냈으며
해당 요청에 문제가 있음을 바로 인지할 수 있었습니다.