스프링

    [스프링부트] 교착 상태 테스트 & 해결 과정

    [스프링부트] 교착 상태 테스트 & 해결 과정

    실제 운영하고 있는 서비스는 아니라 교착 상태가 발생한 건 아니지만, 교착 상태를 일으키는 테스트 코드를 작성하고 실험해봤다. synchronized, 비관적 락, 낙관적 락 모두 시도해봤지만 테스트가 계속 실패해서 디버깅해봤더니 원인은 락을 잘못 걸었다거나, 커넥션 풀 개수가 적어서가 아니었다. 엔티티 지연로딩 때문이었다. 그 메소드에 예외 잡는 코드를 써놓지 않아서 디버깅하기 전까지 전혀 모르고 있었다. 역시 테스트는 중요하다. 이 과정에서 알아낸 것들을 살펴보겠다. 1. 상태 변경 메소드 @Transactional public void createPaymentNMessage(PaymentsCompleteDto dto, Users user, Gift gift) { IamportPayment payme..

    [디자인패턴] 스프링에서 옵저버 패턴은 어떻게 사용될까 & ApplicationEventPublisher 파헤치기

    [디자인패턴] 스프링에서 옵저버 패턴은 어떻게 사용될까 & ApplicationEventPublisher 파헤치기

    옵저버 패턴(observer pattern)이란 객체에 무슨 일이 생겼을 때 객체를 구독하고 있던 관찰자들에게 알림을 보내는 디자인 패턴이다. 목차 옵저버 패턴이란 스프링 - ApplicationEventPublisher 1. 옵저버 패턴이란 Subject가 관찰 대상, Observer가 관찰자이다. Subject의 상태에 변화가 있을 때 Observer 리스트를 순회하며 그 Observer들에게 알림을 보낸다. 2. 스프링 - ApplicationEvnetListener 2-1. ApplicationEventPublisher를 활용한 예 public interface NotificationEvent { public Notification createNotification(); } 여러 타입의 이벤트의 ..

    [디자인패턴] 스프링에서 전략 패턴은 어떻게 사용될까

    [디자인패턴] 스프링에서 전략 패턴은 어떻게 사용될까

    전략 패턴(strategy pattern)은 동적으로 알고리즘을 선택할 수 있는 디자인 패턴이다. 전략 패턴의 사용 사례 몇 가지 Comparator와 Collections.sort() 스프링 시큐리티 - AuthenticationProvider와 ProviderManager 스프링 시큐리티 - WebSecurityConfigurerAdapter와 SecurityBuilder 0. 들어가기 전, 전략 패턴이란? 재미없는 얘기부터 하겠다. Context, IStrategy 등 잘 와닿지 않는 일반화된 예시를 들어가며 전략 패턴이 무엇인지 설명할 것인데, 어쩔 수 없다. 일단 전략 패턴이 무엇인지, 어떻게 생겼는지는 알아야 하기 때문이다. class Context { IStrategy Strategy; vo..

    [스프링부트] 성능 테스트 & 튜닝 과정

    [스프링부트] 성능 테스트 & 튜닝 과정

    목차 아키텍처의 비효율성은 DB에 데이터 100개가 아니라 몇 만개쯤 있어야 드러난다고 한다. 그래서 테스트 데이터를 만 개 넣고 ngrinder로 성능 테스트를 해봤다. Mockaroo로 테스트 데이터를 만드는 법과 ngrinder 설치, 테스트하는 법은 따로 작성하겠다. 1. 테스트 데이터 삽입 1-1. 테스트 더미 데이터 생성 Mockaroo는 테스트 데이터를 복잡한 DB 구조에 맞게 생성할 수 있는 사이트이다. 외래키도 적용할 수 있다. 이렇게 필드에 적용할 수 있는 타입이 여러 가지 있어서 편하다. SQL DateTime 필드도 있어서 created_date 같은 필드도 문제 없다. 하지만 단점은 최대 1,000개까지만 만들 수 있다는 것이다. 1,000 개씩 10번 노가다하면 10,000개를 ..

    [스프링부트] 트랜잭션 때문에 애먹은 지점

    테스트코드를 쓰면서 트랜잭션 때문에 골이 아팠다. 이게 다 @Transactional을 안 쓰고 버텨서 그런 것 같다. 1) 여러 save를 하나의 트랜잭션으로 묶을 때 + nullable=false nullable=false와 여러 엔티티 save를 하나의 트랜잭션으로 묶는 것은 관계가 없어보이지만 있다. 예를 들어 내 경우에는, Payment와 Message 엔티티가 있고 Message가 Payment를 nullable=false로 참조하고 있었다. 그리고, Payment를 저장한 후에 Message를 저장하는 로직이 있었다. @Service public class IamportMessageService { private final IamportPaymentService iamportPaymentSe..

    [스프링부트] 통합 테스트 작성 과정

    힘들었다. 처음엔 어떻게 써야할 지 알 수 없었다. 지금도 마찬가지긴 하지만. 그땐 더더욱 암흑이었다. 그냥 각 엔티티 save 하는 것만 테스트 했고 그것만 해도 힘들었다. 이런저런 준비 과정이 필요하고 어떤 라이브러리의 함수를 써야할 지도 몰랐다. 그런데 테스트 프레임워크 사용법을 모르는 것보다 방법론을 모르는 게 더 영향이 컸다. 그래서 다른 사람들의 깃허브를 보고 참고하고, 라는 책을 읽었다. 이 책이 도움이 많이 되었다. 그런데 아직 단위 테스트는 어떻게 써야할 지 감을 못 잡았고 통합 테스트만 썼다. 1) 동작 단위로 테스트 & 외부 의존성만 목킹 책에서는 테스트 방식에 있어 고전파, 런던파가 있다고 소개한다. 런던파가 빡세게 목킹하고, 클래스 단위로 쪼개서 테스트해야한다고 주장한다. 고전파는..

    [스프링 해부] HandlerAdapter가 컨트롤러 메소드를 대신 호출하는 과정 해부2

    [스프링 해부] HandlerAdapter가 컨트롤러 메소드를 대신 호출하는 과정 해부2

    이전 글에는 invokeHandlerMethod()까지 살펴봤다. 현재 호출되어야 하는 메소드는 UserController의 signup() 메소드이다. invokeHandlerMethod()부터 이어지는 흐름은 다음과 같다. invokeHandlerMethod() - RequestMappingHandlerAdapter HandlerMethod를 호출 invokeAndHandle() - ServletInvocableHandlerMethod returnValueHandler로 리턴값 처리 invokeForRequest() - InvocableHandlerMethod argumentResolver로 인자 처리 후에 메소드 호출 모두 invoke로 시작한다. 2번부터 시작하겠다. 2. invokeAndHand..

    [스프링부트 리팩토링] 패키지 구조 조금 더 개선하기

    DDD를 끝까지 밀어붙여 헥시고날 아키텍처로 뜯어고칠 자신이 없어서 관두긴 했지만, DDD의 Aggregate 관련 규칙을 적용하는 것 정도는 괜찮을 것 같아서 리팩토링을 시작했다. 그것도 그렇고, 저번에 올린 게시글의 도메인형 패키지 구조도를 보면 약간 이상한 점이 있다. 나는 사실 다른 사람의 깃허브를 보고 패키지 구조를 바꿨던 거라, 인프라(인프라스트럭처, infrastructure)가 뭔지도 몰랐다. 1. 변경 전 패키지 구조의 문제 최상위 모듈에 infra와 modules 두 가지가 있다. 각종 설정 파일(XXXConfig), 공통 설정, 유틸 관련은 모조리 infra 패키지에 몰아넣었고 비즈니스 로직은 modules에 몰아넣었다. 📂 infra 📂 config 📂 jwt 📝 SecurityCo..

    [스프링부트 리팩토링] 패키지 구조 변경

    처음 프로젝트 할 땐 패키지 구조에 크게 신경을 안 썼다. 그런데 도메인이 많아질수록 너무 불편해서 뭔가 이상하단 생각이 들었고 깃허브에 있는 다른 사람들의 프로젝트를 보니까 도메인을 대분류로 삼아 도메인의 하위에 컨트롤러, 서비스, 레포지토리 등을 두더라. 그래서 일단 따라했다. 우선 패키지 구조에는 크게 두 종류가 있다. 패키지 구조 종류 두 가지 계층형 패키지 구조 도메인형 패키지 구조 1) 계층형 📂 config 📂 domain 📄 User 📄 Gift 📂 dto 📂 controller 📄 UserController 📄 GiftController 📂 service 📄 UserService 📄 GiftService 📂 repository 📄 UserRepository 📄 GiftRepository ..

    [스프링부트 리팩토링] 서비스에서 서비스를 호출해도 될까?

    서비스에서 다른 서비스를 주입받아 사용하는 경우 순환참조가 자주 발생한다. 순환참조뿐만 아니라 서비스는 보통 하나의 리포지토리를 책임진다는 본래 의도도 흐려진다는 문제가 있다. 아예 순환참조가 일어나지 않게, 그리고 서비스에서 서비스를 호출하게 하지 않고 하나의 책임만 맡도록 개선하려고 한다. 도메인 서비스와 응용 서비스를 나누는 방법을 다룬 글도 봤는데 그쪽은 DDD의 애그리거트와 관련된 전략이라 이 글에서는 다루지 않는다. 서비스에서 다른 서비스를 호출하는 경우의 문제점 순환참조가 자주 발생한다. 책임이 불분명해진다. 하나의 서비스가 포함하고 있는 의존성이 여러 개이다. 테스트할 때도 불편해진다. 예시) User : Event = 1 : N 즉, 이벤트 엔티티가 FK로 유저 엔티티를 참조하고 있다. ..