본문 바로가기

Programing/Framework

(79)
Kotlin DSL Gradle: 멀티 모듈로 변경하기 단일 모듈 기반의 프로젝트 spring initializr 에서 프로젝트를 만들면 기본적으로 단일 모듈 기반의 프로젝트를 생성한다. 이 구조는 단순하고 만들기 쉽지만 단점도 있다. 핵심 비즈니스 구현을 하는 도메인 영역과 세부사항의 일종인 구현 기술의 코드가 섞이게 되기 때문이다. 실무를 하면서 일종의 기술 영역인 JPA의 Entity 가 도메인 영역인 서비스를 통과해 Controller 까지 전달했던 것을 본 적이 있다. 물론 자바나 코틀린에서는 패키지를 구분하여 모듈을 분리할 수 있는 구조를 제공한다. 하지만 이것은 구조화적인 것으로 의존성에 대해 직접적인 통제를 할 수 없다. 페리페리크 안티 패턴(Périphérique anti-pattern) 헥사고날 아키텍처 - 혹은 '포트와 어댑터' - 라는 ..
DataIntegrityViolationException Sentry 로 알림이 오면 팀에서는 습관적으로 ignore 처리를 하는 것을 발견했다. 특히 배포 직후에는 이런 ignore가 빈번했는데 새로운 버전이 배포가 되면 기존의 custom ignore가 무효화가 되는 것 같았다. 백로그의 티켓 중 내부 개선 에픽이 붙어있는 묵혀놓은 티켓을 발견했다. 바로 "정상적인 케이스의 알람을 받지 않는다."이다. 위의 알람의 경우 사용자가 입력을 짧은 시간에 여러번 하여 save 명령이 두 번이 된 경우에 주로 발생했다. DB에는 UC(Unique Constraint) 조건이 달려있었기에 나중에 요청이 온 쿼리가 수행이 되지 않는다. 버튼을 클릭 후 disable로 변경시켜 입력을 두 번하는 것을 막는 것이 근본적인 방향이겠지만 해당 UI는 다른 팀이 담당하고 있어서..
spring-boot 신규 프로젝트 BY spring initializr 회사에서 신규 프로젝트를 진행하게 되었다. 새 술은 새부대에 부으라는 말 처럼 spring initializr를 이용해서 새 프로젝트를 만들었다. 전에 N사에 면접을 봤을 때 어떤 조직장이 코틀린을 써봤냐고 물어본 적이 있었다. 당시 코틀린을 실제 업무 프로젝트에서의 경험이 없어서 사실대로 이야기 했는데 개인적으로 아쉬움이 남았다. 그래서 이번에는 신규 프로젝트 니 Java 대신 Kotlin 으로 해보았으면 바람을 반영했다. 그런데 Language를 Kotlin으로 선택을 하고 Gradle Project로 생성을 했더니 build.gradle이 아닌 build.gradle.kts 파일이 생성되었다. 넌 뭐냐 build.gradle.kts 검색을 해보니 이 형태가 Kotlin DSL 이라는 것을 찾을 수 ..
[스프링] MVC - @RequestBody 객체의 Setter가 필요한가? 주의: 이 글은 jackson-databind 2.8.11.11 기준으로 작성되어 있습니다! 버전에 따라 실제 구현 내용은 바뀔 수 있으니 참고용으로 읽기를 바랍니다. 3줄요약 1. Immutable 객체는 좋은 습관이다. 하지만 절대적인 최선이란 없고 최선의 실천방법(Best Practice)는 상대적이다. 2. Request 객체에 Setter가 없어도 값은 필드 주입이 된다. 3. 필드 주입의 경우 리플렉션에 의한 처리가 되어 Setter가 있는 경우보다 오버헤드가 있을 수 있다. 코드리뷰 코드리뷰를 하다가 getter만 존재하는 @RequestBody 객체를 보았다. (HTTP POST 요청) 불변에 대한 장점들이 많이 알려져 있기에 VO나 DTO 같은 객체는 불변으로 만드는 편이다. @Sette..
스프링 캐시 인터셉터 어노테이션 기반의 캐시를 종종 애용해주시는 우기님 덕분에 공부를 하게 되었다. 기회를 제공한 우기님께 감사를 드립니다. @Cacheable 어노테이션이 붙어 있는 메서드를 호출하게 되면 어떤 과정이 수행되어 캐시에 데이터가 저장되고 하는지가 궁금했다. 현상에 대한 디버깅을 통해 분석한 것이라 여러 방법 중에 하나일 수 있다. 디버깅을 하다보면 CacheInterceptor 클래스가 보이는데 아래와 같은 계층 구조로 되어 있다. 아래와 같은 MethodInterceptor 인터페이스를 구현하고 있기에 존재하는 메서드는 invoke 메서드 하나 뿐이다. @FunctionalInterface public interface MethodInterceptor extends Interceptor { Object in..
[spring] JSR-303 과 @Valid 과 @Validated Controller 에서는 요청바디에 대해서는 @Valid 라는 annotation을 붙이면 Bean Validation(JSR-303)기능을 수행해준다. 하지만 @PathVariable 에 대해서는 적용이 불가능하다. 만약 bean validation 을 통해 하고자 한다면 @Validated 을 Controller 클래스(타입)에 붙여주면 동작을 한다. @Valid의 경우 바인딩이 실패가되면 MethodArgumentNotValidException 을 발생시킨다. 하지만 @Validated 로 바인딩 validation 실패가 발생하면 ConstraintViolationException 예외가 발생하였다. javax.validation.ConstraintViolationException: null a..
[spring] URL path template에서 매핑된 값 구하기 인터셉터를 구현하다보니 URL 요청에서 template로 매핑된 부분의 값을 구할 필요가 있었다. 아래 코드에서 thisValue에 해당하는 부분이다. @GetMapping("/i/wanna/{thisValue}/really") public SomeResponse getSomeHanlder(@PathVariable String thisValue) { // ... 어떻게 구할까 고민을 하다가 @PathVariable 를 처리하는 PathVariableMethodArgumentResolver 에서 힌트를 얻을 수 있었다. package org.springframework.web.servlet.mvc.method.annotation; public class PathVariableMethodArgumentRes..
[spring] ServletWebRequest 생성 package org.springframework.web.servlet.mvc.method.annotation; public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean { @Nullable protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequ..