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

(1) 회원 관리
(2) 도서 관리
(3) 소셜 관리
프로젝트는 다음과 같은 과정으로 진행했다.
주제 선정 → 요구사항 명세서 작성 → 이벤트 스토밍 → ERD → 백엔드 개발 → 기능 명세서 작성 → 화면 설계 → 프론트엔드 개발 → 발표
이중에서 이벤트 스토밍이라는 것이 있는데, 이것은 도메인 주도 개발(DDD)를 위해 진행한 것이었다. 우선 이것을 이용한 이유를 설명하기 전에, DDD가 무엇이며 이벤트 스토킹 기법이 무엇인지 간단하게 이야기 하자.
✅ 도메인 주도 개발(DDD)란?
비즈니스 도메인별로 나눠서 설계, 개발을 진행하는 방식이다.
여기에서 말하는 도메인은 유사한 업무의 집합 즉, 소프트웨어가 해결하고자 하는 비즈니스 문제 영역 이라고 생각하면 된다.우리 프로젝트로 예를 들면, 구매/도서/회원 같은것을 하나의 도메인이라고 생각하면 된다.
우리는 이러한 DDD를 실현하기 위해 이벤트 스토밍 기법을 사용했다. 그리고, 이 기법을 이용해 소통하면 각자 생각하는 기능이 모두 통일될 수 있고 의견을 맞춰나갈 수 있기 때문에 도입했다.
(1) CQRS 구조 적용
CQRS구조랑 Command와 Query의 책임을 분리해서 사용하는 구조이다. 여기에서 Command는 데이터의 상태를 변경(create, update, delete)하는 것이고, Query는 데이터를 조회(select)하는 것이다.
CORS의 장점 :
https://learn.microsoft.com/ko-kr/azure/architecture/patterns/cqrs
⭐ CQRS를 도입한 이유
결과적으로 Command와 Query를 분리한 CQRS 패턴을 도입함
(2) MSA 구조를 도입한 이유 ⁉️
사실 MSA 구조라는 게 어느 정도 규모가 있어야 적용하는 게 적절하다고 생각한다. 그리고, 그 규모는 적어도 회사에서 운영하는 프로젝트라고 본다. 내 프로젝트 정도의 규모는 MSA 구조를 사용하는 것보다 모놀리식을 사용하는 게 더 좋다.
하지만, 이 프로젝트에서는 기술적 실험과 구조적 확장성을 경험하기 위한 목표로 이 MSA 구조를 도입했다.
⭐ 우리의 MSA 구조
위와 같은 생각으로 MSA 구조로 분류했고, 우리는 크게 2가지 서비스로 분리했다.
book-service와 etc-service로 분리했다. 이렇게 분리한 이유는 book 서비스는 도서 관련 핵심 도메인이고 그외에 나머지는 부가 기능이었다. 그리고, 도서 기능을 복잡도와 중심성을 감안했을 때 이렇게 나누는게 맞다고 판단했다. (기능 크기 중심으로 분리)

(1) 비밀번호 재설정 기능 구현
Gmail SMTP를 활용해(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번의 발표 모두 내가 맡아서 진행했다.
⚠️ 문제 상황
@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이기 때문에 문제 발생✅ 문제 해결
실제 구현체로 바꿔 문제 해결
@InjectMocks
private PasswordResetCommandServiceImpl passwordResetService;
이번 프로젝트는 Spring Boot 적응기 느낌이었다. 그래서 간단한 CRUD를 구현하는 수준의 기능을 맡았고, 여기에 심화할 수 있는 비밀번호 재설정 기능까지 담당해 프로젝트를 진행했다. 이 경험을 바탕으로 더 발전된 프로젝트를 진행해야 겠다.
그리고 이번에 MSA 구조를 경험했다. 이 구조를 통해 단순히 기술을 사용하는 것을 넘어 '서비스 경계와 책임을 고민하는 훈련'이 됐다. 그리고, 규모가 작았던 만큼 마이크로서비스의 분리는 오히려 관리 복잡도를 증가시켰다. 하지만, 학습 단계였기 때문에 이러한 구조를 도전해본 것에 의의가 있다고 생각한다. 또한 이번 경험을 통해 MSA구조와 모놀리식 구조를 언제 사용하면 좋을지에 대해 많은 생각을 할 수 있게 됐다.
마지막으로 성능 개선을 위해 회원가입과 로그인 쪽에서 Redis를 활용하고, ElasticSearch를 활용해보고 싶다.