유어클래스 서버가 변하고 있어요

one layer architecture 서버에서 layer architecture적용기

서론

코드스테이츠 LMS 유어클래스

코드스테이츠의 LMS “UrClass”는 Node.js 기반에 typescript, graphql을 사용 하고 있습니다.

코드스테이츠 UrClass는 LMS 로 코드스테이츠 내 부트캠프 학습을 위해 수강생들과 코스 엔지니어, 매니저분들이 사용하고 있는 웹 어플리케이션 입니다

유어클래스의 전신인 Learnco 에서도 graphql을 사용 했고, 부분적으로 typescript를 사용 중 이었습니다. typescript와 graphql을 함께 사용하면서 “db schema랑 typescript type이랑 graphql type 세가지는 아무리봐도 같이 겹치는것 같은데, 세번씩이나 정의를 해야할까 …?” 라는 불편함을 겪었습니다. 유어클래스 프로젝트가 킥오프를 하게 되면서 이전의 타입 중복 선언을 피해보고자 리서치 해본 결과, typescript + graphql + type-graphql + typeorm 이라는 스택을 채택 하였습니다. class를 활용하여 typescript 객체 타입을 정의하고, 그 위에 typeorm과 type-graphql decorator를 씌우면서, 타입의 중복 선언을 최대한 피하면서 코드 양을 확연히 줄이는 성과를 이루어 냈습니다. 그만큼 개발 속도가 빨라지면서, schema가 나오면 CRUD api는 바로 만들어 낼 수 있을 만큼 속도를 낼 수 있었습니다.

책임과 권한이 막강한 레졸버. 번아웃 오기 딱 좋겠구나!

서론에 이렇게 자화자찬을 늘어 놓는 것은 당연하게도, 한계에 도달 했기 때문 이겠죠. 코드양을 줄이면서 빠른 개발을 할수 있었지만, 하나의 class에 엄청나게 막중한 책임을 부과 하여, 점점 떼어내기 힘든 코드를 만들고 있었습니다. 예외처리를 위한 if else 코드가 늘어나는 경우가 부지기수였습니다.

껌딱지가 신발에 아주 끈질기게 달라 붙어 있다.

본론

이 때 코드스테이츠 크루에 최근에 합류하신 승환님이 “우리 클린아키텍처를 지향 해보는 것은 어떤가요?” 하고 주장 하시며, 개발팀에 layered architecture를 소개하고 세미나를 진행 하였습니다. layered architecture를 소개하시면서 grahphql 공식 홈페이지에 있는 다음과 같은 아키텍처를 지향하게 되었습니다.

역시나 공식 홈페이지에는 라이브러리 철학을 담고 있다. 많이 놓치지만.

이전에는 client to DB의 형식으로, 서버는 사실상 클라이언트가 테이블을 활용 하기 위한 interface 정도의 역할만 했다면, 위 아키텍처로 변경 했을 때는, 최상단 레이어에 어떤 인터페이스가 오건(rest던 graphql이던 기타 다른 프로토콜이건) 우리는 서비스 로직에만 충실하게 작성 하면 되도록 역할을 떼어낼 수 있었습니다.

그렇게 탄생한 유어클래스 서버의 아키텍처는 다음과 같습니다.

음 일단 복잡하긴 하다…

Presentation Layer에서 graphql 혹은 rest api 호출을 수신하고, 이를 Business Logic Layer인 Service Logic으로 넘겨줍니다. service logic에서는 실제로 우리 도메인 로직이 어떻게 돌아가는지 문장으로 써놓은 것 처럼 코드를 작성하게 됩니다. repository를 이용하여 데이터를 쿼리하거나 생성, 수정, 삭제를 하고, 필요한 데이터를 entity layer에서 자바스크립트 객체로 담아서 돌려줍니다.

현재는 entity를 차지하고있는 layer의 역할은 실제로 우리가 만든 도메인 모델, 즉 nodejs 기반으로 만들어진 프로젝트에서는 순수자바스크립트 객체여야 하지만, 현재는 orm의 model 선언을 겸임 하고 있습니다. 아직까지 그렇게 까지 분리 하는 것은 오히려 mapping cost가 늘어나는 것에 비해 효력은 없다고 판단하고 그렇게 진행 하였습니다.

이런식으로 서버아키텍처를 변경하고, 새로 생겨나는 코드들을 아키텍처에 맞게 작성 하다보니 이런 장, 단점을 느끼게 되었습니다.

장점

  • 정해진 아키텍처 위에서 코드를 작성하면, 잘못 짜기가 어려워진다.
  • ORM 바꾸기 위해 코드 전체를 갈아 엎어야 하는 일은 없어진다(필요한 부분만 떼어내면 된다)
  • 서비스 로직이 가독성이 높아져, 로직을 이해하기 쉽다.
  • 의존성이 아래로 향하기 때문에(궁극적으로는 entity로) 상단 layer에서 뭐가 아무리 바뀌어도 크게 개의치 않을 수 있다.

물론 장점만 있다면 거짓말 이겠죠. 아쉬운 점도 분명히 존재 합니다.

단점

  • layer 이동 간 type mapping을 수동으로 해주어야 하기 때문에, mapping cost가 무지 크게 발생하여, 작성해야 하는 코드 양 자체가 엄청나게 늘어난다.
  • (경험하진 않았지만) 하단 로직이 바뀌면 오히려 위로 모든 로직을 수정 하여야 할 것 같다?
  • layer 이동 간 type을 mapping 하기 위해 비슷해 보이는 class를 무지하게 선언 해야 한다.

layer 간 이동을 위해서 비슷한 클래스를 중복해서 선언 하는것이 매우 불필요 하다고 느껴 졌습니다. 하지만 나중에 알게된 사실로 각 클래스는 단일 책임을 져야하고, 비슷해 보이는 클래스는 사실 고도화 됨에 따라, 다른 요인에 의해서 다르게 변화될 수 있기 때문에, 이는 필수 불가결한 중복이었습니다. 클린아키텍처 책에서는 우발적 중복 이라고도 칭하고 있습니다.

결론

클라이언트에서 데이터베이스를 직접 쓰는 것 처럼, 서버를 active 데이터베이스 처럼 활용 하는 패턴으로 이전까지 코드를 작성해 왔고, 그 만큼 빠르게 api를 만들어 내는 성과를 얻었던 것 같습니다. 그리고 이는, 초반에 결정 할 수 있는 선택지 중 나쁘지 않은 선택이었다고 생각 합니다.

하지만, 코드스테이츠의 운영을 대부분 유어클래스에 담아 내기로 결정 하면서 서버가 훨씬 더 복잡해 질 것은 분명했고, 뿐만아니라 클린아키텍처를 지향 하는 건강한 개발자 승환님이 크루에 합류 하면서, 코드스테이츠 서버 아키텍처는 변신할 절호의 기회를 맞았다고 생각 했습니다.

이제 막 시작한 layered architecture는 코드스테이츠의 시스템이 더욱 복잡해 지고 어플리케이션이 더욱 고도화 되면서 그 빛을 발할 것이라 기대 하고 있습니다.

아직까지 OOP, DDD 혹은 SOLID 원칙 등, 클린아키텍처를 지향 하기 위해 공부 해야 할 것이 더 많습니다.

그래서 앞으로 코드스테이츠 개발팀은, 더욱 더 복잡해질 코드스테이츠의 운영을 위해 클린아키텍처를 지향 하기 위해 학습하고, 개발 크루의 성장을 위해 무거운 코드 리뷰를 지향 할 예정입니다.

--

--