지난 주 Redis 에서 Transaction 을 주제로 포스팅 했는데, 오늘은 해당 트랜잭션이 잘 동작하고 있는지 테스트를 작성해 보았다. 트랜잭션에서 가장 중요하게 다뤄져야 할 부분은 원자성이므로, 테스트 대상은 트랜잭션 중간에 예외가 발생했을 시 롤백의 여부가 되겠다. 강제로 예외를 발생시키는 부분을 코드 중간에 넣어서 테스트를 해봐도 되지만 그렇게 되면 테스트 시에는 기존의 멀쩡한 비지니스 코드를 건드렸다가 배포시에는 다시 해당 예외 코드를 지워야 하는 번거로움이 생기며, 테스트의 자동화라는 목적도 무색해진다. 어떻게 기존의 코드를 건드리지 않고 예외를 던지게 할 수 있을까? 를 고민하다가, Decorator 패턴 / Proxy 패턴에서 그 답을 찾았다.Decorator 패턴 / Proxy 패턴D..
개발
어제 토비의 스프링 5장 챕터를 읽으면서 Transaction 의 원자성 에 대해서 처음 알게 되었다. 사실 Transaction 을 선언함에 있어서 가장 중요하고 핵심적인 이야기로 보이는데, 이걸 이제서야 개념적인 지식으로 습득했다는 데서 다소 충격적이었다. 가끔씩 Service 단에 Transaction 이 진행되는 메서드를 작성하면서 뚜렷한 이유는 없지만 왠지 모를 불안감, 다소 완성도가 떨어지는 듯한 느낌이 들곤 했는데, 바로 원자성에 대한 보장이 없다는 점이 그 원인임을 알게되었다. 이걸 깨닫고 TIL 에 Transaction 의 특성 4가지를 정리해서 아주 그럴듯하게 정리해놓고 싶었지만 솔직히 원자성 이외의 특성들에 대해서 잘 알지도 못하면서 떠드는 것은 기만같다. 그래서 간단하게 원자성에 대..
개발자는 코드를 작성할 때 언제나 런타임 시 발생하는 예외 상황에 대해 고려 해야한다. 코드가 항상 의도대로 동작하는 것은 아니기 때문이다. 예상하지 못한 상황들을 적절하게 핸들링 함으로써 원하는 대로 로직이 작동하지 않은 경우에도 어플리케이션을 올바르게 작동하게 한다거나, 아니면 예외를 의도적으로 발생시켜 여러가지 시나리오를 핸들링 하게 만들 수 있다. 1. RestControllerAdvice 예외 처리를 위해서는 기본적으로 RestControllerAdvice 어노테이션을 사용 할 수 있다. RestControllerAdvice 어노테이션은 Controller 계층의 예외를 전역적으로 처리하는 AOP 기술의 일종이다. Advice 라는 단어에서 프록시 객체를 생성하거나 바이트 코드 조작하는 AOP ..
이전 글 : 채팅 서비스에 Redis 도입 (1) [ https://techforme.tistory.com/16 ] 이전 글 : 채팅 서비스에 Strategy Pattern 적용 [ https://techforme.tistory.com/15 ] 구독 정보 Repository 로서 Redis 도입 이전 글에서 채팅 서비스에 Message Broker 로서 Redis 를 도입했던 글을 썼었는데, 이번에는 구독 정보 Repository 로서 Redis 를 적용한 부분에 대해서 쓰려고 한다. 구독 정보 Repository 는 이전에 인메모리 캐시를 이용한 ConcurrentHashMap 으로 구현하면서 Strategy 패턴을 적용했었는데, 그렇기 때문에 아래와 같이 인터페이스만 구현하고 yml 파일 설정만 변경..
파사드 패턴이란? 파사드(Facade)는 '건축물의 외관, 겉면'을 뜻하는 단어로, 프랑스어(façade)에서 건너온 단어이다. 원래 어원은 라틴어에서 얼굴(Face)을 뜻하는 facies(파시에스) 라고 하는데 건출물 외관 = 얼굴 로 이해해볼 수 있다. 디자인 패턴에서 말하는 파사드 패턴은 내부의 코드를 가려놓고 전면에 단순화된 인터페이스를 내세우는 구조가 마치 내부의 인테리어나 구조를 덮어놓은 건축물의 외벽과 유사하다는 데서 차용되었다. 여러 클래스들을 직접 가져와서 쓰게 되면 가독성도 떨어지고 의존관계도 복잡해지니, 하나의 단순화된 클래스를 만들어서 이를 쉽게 이용할 수 있도록 만드는 것이다. 아래 그림과 같이 말이다. 언뜻 듣기에 너무 쉬운 개념이라서 '이걸 따로 배울 필요가 있었나?' 라는 생..
오늘은 너무 유명한 N+1 문제와 이와 관련한 EntityManager 의 getReference 라는 메서드를 이야기 하려고 한다. 사실 N+1 이 발생하는 원인이나 해결책은 간단한데, 조금 애매한 부분이 있어서 혼란을 겪었다. N+1 문제 N+1 문제는 자바 ORM 에서 객체 내부의 연관된 객체에 접근하려고 할때 발생한다. DB에서 객체를 로드해 올때 객체의 필드에 다른 엔티티가 포함되어 있는 경우, ORM 은 해당 엔티티의 정보를 전부 가지고 오지 않는다. (select query 를 생각해보면 당연하다. 연관된 다른 테이블의 자료는 조회해오지 않는다.) 그 대신 객체 행세(?)를 할 수 있는 프록시 객체(위임 객체)를 넣어주는데, 이 프록시 객체는 껍데기만 가지고 있을 뿐이고 변수에 데이터를 가지..
채팅서비스의 메세지 브로커 및 구독 관리에 Redis 를 적용하였다. (+ RefreshToken 저장) 이번 프로젝트를 진행하면서 손에 꼽을 정도 이해하기 힘들었던 주제였던거 같다. 어떤 구조로 동작하는 것인지 도무지 감이 안와서 코드 한참을 들여다 보고, 실제로 실습을 진행해 보고서야 느낌을 알게 됐다. 솔직히 그렇게 복잡하거나 어려운 내용은 아닌데 뭐랄까 속시원하게 설명해주는 레퍼런스가 없던게 문제 같다... 아닌가... 내 배경지식의 탓일 수도 있고. 여튼 시간이 이틀 꼬박 걸렸다. (사실 여전히 내가 올바르게 적용을 한 것인지도 잘 모르겠다.) 메세지 브로커로서 Redis 의 역할 메세지 브로커는 브로커(broker, 중개인) 라는 단어의 의미 그대로, 메세지를 발행한 곳에서 구독한 곳으로 전달..
1. 채팅 서비스의 Subscription 정보 관리 채팅 서비스에서 메세지를 주고 받는 과정은 특정 토픽에 대한 발행과 구독이라는 행위로 이루어 진다. 채팅 서비스를 이용하는 유저가 서버에 메세지 전송을 요청하면, 채팅 서버에서는 메세지를 해당하는 토픽에 발행한다. 발행된 메세지는 해당 토픽을 구독하고 있는 모든 유저에게 전송된다. 이러한 송신 → 수신 과정을 Message Broking 이라고 한다. 전송이 요청된 메세지를 올바르게 전달하기 위해서는 어떤 유저가 웹소켓 서버와 연결되어 있고, 또 해당 페이지를 구독하고 있는지를 알고 있어야 하기 때문에 채팅서버에서는 구독 정보를 저장해 두어야 한다. 스프링 웹소켓은 자체적인 Message Broker 가 내장되어 있어서 이러한 구독 정보 관리를 관리한..
지난 글 마지막에 Enum Type 의 필드에 대해서는 1. Enum Type 은 일반적인 String 또는 Long, Double 같은 클래스와 다르게 별도의 애너테이션을 만들어야 한다. 2. 아예 엉뚱한 값이 들어오면 직접 구현한 Validator 가 작동하기 전에 Parsing 과정에서 Exception 이 터지기도 한다. 라고 이야기 했는데 이 두 문제를 해결하여 적절한 에러메세지를 반환해 보았다. 일단 2번 문제에 대해서 이야기하자면 Serialize 와 Deserialize 의 개념에 대해서 먼저 정리를 해야한다. (직렬화 / 역직렬화) 위 개념은 객체나 데이터를 더 낮은 수준의 데이터 형태로 전환 하거나 그 반대 과정을 말한다. 더 낮은 수준의 데이터라는 건 가만히 생각해보면 조금 모호한 개..
Pull Request 내용 하 글쓰다가 날라가서 쓸 맛이 안난다 Issue / PR 내용만 복붙하고 어떻게 구현 했는지 써야겠다. Issue 내용 요청에 대한 유효성 검사(Validation) 구현 #21 현재 Web 에서 API 로 향하는 요청에 대하여 Front-end 에서의 유효성 검사가 수행되고 있으나 Postman 등 다른 경로를 통해 들어온 요청에 대해서는 해당 유효성 검사를 거치지 않으므로 서버에서 별도의 Validation 을 수행하여 예기치 못한 오류가 발생하지 않도록 해야합니다. (예를 들어 특정 좌표 및 반경을 기준으로 창고를 조회하는 api 에서 반경 값을 아주 큰 수로 지정하게 되면 DB에 저장된 모든 Storage 를 서버로 가져오게 되므로 아주 큰 부하를 야기할 수 있습니다...