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

Seungjae·2022년 5월 16일
0

우아한 스터디

목록 보기
2/10

계층형 아키텍처


Flow

  1. 맨 위의 웹 계층에서 요청을 받는다.
  2. 도메인 혹은 비즈니스 계층에 있는 서비스로 요청을 보낸다.
  3. 서비스에서는 필요한 비즈니스 로직을 수행한다.
  4. 이때 도메인 엔티티의 현재 상태를 조회하거나 변경하기 위해 영속성 계층의 컴포넌트를 호출한다.
  • 잘 만들어진 계층형 아키텍처는 선택의 폭을 넓히고, 변화하는 요구사항과 외부 요인에 빠르게 적응할 수 있게 해준다.

  • 일반적으로 로직 flow와 컴포넌트들의 의존성 flow가 일치하여 받아들이기 쉽다.

뭐가 문제지?


  • 코드에 나쁜 습관들이 스며들기 쉽게 만든다.
  • 시간이 지날수록 SW를 점점 더 변경하기 어렵게 만드는 수많은 허점들을 노출한다.

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

  • 전통적인 계층형 아키텍처의 토대는 데이터베이스

    • 위의 구조에서 의존성 구조를 따라가보면 자연스레 결국은 DB에 의존하게 될 것을 짐작할 수 있다.
  • 따라서 모든 것이 결국은 영속성 계층을 토대로 만들어진다.

  • 하지만 우리가 만드는 대부분의 애플리케이션은 상태가 아니라 행동을 중심으로 모델링한다.

    • 여기서 ‘상태 → 영속성, 행동 → 도메인 로직’ 으로 볼 수 있다.
    • 행동이 상태를 바꾸는 주체이기 때문에 행동이 비즈니스를 이끌어간다!
  • 하지만 계층형 아키텍처는 데이터베이스의 구조를 먼저 생각하고, 이를 토대로 도메인 로직을 구현하게 하는 데이터 중심적 사고를 유발한다.

  • 비즈니스 관점에서는 전혀 맞지 않는 방법이다.

    • 도메인 로직을 먼저 만들어야한다! → 우리가 로직을 제대로 이해했는지 확인 가능
    • 도메인 로직이 맞다는 것을 확인한 후, 이를 기반으로 영속성 계층과 웹 계층을 만들어야한다!
  • 이런 데이터베이스 중심적인 아키텍처가 만들어지는 가장 큰 원인은 → ORM

    • ORM + 계층형 아키텍처 ⇒ 비즈니스 규칙을 영속성 관점과 섞고 싶은 유혹
  • ORM에 의해 관리되는 엔티티들은 일반적으로 영속성 계층에 위치

  • 즉 위 그림과 같은 영속성 계층과 도메인 계층 사이에 강한 결합이 발생!

  • 서비스는 이로 인해, 영속성 계층과 관련된 작업들을 해야만 한다.

  • 영속성 코드가 사실상 도메인 코드에 침투하여 둘 중 하나만 바꾸는 것이 어려워진다!

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

  • 전통적인 계층형 아키텍처에서 전체적으로 적용되는 유일한 규칙특정 계층에서는 같은 계층에 있는 컴포넌트와 아래에 있는 계층에만 접근 가능

  • 만약 상위 계층에 위치한 컴포넌트에 접근해야 한다면?

    • → 그 컴포넌트를 계층 아래로 내려버린다.
    • 하지만 과연 이게 1번으로 끝날까? ⇒ 깨진 유리창 이론 → 하나 둘씩 이런 코드가 늘어가며 애플리케이션 전체로 퍼지게 된다.
  • 이런 상황이 쌓이며... 아래와 같은 그림의 현상 발생

  • 영속성 계층에서 모든 것에 접근 가능하기에 시간이 지나며 점점 비대해진다.

비대해지면 안돼?

  • 현재 상황에서 의존성 방향의 끝이며 변경하기 어려운 안정적인 컴포넌트여야하는 영속성 layer비대해지며 변경될 일(이유)이 많아지는 모순적인 일이 발생!

  • 변경하기도 힘들고 그로인해 부수효과가 얼마나 생길지 가늠조차 안되는 상태인데 계속 해서 변경해야하는 답도 없는 상황 발생...

테스트하기 어려워진다.

  • 계층형 아키텍처에서는 계층을 건너뛰는 현상이 발생하기도...

    • 엔티티 필드를 단 하나만 조작하는 경우 같은 굳이 도메인 계층을 거치지 않고, 간단하게 웹 계층에서 영속성 계층에 접근하면 해결될 것 같은 일들
  • 이것도 처음에는 편하고 좋아 보인다...

    • 하지만 → 깨진 유리창 이론
  • 결국 크게 2가지 문제가 발생

  1. 도메인 로직을 웹 계층에 구현
    1. 유스케이스가 확장된다면?
    2. 더 많은 도메인 로직을 웹 계층에 추가
    3. 결국 애플리케이션 전체적으로 책임이 섞이고 도메인 로직들이 퍼져나가게 된다.
  2. 웹 계층 테스트에서 도메인 계층뿐만 아니라 영속성 계층도 모킹해야...
    1. 테스트의 복잡도가 증가한다.
    2. 그로 인해 테스트를 작성하기 힘들어지고, 이로 인해 테스트를 작성하지 않게 된다!

유스케이스를 숨긴다.

  • 개발자들은 사실상 새로운 코드를 짜는데 시간을 쓰기보다는 기존 코드를 바꾸는 데 더 많은 시간을 할애한다.

  • 아키텍처는 코드를 빠르게 탐색하는데 도움이 돼야 한다.

  • 위에서 이야기했던 것처럼, 계층형 아키텍처는 도메인 로직이 여러 계층에 걸쳐 흩어지기 쉽다!

    • 새로운 기능을 어디에 넣어야 적당한지 찾기도 어려워질 수 있고, 찾고자 하는 기능과 관련된 코드를 찾기도 어려워질 수 있다!

  • 계층형 아키텍처는 도메인 서비스의 ‘너비’에 관한 규칙을 강제하지 않는다.

  • 즉 위처럼 아주 넓은 서비스가 만들어질 수 있다. (이 부분은 계층형 아키텍처가 아니라 뒤에 나오는 아키텍처에서도 주의하고 신경써야할 부분이라 생각한다.)

  • 넓은 서비스 → 코드 상에서 특정 유스케이스를 찾기 어렵다!

    • 또한 영속성 계층에 많은 의존성을 가지게 되며, 웹 계층의 많은 컴포넌트가 이 서비스를 의존!
    • 서비스를 테스트하기 어려워진다!
  • 고도로 특화된 좁은 도메인 서비스가 유스케이스 하나씩만 담당해야..!! (UserService → RegisterUserService)

□□□Service에 대해...

  • 난 사실 이 네이밍을 선호하지 않는다.

  • 이 네이밍 자체가 서비스의 너비를 넓히고, 많은 책임을 섞이게 만든다고 생각한다. 너무 넓은 범위를 아우르기 쉬운 네이밍인 것 같다.→ 이 부분에 대해서 고도로 특화된 좁은 도메인 서비스 네이밍을 잘하면 해결된다고 생각할수도 있을 것 같다.

  • 위 처럼 고도로 특화된 좁은 도메인 서비스가 필요하다는 개념이 잡히지 않은 개발자가 팀의 합류한다면? 그 사람이 과연 Service라는 네이밍이 붙은 클래스를 보며 무슨 생각을 할까?

    • 고도로 특화된 좁은 도메인 서비스를 만들까?
    • 또 UserService 같은 것들이 애플리케이션 전체적으로 퍼지게 될 가능성이 높아진다고 생각한다.

동시 작업이 어려워진다.

  • 일반적으로 프로젝트에 인원이 더 투입될수록 더 빠른 속도를 기대한다.

  • 하지만, 아키텍처가 동시 작업을 지원하는 것은 쉽지 않은 일이다.

  • 계층형 아키텍처에서 계층별로 맡아서 작업하기란 쉽지 않다. 모든 것이 영속성 계층 위에 만들어지기 때문에 아래 계층의 개발이 선행되어야한다.

  • 그렇기에 특정 기능은 동시에 한 명의 개발자만 작업할 수 있다.

  • 인터페이스를 이용하면 되지 않은가?

    • 데이터베이스 주도 설계를 하지 않은 경우만 가능!
    • 데이터베이스 주도 설계는 영속성 로직이 도메인 로직과 너무 뒤섞여서 각 측면을 개별적으로 작업 불가
  • 또한 코드에 넓은 서비스가 존재한다면, 서로 다른 기능을 동시에 작업하기가 더욱 어려워진다.

    • 같은 서비스를 동시에 편집하는 상황 발생
    • merge conflict같은 문제 야기

유지보수 가능한 소프트웨어를 만드는 데 어떻게 도움이 될까?


  • 계층형 아키텍처는 많은 것들이 잘못된 방향으로 흘러가도록 용인

  • 엄격한 자기 훈련 없이는 시간이 지날수록 코드 품질이 저하되고 유지보수하기 어려워진다.

  • 계층형 아키텍처의 함정을 염두하면, 유지보수하기에 더 쉬운 솔루션을 만드는 데 도움이 될 것이다!

profile
코드 품질의 중요성을 아는 개발자 👋🏻

0개의 댓글

관련 채용 정보