Etc./개발 일기

백기선님 공개 코드 리뷰 받기! with 300명 22/09/17 (Package Structure, Test Code, DDD, ...)

JaeHoney 2022. 9. 26. 12:57

최근에 백기선님이 유튜브에서 공개 코드 리뷰를 시작하셨다.

 

리뷰 내용을 보고 영감을 얻은 부분이 있었고, 부족한 부분을 알고 싶다는 생각에 용기를 내 신청했다!

 

코드 리뷰 영상은 아래 링크에서 확인할 수 있다. (백기선 유튜브 - 멤버십 회원 전용 영상)

내가 리뷰 받을 코드는 초기 상태의 코드라서 설명이 부족해서 미리 양해를 구했다.

백기선님: 아 물론이죠! 아직 완성 안된 프로젝트도 리뷰 가능합니다!

 

그래서 신청했다.

리뷰 시작

리뷰를 할 때 실시간 접속자는 300분 정도 계셨다!

백기선님: 코드 리뷰를 어디로 중점적으로 보면 좋을까요?!

본인: 음 프로젝트 초기 단계라서 패키지 구조테스트 코드 위주로 봐주시면 감사하겠습니다.
(패키지 구조나 테스트 코드 구조는 잡았기 때문이다. 사실 전체적으로 봐주셨다 ㅋㅋ)

 

(... 간단한 팀소개 ...)

 

백기선님: 팀을 어떻게 만나신거에요??

본인: 아! 제가 첫회사에 들어온 지 10개월차 정도인데 저도 네이버, 라인, 배달의 민족에 이직을 하고 싶은 생각이 들었는데 지표가 부족하다보니까 사이드 프로젝트를 해봐야겠다고 생각했습니다! 그런데 인맥이 없으니까 사이드 프로젝트할 인원을 구하는 카카오톡 오픈 채팅방을 통해 팀을 구해서 진행하게 되었습니다.

 

(ㅎㅎ 간단한 만담 이후 바로 리뷰를 진행해주셨다.)

리뷰 진행

백기선님: API 패키지는 우선 도메인 별로 나눠 놓았네요! (account, artist, common, ...) 그쵸! 이렇게 구성하면 Common이 항상 생기죠 ㅎㅎ. Config는 Spring 설정파일 놓아둔 곳이고! 그래서 주요한 도메인은 account, artist, contest, cover, song인 것 같네요!

본인: 네네!

 

백기선님: 근데 이게 command가 뭔 뜻이에요?! (song/command를 가리키시며)

본인: 그게 CQRS 패턴이라고 command랑 query랑 모델을 분리하는 패턴의 command입니다.

 

백기선님: 아 CQRS! 그런데 도메인 자체가 command에요?

본인: 넵넵! 그렇게 도메인 모델도 분리해서 사용했습니다.

 

백기선님: 아 그래요? OK... 저는 조금 생소하지만~ ㅎㅎ

본인: 넵.. (ㅇㅅㅇ)

백기선님: 오 이렇게 하셨네! 이렇게 하신 이유가 있나요??

본인: Id 참조 말씀이신가요?!

 

백기선님: 네네. JPA를 쓰셨는데 Artist랑 연관 관계를 맺은게 아니라 그냥 이거는 사실상 관계가 없는 거죠. DB를 표현한거죠. 사실 이거(JPA)를 제대로 쓸려면 Artist가 되야 하지 않아요?!

본인: 아 네! 알고는 있었는데 도메인 모델을 라이프 사이클을 기준으로 객체 참조를 할 지 ID 참조를 할 지 정한다구 하더라구요! 두 도메인이 라이프 사이클이 같지 않은 것 같아서 ID 참조를 사용했습니다.

 

백기선님: 아 ㅎㅎ 자 그럼 라이프 사이클에 대해서 한번 이야기해볼까요?? 말씀하신 라이프 사이클은 어떤 거죠??

본인: 가수인 Artist를 생성 및 삭제될 때랑 Song을 생성 및 삭제될 때랑 시점이 다르니까! 그래서 분리했던 것 같습니다.

 

백기선님: 음 저는 이게 개별적인 라이프 사이클이 맞는건가..? 조금 의구심이 들긴 합니다. 제가 봤을 때는 Song은 Artist에 종속적이라서 연관 관계를 맺어주는 게 맞는 게 아닌가..?! 그리고 저도 의도적으로 이렇게 연관 관계를 끊는 것은 본적은 있어요. 이렇게 되면 artist 내용은 어떻게 가지고 오나요?!

본인: 가지고 오는 것은 ArtistService를 통해서 가져오는데 Artist 패키지에 있는 서비스를 참조하는 것은 아닙니다. Song의 Application layer에 있는 ArtistService를 구현하는 Infrastructure에 있는 구현체를 주입받아서 가져옵니다.

참고

리뷰 때는 설명을 자세히 못드렸다. (부족해서)

 

이전에 봤던 우아콘 영상 내용이다. 해당 영상에서는 두 객체의 관계가 영구적일 때만 객체 참조를 사용한다.

 

더 자세히 풀어보자. 도메인 간의 관계는 연관 관계로 사용할 수 있다. 객체 참조는 연관 관계를 구현하는 방법 중 한 가지일 뿐이다!

문제는 도메인 간의 객체 참조를 하면 아래 문제가 생길 수 있다.

  • 도메인 간의 결합도 상승
  • 성능 이슈가 발생하기 쉽다. (모든 도메인을 한번에 조회하는 것도 가능해진다.)
  • 수정할 도메인의 경계 및 트랜잭션 경계가 모호해진다
  • 패키지 의존성 사이클이 돈다. (모든 패키지가 같이 변경되는 것을 의미한다.)

따라서 함께 생성되고 함께 삭제되는 객체들은 묶고, 도메인 제약사항을 공유하는 것이 아니라면 분리하는 것이 좋다. 가능하면 분리하는 것이 바람직하다고 한다.

 

아직 보지 않았다면 꼭 참고해보시길 권해드린다!

계속

백기선님: 아.. 그러면 이 프로젝트 안에서는 연관 관계가 아예 없겠네요?!

본인: 엇 거의 그렇지만 있긴 합니다.

 

백기선님: (찾으시다가) 어?! 여기있네! 아..! 그러니까 여기 패키지안에서만 연관 관계를 만들었나 보네? 맞아요?!

본인: 아 네네!

 

백기선님: 아..! 그러니까 다른 패키지에서는 다른 패키지로 연관 관계를 아예 안 만들었죠?!

본인: 엇 네네! 이게 ~ (설명드리려다가 감탄해주셔서 말씀을 못드렸다.)

 

백기선님: (사뭇 진지해 지셔서) 아~  아~ .. 아 알겠어요. 이제 이해했어요. 네 나름 괜찮네요. 네 괜찮네요. 이렇게 개발하면 좋은 점은 패키지 별로 따로 뜯어내기가 아주 쉬워지죠..! 그런데 실제로 그렇게 되어있나요?!

본인: 아.. 네! 실제로 전혀 다른 애그리거트 단위로 패키지를 잡아서 다른 패키지에 대한 의존성은 전혀 없을겁니다.

 

(크으..👍 의도를 알아봐주시고 진지하게 잘했다고 말씀해주셔서 좋았다! 🤣)

 

백기선님: 아~ 재밌네. 연관 관계를 안쓴 건 아니고, 연관 관계를 쓰는 기준이 패키지 내부만이다..! 아 재밌네~ 재밌네! 잘하셨네요..! 그런데 저라면 아마 이렇게 하진 않았을 것 같아요. 왜냐하면 아직 분리 안됬으니까 ㅎㅎ..

(YAGNI가 생각 났다. YAGNI는 내가 정말 좋아하는 원칙으로 현재 필요한 것이 아니라면 구현하지 않는 원칙이다. 그래서 한번 생각해보게 되었다.)

 

[YAGNI에 대한 생각 정리]

  • 현재 필요하지 않는 기능은 추가하지 않는 것이 맞다.
  • 하지만 설계는 조금 다르다. 확장성을 고려하지 않은 설계로 구현하게 되면, 내가 잠깐 손을 놓은 사이에 다른 개발자가 들어와서 확장성이 없는 설계로 이어서 개발하게 될 수 있다.
  • 당장 필요하지 않더라도 확장성 있게 설계하는 것도 나름의 일리가 있다고 생각한다.

백기선님: 막상 해보시니까 어떤 게 더 편해요??

본인: 트랜잭션 단위나 영향 범위에 대해 걱정하지 않아도 되서 좋은 것 같아요. 대신 할 일이 조금 많아지는 것 같아요.

 

백기선님: 구체적으로 어떤 할 일이 늘어나나요?

본인: 예를 들면 Cover에서 Song(원곡)을 꺼내는 일이 아주 아주 아주 많은데, 그럴 때마다 특정 인터페이스를 사용해서 꺼내야 하는 점이 불편한 것 같습니다.

 

백기선님: 아 맞아요. 이게 가장 큰 단점이거든요..! 잘 알고 계시네요. 저는 사실 기술적인 선택은 자유라고 생각하고, 대신 어떤 기술을 선택할 때 어떤 장점과 단점이 있는 지 본인이 잘 알면 된다고 생각하는데, 잘 아시고 계신 것 같아요. 재밌네요. 네. 재밌네요!

본인: 아 감사합니다.

 

백기선님: (모든 패키지 소스 뒤적거리시면서!) 전 뭐 잘하신 것 같은데요?! 딱히 뭐 문제 될 부분이.. 아..! 테스트나 좀 볼까?? ㅎㅎ

본인: 아 네네..! 테스트를 정말 잘 짜고 싶었어요! 그런데 잘 못해요 ㅎㅎ..

백기선님: 어유~.. 테스트가 아주 충실해보이는데요..?? 볼까요?

본인: 네!

백기선님: 어.. RestDocs까지! 오~ 잘하셨네요! 이게 사실상 얘는(AccountControllerTest) 통합 테스트군요.

본인: 네! 맞아요. 사실 Service단을 Mocking하고 @WebMvcTest로 하는 거랑 아직도 어떤 좋을 지 고민되거든요! 근데 이게 원천이 백기선님 강의에요!

 

백기선님: 아 네! 익숙해보입니다 ㅎㅎ 저는 Mocking이 계속 피곤하거든요. 그래서 저는 이걸 선호해요. 저는 그냥 통합테스트를 하는 것을 선호해요. Controller부터 아래까지 쭉~ 다! 시도해보시니까 어떤 것이 편한지?!

본인: 아무래도 가독성이나 코드 작성하는 것은 통합 테스트가 편한 것 같은데 이게 오래 걸리니까 그게 또 단점인 것 같아서요!

 

백기선님: 아.. 맞아요 맞아요! 그게 큰 단점이에요. DB는 어떻게 했어요? 테스트용 DB는?

본인: 테스트는 프로젝트 받으면 바로 실행할 수 있게 H2를 사용했습니다.

백기선님: 아.. 그러네 Embedded-DB 쓰셨군요. Redis도 그냥 Embedded로! 잘하셨네요. 이거 다른 개발자 분들도 보고 참고하실만 한데요?!

본인: 아.. 아닙니다! 감사합니다.

백기선님: 와~ 테스트.. 진짜 충실하다..! 잘하시는데요?? 리뷰할 게 없어요! 잘하시는데?! 이 정도면~ 음.. 잘하시는데?? 깔끔하네요! 깔끔하네요. 더 이상 뭐 볼 게 없습니다. 깔끔해요!

본인: 아.. 네 감사합니다!

 

백기선님: 어유 제가 더 감사하죠! 잘 봤습니다. 제가 딱히 드린 코멘트가 없네요.. ㅎㅎㅎ 잘..잘하셨다..!'라는 코멘트밖에 없네요 ㅋㅋㅋ

본인: 아.. 아닙니다 아닙니다! 잘 배웠습니다.

 

백기선님: 아니에요. 제가 뭘 해드린 게 없는데 ㅎㅎ

본인: 네. 아 감사합니다

 

백기선님: 넵 그럼 여기까지 하겠습니다. 잘 봤습니다. 늦은 시간 참여해주셔서 감사합니다.

본인: 넵! 감사합니다. (퇴장)

 

- 퇴장 직후 -

백기선님: (시청자 분들께) 잘 만들지 않았나요?! 여러분들도 봤을 때 잘 만들지 않았나요?! 어유.. 잘하시는 분들이 많아요!

 

백기선님: 저 정도면.. Hard Skill은 충분하지 않을까..?? 저 정도면 충분할 것 같은데?!

 

백기선님: 제가 잘했다고 거듭 말씀드렸던 밑 배경에 뭐가 있었냐면! 패키지 간의 의존성이 분명 있어요. 없을 수는 없어요. 그런데 Circular Dependency만 없으면 되요. 모든 Package Denpendency가 다 단방향이어야 합니다~ 그걸 고려하셨다는게.. ~

느낀점

사실 리뷰를 진행하게 된 이유가 부족한 점을 알기 위해서 + 잘 공부하고 있는 지 리뷰를 받고 싶어서이다.

 

해당 리뷰를 통해 거둔 수확은 크게 두 가지이다.

  • 부족한 점을 알게 된 점
  • 잘 공부하고 있었다는 것을 확인 받은 점

리뷰를 통해 알게 된 부족한 점은 이런 것들이 있다.

  • 패키지 의존성에 대해 더 명확히 알게 되었다.
    • (사실 패키지 의존성을 잘 몰랐다. 리뷰라는 계기를 통해 더 찾아보면서 알게되었다!)
  • Controller의 단위 테스트 및 통합 테스트의 장단점에 대해 다시 생각해보게 되었다.
    • 이전에 포스팅한 내용 (https://jaehoney.tistory.com/213)
    • 해당 내용에 추가로 단위 테스트에서는 선행되었어야 할 Mock에 대해 더 고민하게 되었다.
  • YAGNI
    • 개발을 할 때 현재 필요하지 않은 기능을 미리 구현해서는 안된다.
    • 하지만, 미리 좋은 설계 원칙을 적용해 코드를 구현하는 것은 가능하다는 나만의 결론을 내릴 수 있었다.
  • DDD - Package Structure
    • 프로젝트에 DDD를 적용하고 서로 다른 애그리거트를 하나의 패키지로 잡고 의존성을 없앴다.
    • 결과는 좋았지만, 해당 내용에 대해서 어떠한 장단점이 있는 지 잘 모르고 진행했던 것 같다. (답변을 자세히 못드렸다.)
    • (결과가 좋아도, 명확히 알고 진행하는 것과 잘 모르고 진행하는 것은 아주 명백히 다르다!)

 

그래도 잘 공부하고 있다는 생각이 들어서 아주 아주 좋았다.

 

(정말 감사합니다! 🙇)