이전의 프로젝트 구조의 단점과, 사내의 코드 구조를 보고 감명을 받아 이번학기 프로젝트에 적용해보려고 한다. 백엔드 개발자가 나 혼자이므로 하고싶은걸 다해볼 생각이다.

전형적인 4계층 아키텍처였다.
db layer가 가장 밑단에 있었고, db 모델링을 기준으로 상위 계층들이 의존적이였다.
엄밀하게 말하자면 이전 프로젝트의 구조는 Domain 레이어는 없지만 각 앱의 Domain 레이어 역할을 비슷하게 하는 파일이 있었다. 하지만 이거는 필요한 상수, 클래스등을 정의해서 단순히 참조하는 역할만 했을뿐 실질적인 도메인 계층이라고 볼수없었다.
따라서 영속성 계층인 persistence layer가 django model manager에 강하게 의존적이였으며,
db 구조가 바뀔시 영속성 계층을 모두 뜯어 고쳐야하는 상황이 발생했다.
또한 모든 레이어가 프레임워크에 강하게 의존적이다보니, 프레임 워크를 바꿀시 코드 전체를 통채로 수정해야하는 상황이 발생할수도 있었다. (물론 프레임워크를 바꿀 예정이 없었고, 학원 사이트 정도기때문에 그럴일이 없을거라고 판단 했기때문에 이렇게 한거긴 하다)
그래서 계층 구조를 가지되, 프레임워크에 의존적이지않는 도메인 계층에 의존적이며, 인프라를 바꿨을때 코드의 변경을 최소화 하는 아키텍처를 적용해 보고싶었다.

이 글에서 클린 아키텍처를 모두 소개하진 않을것이다. 간략하게 설명하면
전통적인 db 중심적 계층에서 벗어나 도메인 엔티티가 가장 안쪽에 위치하며 비지니스 로직을 담은 use Cases 계층, 외부와의 통신을 담당하는 컨트롤러 계층, 가장 밖에 위치한 인프라 계층으로 나뉘어진다.
이 아키텍처의 핵심은 안쪽 레이어에 의존적이되, 바깥 레이어를 바라볼 일이 있으면 의존성 역전을 이용해서 인터페이스를 참조하는 구조를 만들어두면, 바깥 레이어가 수정됐을때 바깥 레이어가 아닌 인터페이스를 참조했기때문에 안쪽 레이어의 수정소요가 없다.
또한 db, 프레임워크, 외부 api 등을 모두 인프라 계층에 둬서 의존성을 줄이고, 마찬가지로 인터페이스를 바라보게 만들어서 언제든 교체했을때 안쪽 레이어의 수정을 줄일 수 있다.
항상 생각하는거지만 아키텍처는 적용하는 환경의 상황에 따라서 변해야한다. 완벽한 아키텍처를 무지성으로 받아드린다면 그거만큼 바보짓은 없다고 생각한다.
그러면 나는 프레임워크를 바꾸거나 dbms를 바꾸거나 db를 바꿀 상황이여서 지금 이렇게 적용하려는거냐? 물론 아니다. 하지만 현재의 규모는 작지만 어떻게 변할지 모르기때문에 그런상황에 대비를 해야하며, 중간 어딘가에서 잘 타협을 하여서 아키텍처를 설계해아한다고 생각한다.
클린아키텍처를 엄밀하게 따라하려면 서비스 레이어와 유스케이스 레이어는 분리되어야한다.
유스케이스 즉 도메인을 기준으로 사용될수있는 케이스를 가장 작은 단위로 나누고, 해당 유스케이스들의 조합을 서비스 레이어에서 호출해야하는 구조이다.
하지만 나는 굳이 서비스 레이어에서 유스케이스를 정의하면되지, 왜 따로 레이어를 빼야하는지 아직 잘모르겠다. 마치 프론트에서 최소 컴포넌트 단위를 어디까지 쪼개야하는지와 같은것처럼, 기능들을 잘 만들어놓고 가져다가 쓰면 물론 좋겠지만, 아직까지 그 필요성을 느끼지못했으므로 하지않았다.
고로 최종적인 구조는 Domain > Service > Interface > Infra 이렇게 구성하였다.
장고를 다뤄본 사람들은 알겠지만, 프레임워크의 기능들이 처음부터 끝까지 많은걸 제공하다보니, 기능 하나하나들이 프레임워크에 정말 강하게 의존하고있다.
그래서 내 목표는 의존성을 최소화하는거지, 완벽하게 분리된 서비스를 만드는게 아니다.
텍스트로 보는것보다 그림으로 보는게 더 잘 와닿을테니 구조를 직접 눈으로 봐보자.




서비스는 도메인을 중심으로 사용되는 유스케이스들의 모음과, 인프라를 사용하는 인터페이스들을 가지고있다. Oauth와, db에 접근하는 레포지토리 디렉토리는 이러한 인터페이스들을 가지고있다.


IOauthProvider는 OuthProvider인 apple, google, 등등을 위해 만들어놓은 추상클래스이고, 이 추상클래스를 서비스 레이어의 유스케이스에서 사용할것이다.
이렇게 하면 인프라가 바뀌어도 인터페이스 (편의상 인터페이스라고 하겠다) 를 바라보고 있기 때문에 서비스 코드를 변경할 필요가없다.

레포지토리도 같은맥락으로 쓰인다.


이전 프로젝트로 그랬지만 내 프로젝트는 query param, path, body등을 검사하는 validator을 컨트롤러 단에서 따로 만들어서 쓰고있다. (물론 비지니스 로직이 들어간 validator를 의미하는게 아니다)
django view의 함수에서 간단하게 데코레이터를 붙여서 쓸수있게 만들어져있다.
코드는 안보여줄거다.
views


저번 프로젝트부터 느끼는 점이지만, django의 장점은 다양한 플러그인, 많은 기능, admin 등 여러개의 기능을 빠르고 쉽게 만들수있다는 점 등등이 있다.
하지만 이러한 기능들을 사용하면 할수록 프레임워크에 의존적이게 되며 코드의 변경이 어려워진다.
또한 django의 디자인 패턴은 mvt를 중점으로 만들어놔서 django의 validater, permission등을 사용하려면 모두 view에서밖에 쓸수없는 구조기때문에, (혹은 model) 비지니스 로직이 이곳저곳에 혼재될수있다.
결국 django가 지향하는 디자인 패턴으로 만든다면 큰문제가 없지만.. 유용한 기능들이 해당 패턴에 의존적이여서 다양한 아키텍처에서 사용할수 없다는 단점이 있다. 또한 기능들끼리 강하게 연결되어있는 경우가 많아서 얘네가 하라는대로 안하면 나머지도 못쓰는 경우가 많다.
ex) 장고 admin을 사용하려면 장고가 제공하는 User 모델을 사용해야함... 그렇게되면 장고가 제공하는 user 구조를 사용해야하고..(물론 커스텀 가능하지만 제한적이다) jwt같은경우도 simplejwt라고 자기들이 만들어놓은게있는데 자기들이 만든 user에만 사용가능하다. 따라서 jwt를 user외에 다른곳에서 사용하려면 결국 내가 만들어야함.ㅋㅋ 등등
결국 내가 django가 지향하는 디자인패턴대로 설계하지않으면 django의 기능을 잘 사용하지못하는거기때문에 프레임워크의 장점을 살리지 못하는거다. 그러면 django를 왜 사용하는가? 등등 생각이 많다..