[웹 개발 프로젝트] Book적Book적

지니·2025년 8월 6일

Project

목록 보기
2/3

1. 프로젝트 개요


1-1. Book적Book적 프로젝트란?

책을 중심으로 한 웹 기반 도서 서비스로 도서 구매 + 커뮤니티 기능을 통해 책에 대한 생각과 경험을자유롭게 공유 할 수 있는 플랫폼

  • 백엔드 : Spring Boot를 이용해 개발했으며 MSA 구조로 설계
  • 프론트엔드 : Vue.js를 이용해 프론트엔드 개발

1-2. 프로젝트 주요 기능

(1) 회원 관리

  • Spring Security를 활용한 회원가입, 로그인 기능
  • Gmail API를 이용한 비밀번호 재설정 기능

(2) 도서 관리

  • 도서 API를 연동한 도서 목록 확인
  • 도서 검색, 조회 기능
  • 관리자의 도서 관리 기능
  • 도서 구매 기능 (Toss API 연동)

(3) 소셜 관리

  • 팔로우/팔로워 기능
  • 독서 커뮤니티 기능

2. 프로젝트 진행 과정


2-1. 진행 과정

프로젝트는 다음과 같은 과정으로 진행했다.

주제 선정 → 요구사항 명세서 작성 → 이벤트 스토밍 → ERD → 백엔드 개발 → 기능 명세서 작성 → 화면 설계 → 프론트엔드 개발 → 발표

이중에서 이벤트 스토밍이라는 것이 있는데, 이것은 도메인 주도 개발(DDD)를 위해 진행한 것이었다. 우선 이것을 이용한 이유를 설명하기 전에, DDD가 무엇이며 이벤트 스토킹 기법이 무엇인지 간단하게 이야기 하자.

✅ 도메인 주도 개발(DDD)란?
비즈니스 도메인별로 나눠서 설계, 개발을 진행하는 방식이다.

여기에서 말하는 도메인은 유사한 업무의 집합 즉, 소프트웨어가 해결하고자 하는 비즈니스 문제 영역 이라고 생각하면 된다.우리 프로젝트로 예를 들면, 구매/도서/회원 같은것을 하나의 도메인이라고 생각하면 된다.

우리는 이러한 DDD를 실현하기 위해 이벤트 스토밍 기법을 사용했다. 그리고, 이 기법을 이용해 소통하면 각자 생각하는 기능이 모두 통일될 수 있고 의견을 맞춰나갈 수 있기 때문에 도입했다.

2-2. 여러 구조와 아키텍처에 대한 고민

(1) CQRS 구조 적용

CQRS구조랑 Command와 Query의 책임을 분리해서 사용하는 구조이다. 여기에서 Command는 데이터의 상태를 변경(create, update, delete)하는 것이고, Query는 데이터를 조회(select)하는 것이다.

CORS의 장점 :
https://learn.microsoft.com/ko-kr/azure/architecture/patterns/cqrs

⭐ CQRS를 도입한 이유

  • 쓰기에는 JPA, 읽기에는 MyBatis를 사용하고 있었음
    (초기에 JPA로 복잡한 쿼리를 작성하는데 한계를 느꼈고, 조회 로직에서는 MyBatis를 적용하는 것이 더 좋다고 판단)
  • 읽기와 쓰기 로직을 분류하는 것이 추후 유지보수를 위해선 더 편리하다고 생각함

결과적으로 Command와 Query를 분리한 CQRS 패턴을 도입함

(2) MSA 구조를 도입한 이유 ⁉️
사실 MSA 구조라는 게 어느 정도 규모가 있어야 적용하는 게 적절하다고 생각한다. 그리고, 그 규모는 적어도 회사에서 운영하는 프로젝트라고 본다. 내 프로젝트 정도의 규모는 MSA 구조를 사용하는 것보다 모놀리식을 사용하는 게 더 좋다.

하지만, 이 프로젝트에서는 기술적 실험과 구조적 확장성을 경험하기 위한 목표로 이 MSA 구조를 도입했다.

  • 서비스 책임 분리 경험하기
  • 대뮤모 서비스나 다양한 비즈니스 확장을 고려했을 때, 도메인 단위의 서비스 분할 경험이 필요하다고 판단함

⭐ 우리의 MSA 구조
위와 같은 생각으로 MSA 구조로 분류했고, 우리는 크게 2가지 서비스로 분리했다.

book-service와 etc-service로 분리했다. 이렇게 분리한 이유는 book 서비스는 도서 관련 핵심 도메인이고 그외에 나머지는 부가 기능이었다. 그리고, 도서 기능을 복잡도와 중심성을 감안했을 때 이렇게 나누는게 맞다고 판단했다. (기능 크기 중심으로 분리)

2-3. 나의 역할

(1) 비밀번호 재설정 기능 구현

(2) 팔로우/팔로잉 기능 및 즐겨찾기 기능 도입

  • 관심 회원을 팔로우/팔로잉 할 수 있으며 해당 회원이 작성한 커뮤니티 글 조회할 수 있다.
  • 관심 도서, 관심 작가를 추가/삭제할 수 있다.

(3) Swaager를 이용한 API 명세서, Readme 파일, 발표 자료 제작
이런식으로 Swagger를 연결하면하면 API 명세서를 한 눈에 확인할 수 있다. 밑에 사진은 Swagger를 Spring boot에 연결한 것이다.

연결 방법은 다음 링크에서 확인할 수 있다.

✅ Spring Boot에 Swagger 연동하기
https://velog.io/@dbwls89173/Rest-API-Swagger-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0

(4) 발표
이 프로젝트는 프론트와 백엔드를 나눠서 발표했는데, 2번의 발표 모두 내가 맡아서 진행했다.


3. 프로젝트 회고


3-1. 나의 트러블 슈팅

Mock 테스트 과정에서 에러

⚠️ 문제 상황
@InjectMocks,@Mock 기반으로 단위 테스트를 하려고 했는데...
아래처럼 썼는데, 계속 NullPointerException 발생

@ExtendWith(MockitoExtension.class)
class PasswordResetServiceImplTest 

    @Mock
    private PasswordResetTokenRepository passwordResetTokenRepository;

    @Mock
    private PasswordEncoder passwordEncoder;

    @Mock
    private MemberRepository memberRepository;

    @Mock
    private EmailCommandServiceImpl emailService;

    @InjectMocks
    private PasswordResetCommandService passwordResetService;

🧐문제 원인

  • @InjectMocks는 구현체를 대상으로 해야함. 그런데, 여기에서 PasswordResetCommandService는 실제 구현체가 아닌 Interface이기 때문에 문제 발생
  • 테스트 수행 시 내부 의존성이 주입되지 않아 NullPointerException이 발생

✅ 문제 해결
실제 구현체로 바꿔 문제 해결

@InjectMocks
private PasswordResetCommandServiceImpl passwordResetService;

3-2. 앞으로의 과정

  이번 프로젝트는 Spring Boot 적응기 느낌이었다. 그래서 간단한 CRUD를 구현하는 수준의 기능을 맡았고, 여기에 심화할 수 있는 비밀번호 재설정 기능까지 담당해 프로젝트를 진행했다. 이 경험을 바탕으로 더 발전된 프로젝트를 진행해야 겠다.

  그리고 이번에 MSA 구조를 경험했다. 이 구조를 통해 단순히 기술을 사용하는 것을 넘어 '서비스 경계와 책임을 고민하는 훈련'이 됐다. 그리고, 규모가 작았던 만큼 마이크로서비스의 분리는 오히려 관리 복잡도를 증가시켰다. 하지만, 학습 단계였기 때문에 이러한 구조를 도전해본 것에 의의가 있다고 생각한다. 또한 이번 경험을 통해 MSA구조와 모놀리식 구조를 언제 사용하면 좋을지에 대해 많은 생각을 할 수 있게 됐다.

  마지막으로 성능 개선을 위해 회원가입과 로그인 쪽에서 Redis를 활용하고, ElasticSearch를 활용해보고 싶다.

0개의 댓글