오늘은 계속해서 DataAccess 계층을 개발했다.해당 계층 개발은 어렵지 않아서 오늘 하루만에 끝이났다. 다만 해당 기능을 개발하면서 발생한 에러와 관련하여, 이를 기록하고 정리하는데 조금 시간이 소요되는 것 같다.
발생한 에러는 Lazy Loading 때문에 발생한 문제로, ORM을 사용하다보면 흔하게 겪어볼 수 있는 일이다 보니, 쉽게 해결 할 수 있었다. 그런데 내가 생각하는 방법과는 다른 방식으로 풀이가 되어서, 이 부분에 대해 기록이 필요할 듯하다.
오늘 독서는 디자인패턴을 했는데, Abract Factory(추상 팩토리), Bridge(브릿지) 패턴을 공부했다. 추상 팩토리의 경우, 개인적으로 가장 잘 이해가 안되는 것 같다. 그리고 브릿지 패턴의 경우 다소 깊은 생각을 하게 만드는 것 같다.(재밌다.)
DataAccess 계층 개발, JPA 에러
오늘은 DataAccess 계층 개발을 진행했다. 사용하는 API 는 2개 뿐이라서 정말 금방 개발할 수 있었다. 그러나 에러 없이 개발이 되지는 않았다.
에러는 조회 실패 케이스를 테스트하면서 발생했다. 발생한 에러는 Lazy Loading 에 관한 에러로, OrderEntity 내의 필드인 items(List<OrderItem>)가 문제가 되었다.
발생한 에러는 OrderEntity의 컬렉션필드인 items 에서의 Lazy Loading 때문에 발생했다. 그리고 나는 items 필드를 Eager Loading 으로 설정하지 않았다.
나는 Lazy Loading 문제를 Django 를 개발하면서 겪었고, 이를 해결하기 위해서 JOIN FETCH를 사용했었다. 그리고 Java 에서도 동일했다. 나는 처음에 JpaRepositoryImpl 클래스에서 JPQL을 사용하여 문제를 해결했다.
하지만 나는 과거 레거시 코드에서 겪었던 문자열로 쿼리 작성하는 것을 하고싶지 않았다.(나를 못믿는다. 오타 끔찍하다.) 지금 같은 경우에는 간단하기에 에러가 발생하면 손쉽게 찾을 수 있지만, 복잡한 쿼리를 작성했는데, 에러가 발생하면, 찾기가 까다롭기 때문이다.
그래서 나는 코드로 쿼리를 작성하는 QueryDsl 을 사용하여 개발하기로 마음먹었다. 설정도 다 되어있고, 고민할 필요가 없었다.
나는 첫번째로 사진과 같은 API를 작성했다. 하지만 이 API 는 문제를 해결하지 못했다. 이해가 되지 않았다. 분명 OrderItem을 JOIN 하고 Fetch 를 했는데 Eager Loading 처리가 되지 않는다니? 이해가 되지 않았다.
나는 내가 작성한 API 가 잘못됬나? 하는 생각에 QueryDsl을 사용한 API 예시를 보기도하고, GPT에게 오류를 물어보기도 했지만 문제는 없었다.
원인: List<OrderItemEntity> 컬렉션을 Eager Loading 한 것이 아닌
단일 OrderItemEntity 엔터티 를 Eager Loading 했다.
나는 도저히 원인을 알 수 없어, JPA API 를 보여주고 내가 작성한 쿼리와의 비교를 진행했다.약간의 대화가 필요했지만, 이 문제를 해결할 수 있는 API 를 얻을 수 있었다.
신기했다. 무슨 차이때문에 이것이 Eager Loading 문제를 해결했을까 ? 이전 API 와 해결된 API 의 lefJoin() 을 비교해보았다.
둘의 차이를 나는 모르겠어서, GPT의 도움을 받았다.
이것을 보고 문제는 컬렉션 형태의 필드에 대한 JOIN 과 엔터티 형태의 필드의 JOIN API 가 다르다는 것을 알 수 있었다. 내가 이해한 것이 맞는지 추가적으로 질문을 해보았다.
정말 신기했다. GPT는 답을 알고있다는 사실이 신기했고, 컬렉션 필드를 Eager Loading 하는 방법이 다르다는것이 신기했다. 나는 쿼리에서 어떤 차이가 있는지 궁금하여, 쿼리도 비교했었는데, 내 눈에서는 다른 것이 없었다. 근데 다르네.. 마음이 불편하면서도 신기하다.
단순히 Eager Loading 을 위해서 Fetch Join 만을 알고 있었는데 필드의 종류에 따라 다르다는 사용하는 API 가 다르다는 새로운 사실을 알게되어서 기쁘다.
디자인 패턴: Abstract Factory, Bridge
오늘 복습한 디자인 패턴은 Abstract Factory 와 Bridge 패턴을 복습했다. 이전 레거시 프로젝트를 담당하면서, 사용된 디자인 패턴을 찾아볼 때, 가장 먼저 접해 볼 수 있던 패턴은 추상 팩토리 패턴으로 기억하고 있는데, 오늘 복습해보니, 아닌것 같다는 생각이 든다..
근데 내가 이야기하고 싶은 것은 패턴에 대한 이야기보다는, 패턴을 공부하면서 든 추가적인 생각에 대해 정리해보려고한다.
추상 팩토리
추상 팩토리 패턴에서, 팩토리는 클래스를 생성하는 곳을 말한다. 그리고 추상 팩토리 패턴에서는 이름에서 도 알 수 있듯이, 구체적인 팩토리는 하위 클래스에서 구현된다.
추상 팩토리 패턴은 간단하게, 추상클래스의 개념이 들어간 팩토리라고 생각하는데 이상하게 어렵다. 자꾸만 이를 활용한 상상이 되지 않는다. 그 이유를 알 수 없었는데 책의 일부분을 보고 이것 때문인가? 하는 생각이 든다.
구체적인 공장(팩토리)을 추가하는 것은 간단 하지만, 부품을 추가하는 것은 어렵다. 이미 존재하는 구체적인 공장 전부를 수정해야 하기 때문이다.
* 간단하다: 어떤 클래스를 만들고 어떤 메서드를 구현해야하는지 명확하다.
이것이 어렵다고 느껴지는 정확한 원인은 아니겠지만, 이런 것을 생각해내는 것이 복잡하게 느껴지고 내가 상상을 못하게 되어 어렵게 느껴지는 게 아닐까 싶다. 그래도 상상하는 것은 여전히 재밌다.
브짓지
브릿지 패턴은 다시 복습하면서 앗!!! 내가 이것을 생각하지 못했구나!! 그래서 내가 그랬구나!! 내가 이것을 왜 고민하지 않았지?! 를 많이 했다.
나는 인터페이스, 추상클래스를 사용하는 것이 브릿지 패턴이라고 생각했다. 하지만 이는 잘못된(?) 생각이었다.
추상클래스를 구현하는 다양한 구현체에서 중복되는 기능을 보았을 때, 나는 이것을 상위 클래스로 올렸었다. 그런데 이런 작업에서 내가 부족했던 것이 있는데, 바로 기능을 추가할 때, 새로운 구현을 추가할 때 를 제대로 구분 짓지 않았다 는 것이다.
기능의 클래스 계층에서는 기능을 추가하기 위해 만들어졌다.
- 상위 클래스는 기본적인 기능을 가지고 있다.
- 하위 클래스에서는 새로운 기능을 추가한다.
이것만 보았을 때에는 내가 잘 사용해왔구나 라는 생각을 했었다. 하지만 다음 글을 보고서는 아차, 싶었다.
구현의 클래스 계층은 기능을 추가하기 위해 사용되는 것은 아니며, 새로운 메서드를 늘리기 위해 클래스 계층을 만든 것도 아니다. 다음과 같은 역할 분담을 위해 클래스 계층이 사용된 것이다.
- 상위 클래스는 추상 메서드로 인터페이스(API)를 규정한다.
- 하위 클래스는 구상 메서드로 그 인터페이스(API)를 구현한다.
분명 나는 기능으로서의 클래스 계층을 사용했다. 그리고 개발 간, 중복되어 사용되는 API 를 상위 클래스로 올렸다. 이것은 가끔은 구상메서드이기도하였고, 추상 메서드이기도 하였다.
이렇게 본다면, 나는 기능을 추가하려고 한것일까? 구현을 하려고 한 것일까? 헷갈리기 시작한다. 그리고 나는 개발을 할 때, 이것을 상위 클래스에 두어야할지, 하위 클래스에 두어야할지 고민하는 경우가 많이 생겼었다.
지금 돌이켜 본다면, 나는 기능을 추가하려는 쪽이 더 가까웠던 것 같다. 그런데 이게 왜 아차 싶었냐고 묻는다면, 그렇게 개발한 클래스들이 뭔가, 어딘가, 개선할 수 있을 것 같은데, 어떻게 개선해야할지 몰랐기 때문이다.
그렇다면 지금 당시 고민의 원인은 무엇이고, 어떻게 개선할 수 있을까? 그 때 개발하던 모듈이 정확하게 기억은 안나는 것이 문제인데.. 아마도 브릿지 패턴을 사용하여 관리하면 그 당시의 고민을 어느정도 해결할 수 있지 않았을까 싶다.
DataAccess 계층의 개발은 사실 아직 Commit 과 PR을 작성하지 않았다. 내일 마무리 정리를하고서 PR을 작성하고, 벌써 금요일이라서 지금까지 개발된 것을 Main 브랜치에 병합시킬 계획이다.
그리고 친구에게 알아온 타이머 프로그램을 통해 독서하는 시간을 측정했는데, 분명 10~20분정도라고 알고있던 시간이 30분이 넘었다. 이를 몰랐던 것이 참 어이가 없다. 그런데 정말 가지고 있는 책들이 너무 재밌다. 이 책의 내용을 다른사람들과 같이 이야기하면 또 얼마나 재밌을까?
어서 빨리 취업할 수 있도록, 프로젝트는 부족한 부분을 계속해서 기록하고, 독서를 통해 좀더 나은 코드로 개선할 수 있도록 노력해야겠다.
'회고 > TIL' 카테고리의 다른 글
Order 도메인 1차 개발 완료, Wiki 정리, 추가 개발사항, 책 쇼핑 (0) | 2023.08.27 |
---|---|
DataAccess 마무리, Web계층 개발, 남은 일정, 인프런 강의 수강 (0) | 2023.08.26 |
Order Messaging 계층 1차 마무리, DataAccess 계층 개발 시작, 독서 (0) | 2023.08.23 |
이력서 업데이트, 친구와 모각코 (0) | 2023.08.22 |
예비군 훈련, TestContainer, 예측가능한 코드, 참조오류 (0) | 2023.08.21 |