2021-03-09-TIL
2021-03-09-TIL
[CODE REVIEW]
코드 리뷰에서 나온 주제들을 하나씩 찾아본 기록이다.
slf4j without toString
log.debug("user: " + user)처럼 문자열을 이어 붙이면 로그 레벨이 꺼져 있어도 user.toString()과 문자열 결합이 먼저 실행된다. SLF4J FAQ는 log.debug("user: {}", user)처럼 자리표시자({})를 쓰라고 권한다. 이렇게 하면 해당 레벨이 활성화된 경우에만 인자를 문자열로 바꾸므로 불필요한 비용이 없다. 따라서 로그를 위해 명시적으로 toString()을 부를 필요도 없다.
- https://stackoverflow.com/questions/11295764/slf4j-without-tostring
toString in JPA
양방향 연관관계의 두 엔티티가 서로를 toString()에 포함하면, A의 toString()이 B의 toString()을 부르고 B가 다시 A를 부르는 무한 재귀로 StackOverflowError가 난다. Lombok의 @ToString이나 @Data를 엔티티에 그대로 붙였을 때 자주 생긴다. 연관 필드는 toString()에서 빼고(@ToString.Exclude), 지연 로딩 필드에 접근해 의도치 않은 쿼리가 나가는 것도 피해야 한다. JSON 직렬화에서도 같은 순환이 생기므로 엔티티 대신 DTO를 응답으로 쓰는 편이 안전하다.
- https://stackoverflow.com/questions/40266770/spring-jpa-bi-directional-cannot-evaluate-tostring/40267032
redirect: 와 redirect:/
Spring MVC에서 뷰 이름에 redirect: 접두사를 붙이면 UrlBasedViewResolver가 이를 리다이렉트 지시로 해석한다. Spring 문서에 따르면 redirect:/myapp/some/resource처럼 /로 시작하는 이름은 현재 서블릿 컨텍스트 기준으로, redirect:https://...는 절대 URL로 리다이렉트한다. / 없이 redirect:list라고 쓰면 현재 요청 URL을 기준으로 한 상대 경로가 되므로, 요청 경로가 바뀌면 다른 곳으로 이동할 수 있다. 의도가 분명하도록 /로 시작하는 경로를 쓰는 편이 낫다.
- https://nsinc.tistory.com/168
forward vs redirect
- forward: 서버 안에서 요청을 다른 리소스(뷰나 다른 컨트롤러)로 넘긴다. 브라우저는 이를 모르며 URL도 바뀌지 않고, 요청 객체가 그대로 공유된다.
- redirect: 서버가 3xx 응답과
Location헤더를 보내고, 브라우저가 그 주소로 새 요청을 보낸다. URL이 바뀌고 요청이 두 번 일어난다.
글 작성처럼 상태를 바꾸는 POST 요청 뒤에 뷰를 바로 렌더링하면, 사용자가 새로고침할 때 같은 POST가 다시 전송된다. 그래서 처리 후 조회 페이지로 리다이렉트하는 PRG(Post/Redirect/Get) 패턴을 쓴다.
- https://stackoverflow.com/questions/29560633/difference-between-redirect-and-view-rendering-in-spring-mvc
- https://stackoverflow.com/questions/18671463/why-do-we-use-redirect-in-spring-mvc
- https://www.baeldung.com/servlet-redirect-forward
RESTful url 설계
링크된 글들이 공통으로 정리하는 규칙은 다음과 같다.
- URI는 리소스를 나타내고, 동사는 쓰지 않는다. 행위는 HTTP 메서드로 표현한다(
POST /questions,DELETE /questions/1). - 리소스 컬렉션은 복수 명사를 쓰고, 계층 관계는
/로 표현한다(/questions/1/answers). - 소문자를 쓰고, 단어 구분은 밑줄 대신 하이픈을 쓰며, 끝에
/를 붙이지 않는다. 파일 확장자를 URI에 넣지 않고
Accept헤더로 형식을 정한다.- https://devuna.tistory.com/79
- https://one-it.tistory.com/entry/RESTful-API-%EC%84%A4%EA%B3%84-%EA%B7%9C%EC%B9%99
- https://velog.io/@stampid/REST-API%EC%99%80-RESTful-API
- https://meetup.toast.com/posts/92
How to create a DAO using JPA
DAO(Data Access Object)는 영속성 접근 코드를 한 클래스에 모아 비즈니스 로직과 분리하는 패턴이다. JPA로 만들면 EntityManager를 주입받아 persist(), find(), merge(), remove(), JPQL 쿼리를 감싸는 메서드를 제공한다. Spring Data JPA의 JpaRepository는 이런 공통 CRUD 코드를 인터페이스 선언만으로 만들어 주는 셈이다.
- https://thomas-broussard.fr/work/java/tutorials/advanced/jpa-dao/jpa-dao.html
What exactly is Field Injection and how to avoid it?
필드 주입은 @Autowired를 필드에 직접 붙여 의존성을 넣는 방식이다. 코드는 짧지만 의존성이 생성자 시그니처에 드러나지 않고, 필드를 final로 만들 수 없으며, 단위 테스트에서 리플렉션 없이 목 객체를 넣기 어렵다. Spring 문서는 생성자 주입을 일반적으로 권장하며, 그 이유로 컴포넌트를 불변 객체로 만들 수 있고 필수 의존성이 null이 아님을 보장한다는 점을 든다. 생성자 인자가 지나치게 많아지면 클래스의 책임이 너무 많다는 신호라는 설명도 덧붙인다.
- https://stackoverflow.com/questions/39890849/what-exactly-is-field-injection-and-how-to-avoid-it#:~:text=The%20reasons%20why%20field%20injection,in%20unit%20tests)%20without%20reflection.
댓글
아직 댓글이 없습니다