우당탕탕 우리네 개발생활

<클린아키텍처> 공부에 대한 기록 본문

tech

<클린아키텍처> 공부에 대한 기록

미스터카멜레온 2024. 7. 13. 23:18

왜 <클린아키텍처>를 공부하기로 결심했나?

최근 <클린코드> 스터디를 마쳤다. 이 스터디에 대한 기록은 스터디 리포지토리에 남겨 두었다. <클린코드>는 개발자들이 기본기를 다지기 위해 읽을 수 있는 바이블로 오랫동안 알려져 왔다. 내 주변의 동료들도 대부분 이 책을 공부한 것 같았다. 그동안 묘한 소외감을 느껴왔었는데 드디어 이 책을 공부하게 되었다. 저자인 엉클 밥(로버트 C 마틴)의 오랜 경험과 고민이 녹아있는 철학을 이렇게 저렴하게 경험해도 되나 싶은 마음이 공부하는 내내 들었고 정말 몰입해서 가르침을 받을 수 있었다. 공부하면서 밑줄치고 메모했던 내용들을 블로그에 기록도 해두었다.

 

<객체지향의 사실과 오해>와 <클린코드>를 공부하면서 반복적으로 나에게 각인됐던 단어는 바로 '책임'이었다.

 

코드에서 책임을 분명히 나누는 것은 중요하다. 책임을 제대로 나누지 못한 코드는 거대한 덩어리가 되어 문제를 야기하기 때문이다. 예를 들어, 책임을 여러 개 가지고 있는 코드는 표면적으로 봤을 때 다양한 역할을 수행해 줄 수 있는 만능키처럼 보인다. 이 만능키는 여기저기서 필요로 하게 되고 남용된다. 이런 상황을 통해 여러 사용처에 의존성이 생겨버린 만능키는 수정하는 게 쉽지 않아 진다. 이 만능키의 여러 책임 중 하나라도 수정이 필요해지면 이 만능키에 의존되어 있는 수많은 코드들이 이에 맞게 수정을 해야 하는 경우가 발생할 수 있기 때문이다. 책임이 다양했기 때문에 어느 하나가 수정되더라도 파생효과를 예측하기가 쉽지 않다는 것도 큰 문제다.

 

반면 단일 책임을 가진 코드는 문제를 야기시킬 가능성이 매우 적다. 이는 작은 부품과 같다. 여전히 그 쓰임새는 많다. 의존되어 있는 코드들도 많을지도 모르겠다. 하지만 앞서 언급했던 만능키와는 달리 수정하는 것이 훨씬 쉽다. 책임이 하나이기 때문에 수정에 대한 파생효과 예측이 비교적 쉽다. 이는 곧 유지보수 측면에서의 큰 이점이 된다.

 

객체는 책임의 구현체이다. 즉 모든 객체는 책임을 기반으로 생겨난다. 이러한 객체는 클래스라는 좋은 도구를 통해 코드로 구현 될 수 있다. 객체에 대한 개념적인 부분과 기술적인 부분에 대해 이해가 커짐에 따라 책임을 잘 나눈 모습으로 구현하고 싶은 니즈가 커져갔다. 하지만 선뜻 구현을 시작할 수 없는 모호한(?) 어려움이 있었다. 음.. 어떤 디렉터리를 만들어야 하고 어떤 네이밍으로 어떻게 파일을 만들어야 할지 등 오히려 개념이 부족했을 때 별생각 없이 자연스러웠던 행위들이 낯설어졌다. 고민 끝에 객체들을 어떻게 '정리'해서 보관해야 하는지에 대한 간접경험이 필요하다고 결론을 내렸다. 나는 이러한 정리방법을 '아키텍처'라고 알고 있었다.

 

<클린아키텍처>는 제목에서부터 '아키텍처'라는 단어를 품고 있다. <클린코드>와 같은 바이블성 기술서적이 나에게 잘 맞는다는 사실을 최근 공부를 통해 깨달았고 이와 비슷한 성격의 서적이 아키텍처에 대해 다뤄준다면 모호한 개념들을 습득하기에 최적일 것 같았다.

<클린아키텍처>를 읽고 난 후 어땠나?

<클린코드>가 개발자들의 기본기를 위한 바이블이라면, <클린아키텍처>는 앞서 다져 놓은 기본기를 깊이 있게 탐구하고 확장 적용해보는 책이었다. 그동안 채워지지 않았던 빈 개념들이 이 책을 통해 상당 부분 채워졌다.

 

앞서 얘기했듯 '아키텍처'에 대한 모호함은 불현듯 내 발목을 잡기 시작했다. 무지성으로 Controller-Service-Repository를 찍어내던 상황에서 구체적인 철학에 대한 고민이 생기면서 혼란이 발생한 것이다. 형식적으로 만들던 Request, Response에 대한 DTO들부터 Mapper, Factory, Entity 등이 어디에 위치하는 게 맞는지, Core 객체들은 어떤 식으로 정리해 보는 것이 좋은지 등 모든 것이 고민이었다. 이 책은 이러한 모호함을 상당 부분 정리할 수 있게 도와주었고, 무엇보다 내가 생각했던 구현들을 '실행'에 옮길 수 있도록 도와줬다.

 

이 책을 통해 얻은 수확은 정말 많지만 그 중에서도 '경계'에 대한 이해를 깊이 있게 가져볼 수 있었던 게 가장 큰 수확이었다. 앞서 얘기했던 '책임'을 갖는 수많은 코드들은 결국 그 '경계'를 갖게 된다는 사실을 깨달았다. 이 '경계'에 따라 '책임'은 철저히 분리된다. 일반적으로 경계너머의 책임에 대해서는 절대 관여해서는 안된다. 이러한 경계를 코드로써 나타내기 위한 방법으로 추상화된 인터페이스들이 사용됨을 깨달았다(앞서 다른 서적들을 통해 공부했던 추상화 인터페이스의 역할을 한 단계 더 정교하게 이해할 수 있는 계기가 되었다). 이는 단순히 경계를 오가는 통로의 역할을 할 뿐만 아니라 컴파일 의존 방향이 저수준에서 고수준을 향하도록 만드는 데 큰 역할을 하는 사실도 알게 되었다(DIP(의존성역전원칙)).

 

이전에 얘기했던 정리의 방법이 곧 '아키텍처'다 라는 내 생각은 변했다. 정리방법은 아키텍처라는 단어를 대표하기엔 많이 부족했다. 경계를 분명히 잡고 이를 넘나들지 않도록 만드는 게 왜 중요한지, 그로 인해 이것들을 왜 철저히 지켜야 하는지에 대한 철학들을 먼저 탑재해야 한다. 이런 철학이 탑재된다면 작성되는 코드의 퀄리티가 비로소 '정리'라는 것이 의미 있어지는 단위가 될 것이다. 이때부터는 '정리'를 다양한 방법론에 입각해 진행할 수 있다. 기능중심의 정리방법, 계층중심의 정리방법, 컴포넌트중심의 정리방법 등이 다양하게 사용될 수 있다.

 

'아키텍처'라는 단어는 정리의 방법이라고도 말 할 수 있지만 정리의 방법은 '아키텍처'라고 말하기엔 많이 부족하다는 사실을 깨달았다. 이러한 깨달음을 얻은 이후로 '아키텍처'에게 발목을 붙잡히고 있던 상황에서 자유로워지기 시작했다. 구현 전에 먼저 책임에 대해 고민하고 이를 기반으로 경계를 분명히 하는 설계시간을 가졌다. 이를 기반으로 구현을 하게 되니 분명한 네이밍, 적당한 클래스의 단위 등은 자연스럽게 따라왔다. 이렇게 만들어진 파일들을 동료들과의 논의를 통해 정리하기만 하면 됐다. 많이 부족하지만 oop를 향한 한 발을 또 내딛을 수 있게 됐다.