포스트

2023-02-09-TIL

2023-02-09-TIL

Today I Learned

Package by Layer vs Package by Feature

패키지를 나누는 두 가지 기준이다. package by layer는 controller, service, repository처럼 기술 계층별로 묶고, package by feature는 order, member처럼 기능(도메인)별로 묶은 뒤 그 안에 계층을 둔다. 계층별 구조는 처음 보기에 익숙하지만 기능 하나를 고치려면 여러 패키지를 오가야 하고, 클래스가 거의 다 public이 되어 패키지가 경계 역할을 못 한다. 기능별 구조는 관련 코드가 한곳에 모이고, 기능 밖으로 공개할 것만 public으로 두어 접근을 좁힐 수 있다.

  • https://www.youtube.com/watch?v=5OjqD-ow8GE

Multi Module Monolithic

하나의 저장소, 하나의 빌드 안에서 코드를 여러 모듈로 나누는 구조다. Gradle에서는 settings.gradle에 include로 하위 프로젝트를 등록하고, 다른 모듈을 쓰려면 implementation(project(":모듈명"))처럼 프로젝트 의존성을 선언한다. Spring 가이드 “Creating a Multi Module Project”는 실행 가능한 애플리케이션 모듈과, 애플리케이션이 아닌 라이브러리 jar 모듈을 나누는 가장 기본적인 예제를 보여 준다.

나누는 이유는 의존 방향을 빌드 수준에서 강제하고, API 서버, 배치, 어드민처럼 따로 배포하는 애플리케이션이 도메인 코드를 공유하게 하기 위해서다. 우아한형제들 기술블로그의 “멀티 모듈 설계 이야기”는 반대로 흔한 실패를 짚는다. 공통 코드를 common 모듈 하나에 몰아 넣으면 모든 애플리케이션이 그 모듈에 의존하게 되고, 수정 영향 범위가 시스템 전체로 퍼지며, 웹, JPA, Redis 같은 의존성이 필요 없는 모듈까지 끌려 들어간다는 것이다. 모듈은 역할과 의존성 기준으로 나누고, 하위 모듈의 공개 범위를 엄격히 관리해야 한다는 결론이다. Pulkit Gupta의 글은 이렇게 모듈로 나눈 모놀리스를 이후 마이크로서비스로 쪼갤 때 챙길 항목들을 정리한다.

  • https://pulgupta.com/2019/02/14/multi-module-monolithic-to-microservices/
  • https://www.youtube.com/watch?v=p7-AffMucBw
  • https://www.youtube.com/watch?v=4dO2Wa2fAYI
  • https://www.youtube.com/watch?v=AJW2FAJGgVw
  • https://www.youtube.com/watch?v=ipDzLJK-7Kc
  • https://www.youtube.com/watch?v=nH382BcycHc
  • https://www.youtube.com/watch?v=od6HHvuxgAo&list=PLJyMAT_Wb6qp9RiusxeWxvsfi7VeZtdcY
  • https://hyeo-noo.tistory.com/401
  • https://velog.io/@cha-sung-soo/Multi-Module-%EC%82%AC%EC%9A%A9-%EC%9D%B4%EC%9C%A0
  • https://letsmakemyselfprogrammer.tistory.com/60
  • https://dundung.tistory.com/243
  • https://velog.io/@sangwoo0727/Gradle%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-%EB%A9%80%ED%8B%B0-%EB%AA%A8%EB%93%88
  • https://ryumodrn.tistory.com/7
  • https://stackoverflow.com/questions/50106128/how-to-declare-common-dependencies-in-multimodule-gradle-project-on-parent-folde
  • https://docs.gradle.org/current/userguide/declaring_dependencies_between_subprojects.html
  • https://gwonsungjun.github.io/articles/2019-04/gradle_multi_module
  • https://tecoble.techcourse.co.kr/post/2021-09-06-multi-module/
  • https://spring.io/guides/gs/multi-module/
  • https://techblog.woowahan.com/2637/
  • https://jojoldu.tistory.com/123
  • https://velog.io/@soyeon207/%EC%8A%A4%ED%94%84%EB%A7%81-%EB%B6%80%ED%8A%B8-%EB%A9%80%ED%8B%B0-%EB%AA%A8%EB%93%88-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EB%A7%8C%EB%93%A4%EA%B8%B0
  • https://cjw-awdsd.tistory.com/55

Hexagonal Architecture

Alistair Cockburn이 제안한 Ports and Adapters 패턴의 다른 이름이다. 그가 밝힌 의도는 애플리케이션이 사용자, 다른 프로그램, 자동화 테스트, 배치 스크립트 중 무엇에 의해서든 똑같이 구동될 수 있고, 실제 운영 장치나 데이터베이스와 떨어진 상태로 개발하고 테스트할 수 있게 하는 것이다. 애플리케이션 코어는 포트(인터페이스)만 정의하고, 웹 컨트롤러나 JPA 저장소 같은 기술 세부 사항은 그 포트에 끼우는 어댑터로 바깥에 둔다.

  • https://www.youtube.com/watch?v=vwgNI9w_bsQ
  • https://www.youtube.com/watch?v=MKfSLrwLex8

DTO in Inner Static Class

요청과 응답마다 DTO 클래스를 따로 만들면 파일이 금방 많아진다. 그래서 MemberDto.Request, MemberDto.Response처럼 관련 DTO를 한 클래스 안의 static nested class로 모으는 방식이 쓰인다. 참고한 글 중 하나는 도메인 클래스 안에 DTO를 넣는 예까지 보여 주지만, 그러면 도메인이 표현 계층의 형식을 알게 되므로 별도 DTO 클래스 안에 모으는 편이 의존 방향상 깔끔하다. static이어야 바깥 클래스 인스턴스 없이 생성할 수 있고, Jackson 같은 라이브러리가 역직렬화할 때도 문제가 없다.

  • https://velog.io/@ausg/Spring-Boot%EC%97%90%EC%84%9C-%EA%B9%94%EB%81%94%ED%95%98%EA%B2%8C-DTO-%EA%B4%80%EB%A6%AC%ED%95%98%EA%B8%B0
  • https://jaehoney.tistory.com/157?category=983083
  • https://dev-coco.tistory.com/138
  • https://unluckyjung.github.io/dev/2022/02/20/Dto-InnerClass/

DTO

Martin Fowler의 정의로 DTO(Data Transfer Object)는 메서드 호출 횟수를 줄이기 위해 프로세스 사이에서 데이터를 실어 나르는 객체다. 원격 호출은 비싸니 한 번에 많은 데이터를 담아 보내자는 것이 출발점이고, 직렬화 방식을 DTO 안에 가둔다는 장점도 있다. VO(Value Object)는 다른 개념이다. 식별자가 아니라 값으로 동등성을 판단하는 객체이고, Fowler는 별칭 문제를 피하려면 값 객체를 불변으로 만들라고 한다. Tecoble 글은 둘이 혼동되는 이유로 『Core J2EE Patterns』 초판이 데이터 전송 객체를 VO라고 불렀다가 2판에서 TO로 고친 일을 든다.

  • https://blog.scottlogic.com/2020/01/03/rethinking-the-java-dto.html
  • https://tecoble.techcourse.co.kr/post/2021-05-16-dto-vs-vo-vs-entity/
  • https://www.adam-bien.com/roller/abien/entry/value_object_vs_data_transfer
  • https://matthiasnoback.nl/2022/09/is-it-a-dto-or-a-value-object/
  • https://wook-lab.tistory.com/16
  • https://www.baeldung.com/java-pojo-javabeans-dto-vo
  • https://wildeveloperetrain.tistory.com/101

Pagination in JPA

Spring Data JPA의 JpaRepository는 PagingAndSortingRepository를 상속하므로, 저장소 메서드가 Pageable을 받고 Page<T>를 돌려주게 하면 페이지 번호, 크기, 정렬이 쿼리에 반영된다. Page는 전체 개수를 함께 알려 주기 때문에 count 쿼리가 추가로 실행된다는 점을 알아 둔다.

  • https://cheese10yun.github.io/spring-jpa-best-12/

Java Executable

java.lang.reflect.Executable은 Java 8에서 생긴 추상 클래스로, Method와 Constructor의 공통 기능(파라미터 타입, 예외 타입, 애너테이션 조회 등)을 모은 상위 클래스다. 리플렉션 코드에서 메서드와 생성자를 같은 방식으로 다룰 때 쓴다.

  • https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Executable.html

Module Access Modifier

Java 9 모듈 시스템에 “모듈 안에서만 보이는” 접근 제어자가 있는지에 대한 질문이다. 답은 없다는 것이다. 모듈의 공개 범위는 module-info.java의 exports로 패키지 단위로만 정해진다. 타입이 public이어도 그 패키지를 export하지 않으면 모듈 밖에서 접근할 수 없지만, 메서드나 필드 하나만 모듈 범위로 숨기는 수단은 없다.

  • https://stackoverflow.com/questions/38897806/module-local-access-behaviour-in-java-9

How to Check Date Overlap in SQL

두 기간 A, B가 겹치는지는 “겹치지 않는 경우”를 뒤집으면 간단해진다. A가 B보다 완전히 앞이거나(EndA < StartB) 완전히 뒤면(StartA > EndB) 겹치지 않으므로, 겹치는 조건은 StartA <= EndB AND EndA >= StartB다. 경계가 맞닿는 경우를 겹침으로 볼지에 따라 <=와 <를 고른다.

1
2
3
4
SELECT *
FROM reservation r
WHERE r.start_date <= :end_date
  AND r.end_date >= :start_date;
  • https://social.msdn.microsoft.com/Forums/sqlserver/en-US/5f104287-c9c4-4de4-a3d3-9dbcf2c4b018/query-to-determine-overlapping-date-ranges-by-category?forum=transactsql
  • https://blog.widefix.com/date-ranges-overlap/
  • https://www.codeproject.com/Questions/5260616/Check-for-date-overlap
  • https://stackoverflow.com/questions/325933/determine-whether-two-date-ranges-overlap
  • https://www.kodyaz.com/t-sql/sql-query-for-overlapping-time-periods-on-sql-server.aspx
  • https://www.sqlservercentral.com/forums/topic/check-if-date-ranges-overlap
  • https://way-be-developer.tistory.com/54
  • https://choidr.tistory.com/m/entry/MYSQL-%EB%82%A0%EC%A7%9C-%EC%A4%91%EB%B3%B5-%ED%99%95%EC%9D%B8-%EC%BF%BC%EB%A6%AC
  • https://ysb334kr.tistory.com/41
  • https://stackoverflow.com/questions/49984848/overlapping-dates-exclusion

QueryDSL vs JOOQ

둘 다 자바 코드로 타입 안전한 쿼리를 쓰게 해 주지만 출발점이 다르다. QueryDSL은 JPA 엔티티에서 Q 클래스를 생성해 그 경로로 쿼리를 쓰고, jOOQ는 이미 있는 DB 스키마에서 자바 코드를 생성해 SQL에 가까운 DSL로 쿼리를 쓴다. 참고한 글은 jOOQ가 MySQL, MariaDB 같은 오픈소스 DB에는 무료이고 상용 DB에는 유료 에디션이 필요하다고 정리한다.

  • https://mycup.tistory.com/333

AWS Elastic Beanstalk

애플리케이션 소스 번들을 올리면 실행에 필요한 AWS 리소스를 대신 만들어 주는 서비스다. AWS 문서에 따르면 EC2 인스턴스(또는 EKS 클러스터) 프로비저닝, 로드 밸런싱 구성, 상태 모니터링, 동적 확장을 Elastic Beanstalk가 맡는다.

  • https://docs.aws.amazon.com/ko_kr/elasticbeanstalk/latest/dg/Welcome.html

MySQL Count vs Exists

“조건에 맞는 행이 하나라도 있는가”만 알고 싶을 때 COUNT(*)를 쓰면 안 되는 이유다. jOOQ 블로그의 설명처럼 COUNT(*)는 정확한 행 수를 구해야 하므로 끝까지 세지만, EXISTS는 첫 번째 일치하는 행을 찾는 즉시 멈출 수 있다. MySQL 문서에 따르면 EXISTS 서브쿼리의 SELECT 목록은 무시되므로 SELECT *든 SELECT 1이든 차이가 없다.

  • https://blog.jooq.org/avoid-using-count-in-sql-when-you-could-use-exists/
  • https://www.itprotoday.com/sql-server/exists-vs-count
  • https://dev.mysql.com/doc/refman/5.7/en/exists-and-not-exists-subqueries.html
  • https://lollolzkk.tistory.com/97
참고한 자료외부 출처 5

외부 출처

이 글은 저작권자의 CC BY 4.0 라이선스를 따릅니다.

댓글

아직 댓글이 없습니다