본문 바로가기

📕 Spring Framework/Spring Project44

OutBox Pattern 을 활용한 메일 전송 서비스 개발 [At Least Once] 스프링에서 메일 전송은 정말 간단하게 구현할 수 있다. JavaMailSender 로 말이야. 단순히, 메일만 전송하는 함수만 구현하면 끝일까? 물론 상황에 따라 간단한 구현이나, 복잡한 구현이 나눠져야 한다. 실 서비스에서는? 메일로 전송해야 하는 데이터 중요도에 따라 다르겠지만, 아무래도 메일을 수신하는 클라이언트 입장에서는 서버 장애 때문에, 메일 수신이 안 될 경우 매우 당황스러울 것이다. 즉, 적어도 한번 전송 (At least once) 를 만족하는 Eventually Consistency 를 구현해야 하는 것은 메일 전송 서비스에서 기본적으로 다뤄져야 할 사항이다. 일례로, 분산 서버 환경에서는, 알림 서비스만을 다루는 애플리케이션이 존재하는데, 이때 outbox 패턴이라는 것을 사용하여 구.. 2023. 4. 20.
[리팩토링] 도메인 모델 중심 Clean Architecture 로의 리팩토링 프로젝트를 수도 없이 리팩토링했다. 보다 더 객체지향적인 코드를 작성하기 위한, 유지 보수가 쉬운 코드를 작성하기 위한, 더 작은 객체를 위한 코드를 계속해서 고민하고 구조를 변경했다. 지난 달부터 해서 소프트 웨어 아키텍처에 관해서 관심이 생겼다. 클린 코드를 추구하다 보니 자연스럽게 설계적 고민으로 귀결되었다. 원티드 백엔드 챌린지를 하며 알게된 클린 아키텍처, 도메인 주도 설계 철저 입문, 도메인 주도 설계로 시작하는 마이크로 서비스를 읽어가며, 내가 구성해오던 소프트웨어 설계의 큰 전환점을 맞이하게 되었다. 단순히 예제 프로젝트만을 만드는게 아닌 본 프로젝트에 이를 적용시켜보기로 결정했다. MSA 는 오버 엔지니어링이라 판단했고, 모노리스 구조이지만 최대한 도메인 별 분리가 된 상위 바운디드 컨텍.. 2022. 12. 12.
[이슈] Pageable test 관련 에러 💡문제 API Controller를 테스트 하는데 잘 성공하던 테스트가 계속 실패한다. org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException: No primary or single unique constructor found for interface org.springframework.data.domain.Pageable 테스트 코드 mockMvc.perform(get("/api/v2/users") .param("page", String.valueOf(page))) .andExpect(status().isOk()) .andE.. 2022. 11. 23.
[Refactor] 패키지 구조와 의존성 두 번째 프로젝트의 코드 작성이 거의 끝났고, 테스트 코드 작성을 앞두며 코드 리뷰를 받았다. 가장 큰 골자는 아무래도 참조 관계이다. 패키지 구조를 Layered에서 약간의 DDD(애매하지만 ㅎㅎ) 를 곁들인 구조로 변경했다. 그 과정에서 패키지 간 의존성에 대해서 고민해보고 작명하는 것과 설계하는 시간이 정말 오래 걸렸다. 코딩을 공부하면 할 수록 작은 것에 시간을 오래 들이게 되는 걸 느낀다. 어제는 패키지 이름을 짓는데 반나절이 걸렸다. 회사에서는 변수명 짓는 걸로도 회의를 한다고 하니 약간 실감이 나기도 한다. 이렇게 디테일하게 채워나가면 그 만큼 내 실력이 된다고 믿습니다. 최상위 구조 auth : 인증, 인가 처리 스프링 시큐리티 이용 스프링 컨테이너까지 도달하지 않는 필터 위주이기 때문에 .. 2022. 10. 14.
[Redisson] 트랜잭션 문제 발생 및 해결 지난 포스트 [Redisson]을 이용한 분산 Lock 구현 & 동시성 문제 해결 내 프로젝트의 Payment를 개발하면서 가장 기본 중에 기본이 되는 문제를 직면했었다. 그것은 바로 동시성 문제! 스프링부트의 내장 서버는 기본적으로 톰캣, 언더토우 등등의 WAS로 돌아가는데 이 sweeeetgoguma.tistory.com 지난 포스트에서 Redisson을 이용하여 동시성 문제를 해결하는 코드를 구현했다. 프로젝트 리팩토링이 거의 끝나가 조회 API를 구체화하여 몇 개 추가하던 도중, 스레드 100개의 동시 요청을 직접적으로 받는 과정을 확인하고 싶어졌다. 그래서 실험해봤다. 결과는?? 처참하다.. 무엇이 문제였을까 트랜잭션 처리가 씹혔다. @GetMapping("/test") public void t.. 2022. 10. 1.
[Redisson]을 이용한 분산 Lock 구현 & 동시성 문제 해결 내 프로젝트의 Payment를 개발하면서 가장 기본 중에 기본이 되는 문제를 직면했었다. 그것은 바로 동시성 문제! 스프링부트의 내장 서버는 기본적으로 톰캣, 언더토우 등등의 WAS로 돌아가는데 이 WAS는 멀티스레드 기반으로 동작한다. A라는 상품 (재고 3개) 을 [가]군이 2개 구매하려 한다. 동시에 [나]군이 2개 구매하려 한다. 미세하게 나마 0.00001초의 차이가 있을 수 있다. 결국 각각의 스레드가 같은 상품의 재고를 조회한다. 원래대로라면 한 명은 못 사야 정상이다. 위 문제를 해결하기 위한 방법이 뭐가 있을까? 1. Synchronized 자바로 해결하는 방법이다. Thread-Safe 하기 때문에 매우 좋아보이나, 서버가 증설될 경우 의미가 없어진다. 2. Database Lock D.. 2022. 9. 27.
결제 API 리팩토링 - [2] (feat. WebClient) https://sweeeetgoguma.tistory.com/entry/%EA%B2%B0%EC%A0%9C-API-%EB%A6%AC%ED%8C%A9%ED%86%A0%EB%A7%81-1-feat-%EC%A0%84%EB%9E%B5-%ED%8C%A8%ED%84%B 결제 API 리팩토링 - [1] (feat. 전략 패턴) 결제 API를 리팩토링 시작하며 외부 API를 연동 부분에 대해서 생각해봤다. 기존에도 카카오페이를 이용했었고, 지금도 카카오페이를 이용할 것이지만, 추가적으로 다른 결제 API를 연동할 수 있 sweeeetgoguma.tistory.com 지난 포스팅에 이어서 작성하겠습니다~ 실제 결제 API를 호출하기 위해서는 httpClient 기반의 모듈이 필요하다. 기존에는 동기방식, 멀티스레드를 이용.. 2022. 9. 22.
결제 API 리팩토링 - [1] (feat. 전략 패턴) 결제 API를 리팩토링 시작하며 외부 API를 연동 부분에 대해서 생각해봤다. 기존에도 카카오페이를 이용했었고, 지금도 카카오페이를 이용할 것이지만, 추가적으로 다른 결제 API를 연동할 수 있을 만한 상황을 생각해봤다. 스프링을 처음 공부하기 시작할 때 읽었던 책인 개구리 (스프링 입문을 위한 뭐시기..) 책에서 스프링에서 사용하는 다양한 디자인 패턴들을 알게 되었다. 그 때는 디자인 패턴이란 것에 대해 감이 잘 오지 않았는데, 직접 적용할 기회와 상황이 없었기 때문이라고 생각해본다. 계속 면접 질문 대비해 앵무새처럼 달달 외우고 다니던 도중 직접 적용할 기회가 딱 생겼고, 객체지향 개발 2원칙인 OCP에 찰떡일 것이라는 머리 속의 외침이 울렸다. 그대로 적용해보았다. 기존 플로우 컨트롤러 서비스(카카.. 2022. 9. 20.
동시성 조회 문제 해결 및 성능에 관한 고민 [Lock, Queue, Redis] 주문 건에 대한 상품 재고 파악 동시성 관련 이슈에 대해 고민한 하루다. 프로젝트 리팩토링을 시작하며 지난 도메인들은 기본 crud API만을 다루었다. 5일동안 JPA 강의들을 수강하며 본격적으로 주문 및 결제 API 리팩토링에 다시 착수했다. 아무래도 프로젝트의 토픽이 쇼핑몰이니 주문 및 결제 파트에서 단순 CRUD가 아닌 핵심 비즈니스를 고려하고 싶어, 외부 결제 API 및 디자인 패턴을 적용한 깔끔한 코드들을 고려하며 작성하는 중이다. 대략적인 틀을 만든 뒤, 본격적으로 주문을 구현하던 중, 동시성 이슈 문제에 직면했다. 기존 동시성 문제 해결 방법 MSA를 고려했기에, 데이터 정합성 문제를 해결하기 위해 Outbox pattern을 이용중이었다. 이 방식을 통해 상품 동시성 문제를 해결했었다. .. 2022. 9. 14.
객체 간 매핑을 위한 MapStruct 사용 방법 기존 프로젝트에서 Dto Entity를 매핑할 때 model mapper 라이브러리를 사용했었다. 편하게 사용할 수 있었지만 내부적으로 리플렉션을 이용하기 때문에, 성능 상 문제가 있다. 이번에는 많이들 추천하는 Map Struct를 사용해봤다. 적용하면서 자잘한 문제들이 있었는데, 내가 겪은 문제점들에 대한 해결 방법들을 정리해보겠다. https://mapstruct.org/documentation/dev/reference/html/ MapStruct 1.5.2.Final Reference Guide If set to true, MapStruct in which MapStruct logs its major decisions. Note, at the moment of writing in Maven, al.. 2022. 8. 29.
DB 수정 & jpa 세팅 프로젝트의 전반적인 리팩터링을 다시 시작하며, 기존 mybatis를 이용했던 것을 그대로 옮겨왔다. 하지만 SQL Mapper를 이용한 설계 특성상 객체 지향적인 코드의 작성이 어려웠고, 또 기존 DB 설계의 문제도 있다는 것을 알게 되었다. DB의 전반적인 수정과 더불어, JPA를 이용해 다시 리팩터링을 해보기로 결정을 내렸다. 그 수정과정과 JPA 세팅 방법을 나열해보겠다. https://github.com/GroovyArea/My-ChickenBreast-Shop GitHub - GroovyArea/My-ChickenBreast-Shop: shop api with spring boot shop api with spring boot . Contribute to GroovyArea/My-ChickenB.. 2022. 8. 8.
코드 리팩토링 [1] 지난 1주일간 기존 프로젝트의 리팩터링을 위해 새로운 저장소를 생성했다. 아키텍처 부분 설계를 거의 2, 3일은 한 것 같다. 아직 수정이 필요하겠지만, 항상 고민해보자. 기존 프로젝트는 multi module로 진행했지만, 완벽한 멀티 모듈 프로젝트 이진 않았다. 모놀리틱으로 갈지, MSA를 고려해 모듈간 분리를 할지가 계속 고민된다.. 확장성을 위해 모듈, 패키지간 의존성 분리를 틈틈이 고려해봐야겠다. 기존 작성 코드를 옮기며 조금 더 클린한 객체지향적인 코드로 리뷰어님의 피드백을 통해 수정해나갔다. 많이 알고 있었다고 생각한 부분에서도 헛점이 있었고, 전혀 알지 못했던 디테일한 부분도 알아나가는 중이다. 인증 및 인가 부분은 기존 프로젝트에서는 손수 구현했지만, 이번에는 Spring Security.. 2022. 8. 3.
리팩토링 계획 오랜만에 블로그에 글을 쓴다. 지난 며칠 동안 프로젝트를 배포하기 위해 AWS 망구성을 하고, 프로젝트를 빌드하며 배포까지 시켰다. 부하 테스트를 앞두고, 좋은 기회를 얻어 코드 리뷰를 받게 되었다. 결론은, 이 상태로 부하 테스트를 진행하는 의미가 없을 정도로 심각한 문제가 많았다. 프로젝트를 시작하며 아쉬운 코드 작성 부분도 많았고, 궁금증도 많았지만, 나머지 주관적인 판단하에 깔끔한 부분은 나름 괜찮게 작성을 했다고 생각했었다. 아직 고칠게 많았고, 배울게 많았고, 몰랐던 것이 많은 나였다. 이런 리뷰를 들을 때마다 나는 아직 한참 멀었구나. 공부 기간 대비 많은 성장을 거두었다고 생각했는데, 내가 욕심이 많은 건지. 사실은 기간 대비 성장치가 평균치였던 건지. 무기 해진다. 너무 급한가? 그럼에도.. 2022. 7. 28.
리팩터링 「Authentication(인증)」 태어나서 처음 회사에 지원했다. 서류를 여러 군데 넣었다. 벌써 서류 탈락만 3번째이다. 서류 탈락이 이런 기분이구나...ㅎㅎ 회사 기준에 부합하지 않는 내 실력과 결과물 탓이지 뭐. 더 열심히 다듬어야겠다. 서류를 다듬다가 인증과 인가 구현 중 이슈를 작성했던 부분이 눈에 띄었다. 인증과 인가... 음... 인가는 애노테이션을 이용해 인터셉터로 구현한 명확한 근거가 있었다. 인증은 좀 애매했다. JWT 토큰을 인증하는 부분은 굳이 인터셉터까지 도달할 필요가 없다. 그래서 인증 작업을 인터셉터에서 필터로 리팩토링을 진행했다. 필터(Filter)란? HTTP 요청과 응답을 거른 뒤 정제할 수 있는 기능이다. Servlet Container 단에서 동작한다. 스프링 범위 밖에서 처리된다. Dispathcer.. 2022. 7. 11.
스프링 부트 소나큐브(SonarQube) 적용 + PostgreSql 갈수록 쉽지 않다. 프로젝트를 만들어 가는 과정에서 코드를 작성하는 부분은 극히 일부 과정임을 깨달았다. 오히려 코드를 작성하는 시간이 더 그립다. 리팩터링과 기술 적용 및 버전 맞춤 수정에 시간을 더 쏟는 요즘이다. 클린 한 코드를 위해 손수 리팩터링을 할 수 있지만, 정적 코드 분석 도구란 것이 있다고 한다. 대표적으로 SonarQube를 많이 사용한다고 하는데 이를 적용해 보는 시간을 가졌다. 정말 오래 걸렸고, 정확하진 않을 수 있지만 나름대로 적용했던 과정을 정리해보겠다. (틀린 부분이 있으면 무한한 댓글 감사히 받겠습니다!) 이것이 완료된 후 AWS lightsales, ec2 적용 여부를 판단해보아야겠다. 정적 분석 도구 코드의 품질에 대해 고려할 때 필수적으로 사용하는 도구이다. 지속적인 .. 2022. 7. 5.
반응형