계층형 아키텍처의 문제

풀어갈 나의 이야기·2022년 7월 31일
1

개요

  • 우리는 모두 낮은 개발비용으로 유연하고 적응이 쉬운 소프트웨어 아키텍처를 구축하고자 한다.
    이번 시리즈물을 통해 전통적인 계층형 아키텍처 스타일과 이 스타일의 단점, 나아가 클린아키텍처를 위한 지름길에 대해 알아보고, 육각형 아키텍처 스타일의 애플리케이션을 만드는데 필요한 지식을 나열해 본다.

1. 계층형 아키텍처의 문제는 무엇일까?

  • 계층(Layer)로 구성된 웹 애플리케이션을 개발하다보면, 계층이란 구조에 대해 늘 고민하는 선택사항일 것이다.
    계층을 이용하는 사고방식은 컴퓨터 과학 수업이나, 튜토리얼, 혹은 수많은 모범사례를 통해 우리에게 주입돼 왔다.
    심지어 여러 책에서도 계층에 대해 배웠다.

일반적 전통 웹 애플리케이션 구조의 FLOW

  • 위 그림은 상위수준 관점에서 일반적인 3계층 아키텍처를 표현한 그림이다.
    맨위에 웹 계층에서 요청을 받아 도메인 혹은, 비니지스 계층에 있는 서비스로 요청을 보낸다.
  • 서비스에서는 비지니스 로직을 수행하고, 도메인 엔티티의 현재상태를 조회하거나 변경하기 위해 영속성 계층 컴포넌트를 호출한다

사실 계층형 아키텍처는 견고한 아키텍처 패턴이다. 잘 이해하고 구성한다면, 독립적으로 도메인 로직을 작성할 수도 있다.
잘 만들어진 계층형(Layer) 아키텍처는 선택의 폭을 넓히고, 변화하는 요구사항과 외부요인에 빠르게 적응할 수 있게 해준다.

계층형 아키텍처의 문제점은 무엇일까?

계층형 아키텍처는 코드에 나쁜습관들이 스며들기 쉽게 만들고, 시간이 지날수록 소프트웨어를 점점 더 변경하기 어렵게 많드는 허점을 노출한다.

1.1 계층형 아키텍처는 데이터베이스 주도 설계를 유도한다.

  • 정의에 따르면 전통적인 계층형 아키텍처의 토대는 DB 이다.
    웹 계층은 도메인 계층에 의존하고, 도메인 계층은 영속성 계층에 의존하기 때문에 자연스럽게 DB에 의존할 수 밖에 없게된다.
    그렇다는건 곧 모든 것이 영속성 계층을 토대로 만들어진다. (이런 방식은 다양한 이유로 문제를 초래한다.)

  • 우선 우리가 만드는 대부분의 애플리케이션의 목적이 무엇인가?

    • 우린 규칙이나 정책을 반영한 모델을 만들어서, 사용자가 이런 규칙과 정책을 더욱 편리하게 활용할 수 있게 해야한다.
  • 이때 우리는 상태(state)가 아니라 행동(behavior) 을 중심으로 모델링한다.

    • 행동이 상태를 바꾸는 주체이기 때문에 행동이 비지니스를 이끌어 간다.

왜 '도메인 로직'이 아닌 '데이터베이스'를 토대로 아키텍처를 만들까?

  • 일단 우리는 습관적으로 과거를 떠올려보면, 데이터베이스 구조를 먼저 생각하고 , 이를 토대로 도메인 로직을 구현했을 것이다.
    • 전통적 계층으로 본다면, 틀린방법이 아니다.
    • 하지만 비지니스 관점에선 전혀 맞지 않는 방법이다. (무조건 도메인 로직을 먼저 만들어야 한다.)
  • 그래야만 우리가 로직을 제대로 이해했는지 확인 할 수 있다. (도메인 로직에 확신이 있어야, 영속성 계층 (DB포함) 과 웹계층 (컨트롤러 등)을 만들어야 한다.

왜 이렇게 만들수 밖에 없었을까?

  • 데이터베이스 중심의 아키텍처가 만들어지는 가장 큰 원인은 ORM(object-relational mapping) 프레임워크를 사용하기 때문이다.
    (ORM 프레임워크를 계층형 아키텍처와 결합하면 유혹을 쉽게 받기 때문이다.)

  • 도메인 계층에서 데이터베이스 엔티티를 사용하는 것은 영속성 계층과 강한 결합을 유발한다.

위 그림과 같이 ORM 에 의해 관리되는 엔티티들은 일반적으로 영속성 계층에 둔다.
계층은 아래방향으로만 접근 가능하기 때문에 도메인 계층에서는 엔티티에 접근이 가능하다.

  • 하지만 영속성 계층과 도메인 계층 사이에 강한 결합이 생기게 된다.
    영속성 모델을 비지니스 모델처럼 사용하게 되버리고, 이로 인해 도메인 로직 뿐만아니라, 즉시로딩(eager loading) 지연로딩(lazy loading), DB 트랜젝션, 캐시초기화 (flush) 등 영속성 계층과 관련된 작업을 해야만한다.
  • 영속성 코드가 사실상 도메인 코드에 녹아들어가, 둘중 하나만 바꾸는것이 사실상 불가능해진다.

1.2 지름길을 택하기 쉬워진다.

전통적인 계층형 아키텍처에 전체적으로 적용되는 유일한 규칙은, 특정 계층에서는 같은 계층에 있는 컴포넌트나 아래에 있는 계층에만 접근 가능하다는 것이다.
(팀내 정형화된 합의 외에, 다른 규칙을 강제하지는 않는다.)

  • 따라서 만약 상위계층에 위치한 컴포넌트에 접근해야 한다면, 컴포넌트 계층을 아래로 내려버리면 된다.
    문제점은 딱 한번은 괜찮을 수 있다. 하지만 대수롭지 않게 매번 내린다면 그건 아키텍처라고 하기 어렵다.
    이런 지름길을 대부분의 개발자들은 대수롭지 않게 여긴다. (다는 아니겠지만.. 누군가는 그럴것이다.)
    그러면 나또한 죄책감이 덜하기 때문에 그렇게 할 위험이 크다. 이를 두고 심리학에서는 깨진 창문이론 이라 부른다.

  • 영속성 계층에서는 모든것에 접근이 가능하기 때문에 점점 비대해진다.
  • 결국 수년에 걸친 개발이 이루어진 프로젝트가 있다면, 위 그림처럼 구조가 될 확률이 크다.
    딱 보아도, 헬퍼 컴포넌트나 유틸리티 컴포넌트들이 아래 계층으로 내릴 가능성이 크지 않나??

지름길 모드를 끄고싶다면?

  • 추가적인 아키텍처 규칙을 강제하지 않는 한 계층은 최선의 선택이 아니다.
    여기서 강제한다는 것은 시니어가 코드리뷰를 하는게 아니라, 해당 규칙이 깨졌을때 빌드 자체가 실패해버리도록 만드는 규칙을 의미한다.

1.3 테스트하기 어려워진다.

이런 계층형 아키텍처의 가장 큰 문제중 하나는, 계층을 건너뛰어버릴 수도 있다.
엔티티 필드를 단하나만 조작하면 되는 경우에 웹 계층에서 바로 영속성 계층에 접근하면, 도메인 계층을 건드릴 필요가 없지 않나??

  • 이 구조처럼 건너뛰는 것은 도메인 로직을 코드 여기저기에 흩어지게 만든다.

다시 말하지만 처음 몇번은 괜찮다고 생각된다. 하지만 자주 일어나다보면, 두가지 문제점이 반드시 발생할 것이다.

문제 1. 단 하나의 필드를 조작하는것에 불과하더라도, 도메인 로직을 웹 계층에 구현하게 된다는것.

문제 2. 웹 계층 테스트에서 도메인 계층 뿐만 아니라, 영속성 계층까지 들어가야 된다는것.

시간이 흘러 웹 컴포넌트의 규모가 커지면, 영속성 컴포넌트에 의존성이 많이 쌓이면서 테스트의 복잡도를 매우 높혀버린다.
(그러면 mock 잡는데 시간이 훨씬 많이 걸릴것이다.)

1.4 유스케이스를 숨긴다.

개발자들은 새로운 유스케이스를 구현하는 새로운 코드를 짜는걸 선호한다.
기능을 추가하거나, 변경할 적절한 위치를 찾는 일이 빈번하기 때문에 아키텍처는 코드를 빠르게 탐색하는 데 도움이 되야 한다.
이런 관점에서 계층형 아키텍처는 무엇이 문제일까?

  • 앞서 말했듯 계층형 아키텍처에서는 도메인 로직이 여러 계층에 걸쳐 흩어지기 쉽다.
    유스케이스가 '간단' 해서 도메인 계층을 생략한다면, 웹 계층에 존재할 수도 있고, 도메인 계층과 영속성 계층 모두에서 접근할 수 있도록 컴포넌트를 내렸을 경우, 영속성계층에 존재해 버릴수도 있다.
    새로운 기능을 추가할때?? 계층이 다 깨져버려서, 적당한 위치를 찾기가 정말 어려울 것이다.

  • 넓은 서비스는 코드 상에서 특정 유스케이스를 찾는 것을 어렵게 만든다.
  • 위 그림을 보면, 영속성 계층에 너무많은 의존성을 가지게 되고, 다시 웹 레이어의 많은 컴포넌트가 이 서비스에 의존해야 한다.
    (테스트가 어려워지고, 책임지는 서비스를 찾기도 너무 어려워진다.)

1.5 동시 작업이 어려워진다.

일반적으로 경영진은 예산을 들이고, 소프트웨어가 특정 날짜에 완성되길 바란다. (이 때 논의를 복잡하게 만들지는 말자)

맨먼스 미신을 읽지 않았더라도, 아래의 유명한 결론은 알것이다.
"지연되는 소프트웨어 프로젝트에 인력을 더하는 것은 개발을 늦출 뿐이다."

  • 맨먼스 미신: 소프트웨어 공학에 관한 에세이 중..
  • 상황을 생각해보자. 50명의 개발자가 메달려 있는 SW가 10명이 되는 SW보다 5배 빠르다고 기대할수 있나?
    퀄리티가 5배 좋다고 기대할 수 있을까?
  • 절대 아니다. 그럴수도 있지만, 대부분은 인원이 많다고 빠르거나 퀄리티가 높지 않다.
    이러한 기대를 충족시키려면 아키텍처가 동시 작업을 지원해야 하지만, 이렇게 하기란 쉽지 않기 때문이다.
    계층형 아키텍처는 이런 측면에서 그다지 도움이 되지 않는다. \
    • 예를들어, 너는 도메인,나는 영속성, 너는 웹 이렇게 하면 계층형아키텍처는 이게 가능한가??
      서로 연관되있어서 한쪽이 끝날때까지 기다려야 하는 상황이 와버린다.
  • 코드에 넓은 서비스가 있다면, 서로다른 기능을 동시에 작업하기란 더더욱 어렵다. (merge conflict 는 기본일것이다.)

1.6 그래서 결론은?

과거 계층형 아키텍처를 만들어 봤다면, 논의한 단점들이 익숙하고 심지어 다른단점도 겪었을 것이다.
올바르게 설계하고 추가적인 규칙들을 적용하면,
계층형 아키텍처는 유지보수하기 매우 쉬워지며 코드를 쉽게 변경하거나 추가할 수 있게 된다.

  • 중요한건 앞에 본 예시들처럼 계층형 아키텍처는 많은 것들이 잘못된 방향으로 흘러가도록 용인한다.
    이제부터 하나씩 보다나은 설계점과 아키텍처를 고민해보고, 함정을 염두해 두어 도움이 되는 아키텍처를 만들어보고자 한다.

Refference

profile
깨끗한 스케치북 일수록 우아한 그림이 그려지법, 읽기 쉽고, 짧은 코드가 더 아름다운 법.. 또한 프로그래머의 개발은 구현할 프로그래밍이 아닌, 풀어갈 이야기로 써내려가는것.

0개의 댓글