아키텍처 왜 쓸까

김주형·2022년 11월 16일
0

자라기

목록 보기
13/23
post-thumbnail

🙇🏻‍♂️ Reference


목표

  • 왜 객체지향, 아키텍처 등에 집착하는 건지 궁금해하던 중
  • 슈퍼 앱을 위한 노력이라는 영상을 보고
  • 해결해야 하는 과제가 복잡하고 많아지는 것에 대응하기 위함이라고 생각했습니다.
  • 이를 본받고자 조금이나마 도메인과 클린 아키텍처에 대해 학습했습니다.

계층형 아키텍처의 문제

2

Layer(계층형)를 이용하는 사고 방식은 우리에게 오랫동안 주입되어 왔다고 한다.

  • 웹 : 요청을 받아. 도메인(비즈니스) 계층에 있는 서비스로 요청을 보낸다.
  • 도메인(서비스 보유) : 서비스에서 필요한 비즈니스 로직을 수행한다.
    - 엔티티의 현재 상태를 조회하거나 변경하기 위해 영속성 계층 컴포넌트를 호출한다.
  • 영속성(엔티티) : 상태를 저장 / 관리한다.

견고한 아키텍처 패턴이고, 선택의 폭을 넓히며 변화하는 요구사항과 외부 요인에 빠르게 적응할 수 있게 해준다고 한다.

하지만 코드에 나쁜 습관들이 스며들기 쉽게 만들고 시간이 지날수록 점점 더 변경하기 어렵게 만드는 약점을 노출한다고 한다.

그 이유는 전통적인 계층형 아키텍처의 토대가 데이터베이스 이기 때문인다.
-> 모든 것이 영속성 계층을 토대로 만들어진다.

  • 대부분 애플리케이션의 목적은 보통 비즈니스를 관장하는 규칙이나 정책을 반영한 모델을 만들어서 사용자가 이러한 규칙과 정책을 더욱 편리하게 활용할 수 있게 해주는 것
  • 상태가 아니라 행동을 중심으로 모델링하게 됨.(행동이 상태를 바꾸는 주체이기 때문)
  • 그런데 왜 도메인 로직이 아닌 데이터베이스를 토대로 아키텍처를 만드는 걸까?

2

ORM 프레임워크 사용을 계층형 아키텍처와 결합하는 것에서 비즈니스 규칙을 영속성 관점과 섞게 되고, 영속성 코드가 도메인 코드에 녹아들어가서 둘 중 하나만 바꾸는 것이 어려워진다. 즉 ,강한 결합이 생긴다.
계층형 아키텍처 자체는 다른 규칙을 강제하지 않아 지름길을 택하기 쉬워진다고 한다.

3

  • 계층형 아키텍처에서는 같은 계층이나 아래 계층에만 접근이 가능하다.
  • 개발을 하다보면 상위 계층에 위치한 컴포넌트에 접근해야할 때가 있다. 이때 접근할 컴포넌트를 계층 아래로 내려버린다.
  • 한번이 어렵지 두번 세번은 쉽다.
  • 심리학에서는 이러한 이론을 "깨진 창문 이론"이라고 부른다.

대안 : 의존성 역전하기

단일 변경 이유 원칙

단일 책임 원칙(SRP) x : 하나의 객체는 오로지 한 가지일만 해야하고, 그것을 올바르게 수행해야 한다. ' 오로지 한 가지 일만 하는 것'

  • 단일 변경 이유 원칙 O : 컴포넌트(객체?)를 변경하는 이유는 오직 하나뿐이어야 한다. 이것이 진정한 단일 책임 원칙의 의도이다.

컴포넌트를 변경할 이유가 오로지 한 가지라면 어떤 다른 이유로 소프트웨어를 변경하더라도 전혀 신경 쓸 필요가 없다. 여전히 기대한대로 동작할 것이기 때문이다. 변경할 이유라는 것은 의존성을 통해 너무도 쉽게 전파된다.

의존성 역전 원칙

계층형 아키텍처에서 계층 간 의존성은 항상 다음 계층인 아래 방향을 가리킨다. 단일 책임 원칙을 고수준에서 적용할 때 상위 계층들이 하위 계층들에 비해 변경할 이유가 더 많다는 것을 알 수 있다.

-> 영속성 계층을 변경할 때마다 잠재적으로 도메인 계층도 변경해야 한다.
그러나 도메인 코드는 가장 중요한 코드다. 영속성 코드가 바뀐다고 해서 도메인 코드까지 바꾸고 싶지는 않다. 이 의존성을 어떻게 제거할 수 있을까?

의존성 역전 원칙(DIP) :코드 상의 어떤 의존성이든 그 방향을 바꿀 수(역전시킬 수) 있다.

의존성 역전은 어떻게 동작할까?

여기에 들어가면 다이어그램을 직접 그려보면서 이해해볼 수 있다!

  1. 도메인 계층에 서비스가 있다. 서비스는 영속성 계층의 엔터티, 리포지토리와 상효작용한다.
    2

  2. 엔티티는 도메인 객체를 표현하게 되고, 도메인 코드는 엔티티들의 상태를 변경한다.

    • 따라서 엔티티가 도메인 계층으로 올라오게 된다.
  3. 영속성 계층의 리포지토리가 도메인 계층에 있는 엔티티에 의존한다.

    • 두 계층 사이 순환 의존성이 발생한다.
    • 순환 의존성 : A가 B를 의존하는데 B가 A를 다시 의존하는 현상
  4. 도메인 계층에 리포지토리에 대한 인터페이스를 만들고, 실제 리포지토리는 영속성 계층에서 구현하게 한다.

d

영속성 코드에 숨막히는 의존성으로부터 도메인 로직을 해방시키는 방법이고,
다음 아키텍처 스타일의 핵심 기능이라고 한다.

클린 아키텍처

  • 도메인 코드가 바깥으로 향하는 어떤 의존성도 없어야 함. 대신, 의존성 역전 원칙 도움으로 모든 의존성이 도메인 코드로 향한다.
  • 모든 의존성은 도메인 로직을 향해 안쪽 방향으로 향한다!
    3
  • 의존성을 역전시켜 도메인 코드가 다른 바깥쪽 코드에 의존하지 않게 한다.
  • 영속성과 특화된 모든 문제로부터 도메인 로직의 결합을 제거한다.
  • 도메인 로직의 결합을 제거하고 코드를 변경할 이유를 줄일 수 있다.
  • 변경할 이유가 적을 수록 유지보수성이 더 좋아진다고 한다.
  • 도메인 코드는 비즈니스 문제에 딱 맞도록 자유롭게 모델링 될 수 있다.
  • 영속성 코드와 UI 코드도 영속성 문제와 UI 문제에 맞게 자유롭게 모델링 될 수 있다고 한다.

코드로 검증하기

public class Service {

    private Repository repository;
    private Entity entity;

    public void setRepository(Repository repository) {
        this.repository = new Repository();
    }

    public void setEntity(Entity entity) {
        this.entity = new Entity();
    }

}
public class Repository {

    private Entity entity;

    public void setEntity(Entity entity) {
        this.entity = new Entity();
    }

}
  1. 서비스는 영속성 계층의 엔터티, 리포지토리와 상효작용한다.

2

  1. 엔티티를 도메인 레이어로 끌어올리고 조금 정리해보면 순환 참조를 확인할 수 있다.

ㄴ

  1. 도메인 계층에 레포지토리 인터페이스를 생성한다.
public interface Repository{

    void manageEntityStatus();

}
  1. 영속성 계층에서 영속성 엔티티를 따로 생성하고, 레포지토리 구현체가 사용하도록 코드를 변경해준다.
    • 다음 그림과 일치하면 검증 완료!
      3
public class RepositoryImpl implements Repository {

    private PersistedEntity persistedEntity;

    @Override
    public void manageEntityStatus() {
       this.persistedEntity = new PersistedEntity();
    }

}
public class Service implements Repository{
    private Entity entity;

    @Override
    public void manageEntityStatus() {
        this.entity = new Entity();
    }
}

어라.. 그러고보니 리토지토리가 도메인으로 올라온 엔티티를 의존해야 되네..? 인터페이스가 클래스를 의존하나..?

이건 또 왜 ㅎ..
ㅇ

profile
도광양회

0개의 댓글