본문 바로가기
부트캠프 개발일기/Pre-Project

79일차: Solo Project(키오스크 구현)

by shyun00 2023. 6. 7.

본격적으로 프로젝트를 시작하기에 앞서 Section3에서 배운 내용을 최대한 교재를 참고하지 않고 혼자 구현해 보는 연습을 했다.

이해했다고 생각했던 부분도 혼자서 진행하려고하니 안 되는 부분들이 꽤 있었다. 

 

❯ 솔로프로젝트 - 커피 키오스크 구현하기

1. 기능 요구사항 정의하기

커피 메뉴를 등록하고, 조회하고, 수정할 수 있어야한다.

주문하는 고객의 정보를 저장하고 고객별로 스탬프 개수를 가지게 된다.

고객이 주문하려는 커피의 목록, 갯수 등 커피 주문 정보가 있어야 한다.

(구현 연습을 위해 결제, 배달, 픽업 등 부가적인 기능은 제외하였다.)

 

2. 필요한 리소스 정의 및 컨트롤러 작성

커피, 고객, 주문에 대한 리소스를 정의하고 리소스별로 필요한 기능을 컨트롤러를 통해 작성한다.

이후 기능을 구현할 때 연관관계를 설정하면서 일부 속성이 추가될 예정이다.

 

3. 컨트롤러에 필요한 Dto 객체 설정

Coffee, Member, Order와 관련하여 Post, Patch 등의 요청을 할 때 필요한 파라미터들이 있다.

이를 하나씩 받아오는 것이 아니라 Dto를 통해 RequestBody로 한 번에 받아올 수 있다.

또한 Dto 객체를 통해 유효성 검사를 간단하게 설정할 수 있는데, 이때 의존 라이브러리 추가가 필요하다.

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-validation'
	...
}

 

4. 서비스 클래스(계층) 작성 및 컨트롤러에 DI

실질적인 비즈니스 로직을 담당하는 서비스 클래스 코드를 작성한다.

컨트롤러의 기능과 매칭하여 메서드를 작성하며, DI를 통해 컨트롤러에 주입, 컨트롤러에서 서비스 클래스의 메서드를 사용한다.

 

5. 엔티티 객체 생성 및 매핑

컨트롤러에서 서비스 클래스의 메서드를 사용하기 위해 Dto 객체를 엔티티 객체로 변경(역직렬화)하거나 반대로 변환(직렬화)해야 하는 경우가 있다. 개발자가 직접 코드를 통해 해당 과정을 수행할 수도 있겠지만, MapStruct와 Mapper를 사용해 간단하게 구현할 수 있다.

이때 MapStruct를 사용하기 위해서는 해당 라이브러리를 추가해주어야 한다. 

dependencies {
	...
	implementation 'org.mapstruct:mapstruct:1.4.2.Final' // MapStruct 라이브러리 의존성 주입
	annotationProcessor 'org.mapstruct:mapstruct-processor:1.4.2.Final' // MapStruct 애너테이션 프로세스를 추가
    // * 애너테이션 프로세서란, 컴파일 시점에 애너테이션을 기반으로 추가적인 코드를 생성하는 도구임
}

 

6. 예외 처리

비즈니스 로직을 수행하다 보면 유효성 검사에 실패하거나, 일치하는 회원/커피 정보가 없는 등 오류가 발생할 수 있다.

필요한 경우 이러한 오류 발생 시 어떻게 처리할지 정의해줄 수 있다. (사용자 정의 예외를 사용해 의도적으로 예외를 발생시킬수도 있다.)

@ExceptionHandler를 사용해 특정 예외 발생시 어떠한 조치를 할지 정해줄 수 있는데,

만약 컨트롤러 별로 해당 코드를 작성하게 되면 중복 코드가 많이 생길 수 있다.

따라서 @RestControllerAdvice를 통해 공통적인 부분은 여러 컨트롤러에 적용할 수 있도록 처리할 수 있다.

 

7. Spring Data JPA  적용

대략적인 코드가 완성되었고, 이제 데이터를 데이터베이스와 연동하여 실제로 추가 / 삭제 / 수정할 수 있는지 확인하였다.

인메모리 데이터베이스인 H2를 사용하였다.

JPA를 적용하기 위해서는 의존 라이브러리를 추가해야 하며, H2를 사용하기 위해서는 application.yml(혹은 properties)에 적절한 설정을 해주어야 한다.

spring:
  h2:
    console:
      enabled: true
      path: /h2 # h2 콘솔을 /h2 경로에서 사용할 수 있도록 함
  datasource:
    url: jdbc:h2:mem:test
  jpa:
    hibernate:
      ddl-auto: create # 엔티티 객체를 자동으로 생성함
    show-sql: true
dependencies {
    	...
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
	runtimeOnly 'com.h2database:h2'
	...
}

이후 엔티티 간의 연관관계를 매핑한다.

Spring Data JPA는 단방향, 양방향 연관관계를 모두 지원하며 Sprint Data JDBC는 단방향 연관관계만 지원한다. 

 

8. 트랜잭션 적용

Spring에서 트랜잭션을 가장 간단하게 적용하는 방법은 @Transactional 애너테이션을 사용하는 것이다.

애너테이션을 클래스 레벨에 추가하게 되면 해당 클래스에서 Repository 기능을 이용하는 모든 메서드에 트랜잭션이 적용된다.

메서드 레벨에 적용하게 되면 해당 메서드 레벨에 트랜잭션이 적용된다.

 

9. 테스팅

작성된 코드가 제대로 동작하는지 테스트 케이스를 작성해 확인할 수 있다.

JUnit과  Mockito를 사용해 테스트를 진행할 수 있다.

아직은 코드를 작성하는 것만으로도 쉽지 않아서 테스트 케이스를 나중에 작성했는데,

TDD(테스트 주도 개발)의 경우 테스트를 먼저 하고 요구사항에 맞게 기능을 구현하는 개발 방법도 있다.

 

10. API 문서화

현재 구현한 코드는 백엔드 부분의 코드이다. 클라이언트는 프론트엔드 부분과 소통하게 되며, 프론트엔드는 API를 통해 백엔드와 소통하게 된다. 따라서 상호 요청을 주고받기 위해 필요한 요청정보를 잘 문서화하는 것이 중요하다.

물론 문서를 직접 작성할 수 있겠지만 Spring Rest Docs를 통해 자동으로 생성할 수 있다.

문서를 자동으로 생성할 경우 인적 오류를 예방할 수 있으며 생산성을 향상할 수 있다.

Spring Rest Docs로 API 문서를 자동화하기 위해서는 컨트롤러에 대한 슬라이스 테스트가 먼저 진행되어야 하며,

테스트가 정상적으로 통과되면 정해진 절차에 따라 API 문서가 자동으로 생성된다.


확실히 직접 해보는 것과 해보지 않는 것의 차이가 있었다.

매번 해야지 해야지 하다가 진도 따라가기에 바빠 복습이 미뤄지고 있었는데,

처음부터 다시 한번 구현해 보니 확실히 정리되는 느낌이 들었다.

아직 Section4의 보안 부분은 개념이 명확하지 않은 것이 많아서 프로젝트하는 동안 틈틈이 추가 공부를 해야 할 것 같다.