군만두의 IT 공부 일지

[스터디2] 05. 레이어드 아키텍처 본문

프로그래밍/객체지향

[스터디2] 05. 레이어드 아키텍처

mandus 2025. 1. 13. 15:50

목차

     

    이전 장에서 배웠던 레이어드 아키텍처에 대해 다루려고 합니다. 레이어드 아키텍처를 설계할 때 자주 발생하는 실수 중 하나는 개발 시작점을 잘못 설정하는 것입니다. 많은 개발자들이 데이터베이스 설계나 API 엔드포인트 정의부터 시작하는 경향이 있는데, 진정한 의미에서 레이어드 아키텍처를 구현하기 위해서는 도메인 중심의 설계를 기반으로 기술적 구현을 고려해야 합니다.

    8. 레이어드 아키텍처

    8.1 레이어드 아키텍처의 최소 조건

    • 레이어드 아키텍처는 애플리케이션을 레이어로 나누고 각 레이어에 역할을 정함. 대표적인 레이어는 프레젠테이션, 비즈니스, 인프라스트럭처가 있음.
    • 컴포넌트에 맞춰 레이어를 분류하는 것은 폴더를 관리하는 것과 다를 바 없음.
    아키텍처는 정책과 제약 조건을 이용해 목적을 달성함.
    • 레이어드 구조를 레이어드 아키텍처로 만들기 위해서는 레이어드 아키텍처에만 있는 제약 조건을 이해하고 사용하는 것이 중요함.
    • 레이어드 아키텍처의 최소 제약 조건
      1. 레이어 구조를 사용함. → 레이어드 아키텍처를 사용하므로 당연함.
      2. 레이어 간 의존 방향은 단방향으로 유지함. → 레이어 간 의존 방향이 양방향이 되면 레이어가 사라짐.

    8.2 잘못된 레이어드 아키텍처

    책에서 설명하는 레이어드 아키텍처의 문제는 프로젝트마다 상황이 다를 수 있음을 오해하지 말아야 함.

     

    Q. 계정(Account) 시스템의 백엔드를 만들어 달라고 했을 때 어떤 작업부터 할 것인가?

     

    유형 1: JPA 엔티티 우선, JPA 엔티티를 어떻게 만들지 고민함.(X)

    유형 2: API 엔드포인트 우선, 계정 시스템의 API 엔드포인트를 어떻게 만들지 고민함.(X)

    8.2.1 JPA 엔티티 우선 접근

    • 데이터베이스 테이블을 어떻게 만들지 고민하거나, JPA 엔티티가 어떻게 생겨야 하는지 고민했다는 의미임. → 객체지향스럽지 않음.
    • 잘못된 레이어드 아키텍처에 익숙한 사람일수록 JPA나 데이터베이스를 우선시하는 방향으로 생각하게 되는 경우가 많음.
    • 잘못된 레이어드 아키텍처는 레이어를 지나치게 추상화함.

    ▲ 인프라스트럭처 레이어부터 접근해 개발하는 방식

    • 가장 하단에 위치한 레이어가 인프라스트럭처 레이어이기 때문에 인프라스트럭처 레이어를 만들고, 비즈니스를 만들고, API 엔드포인트를 열어 서비스를 실행하도록 시스템을 만드는 접근법은 문제가 있음.
    • 이러한 접근법으로 만든 애플리케이션은 요구사항에 맞는 데이터베이스를 선택하는 것이 아닌 데이터베이스에 맞는 기능을 개발하는 방향으로 발전함. 즉, 프로그램이 데이터베이스에 종속됨.

    8.2.2 API 엔드포인트 우선 접근

    • 시스템을 인터페이스 관점에서 어떻게 사용해야 할지 먼저 떠올려서 컨트롤러를 먼저 생각함. 핸들러를 어떻게 작성해야 할지 고민하고 어떤 매개변수가 필요한지, 요청의 형태나 응답은 어때야 하는지를 고민함.

    ▲ 프레젠테이션 레이어부터 접근해 개발하는 방식

    • 시스템을 도메인 요구사항 관점에서 본다는 점에서 JPA 엔티티를 우선하는 접근 방식보다 나음. 하지만 프로젝트가 스프링 프레임워크에 종속될 수 있음.
    • 요청과 응답의 형식을 어떻게 할지 고민하다 보면 자연스럽게 어떤 데이터가 들어가야 하는지 고민하면서 트랜잭션 스크립트 같은 코드가 탄생함.

    8.2.3 본질을 다시 생각하기

    • 지나치게 의존한다는 말은 애플리케이션이 그것 없이는 설명할 수 없는 상태라는 의미임. 백엔드 개발자로 성장하고 싶으면 스프링이나 JPA 없이도 성립할 수 있는 애플리케이션을 만들 수 있어야 함. 즉, 순수 자바 코드로 객체지향적인 애플리케이션을 먼저 만들 수 있어야 함.
    • 애플리케이션의 본질은 도메인임. 애플리케이션을 개발하는 것은 도메인을 파악하고, 이에 따른 도메인 모델을 구성하고, 도메인 모델을 표현하는 데 적합한 언어를 선택하고, 도메인 모델을 만들고, 도메인 기능을 제공할 기술을 선택하는 것임. 즉, 도메인에 따른 기술 스택(스프링, JPA)이 결정되어야 함.
    • 오늘날 JVM 언어를 다루는 백엔드 개발자들은 서버를 만들 때 거의 스프링과 JPA를 쓰지만, 목적에 맞는 기술 스택을 찾고 장단을 비교하여 선택을 최후까지 미룰 수 있어야 함.

    8.3 진화하는 아키텍처

    시스템 개발의 첫 시작을 도메인으로 두면 됨.

    8.3.1 인지 모델 변경하기

    도메인을 개발하려면 비즈니스 레이어부터 개발하면 됨.
    • 서비스 컴포넌트는 비즈니스 레이어에 속하는 컴포넌트이지만, 비즈니스 레이어는 도메인까지 포함하는 개념임. 따라서 비즈니스 레이어, 그리고 비즈니스 레이어 중에서 도메인을 가장 먼저 개발해야 함.
    • 계속 잘못된 접근을 하고 있는 이유는 레이어드 아키텍처에 대한 인지 모델이 잘못됐기 때문임. 도메인이 눈에 안 들어오니 도메인 레이어를 바깥으로 드러내면 다음과 같이 변경할 수 있음.

    ▲ 도메인 레이어를 바깥으로 드러내는 방식

    • 비즈니스 레이어에서 도메인을 분할하여 도메인 레이어(domain layer)라는 이름으로 인지 모델에 추가함. 도메인 레이어는 비즈니스 도메인을 표현하는 클래스가 모이는 곳임.
    • 도메인 레이어는 종종 common, core 패키지에 작성되지만, 프로젝트 공통 코드(유틸 클래스, 설정을 위한 클래스)를 모아서 관리하는 것은 도메인의 목적이 아님. 도메인 레이어의 목적은 애플리케이션에서 사용하는 주요 도메인 객체들을 표현하는 것임.
    • 패키지와 레이어는 다름. 레이어를 표현하기 위한 수단으로 패키지를 사용할 수 있지만, 패키지 하나하나가 레이어드 아키텍처의 모든 레이어에 대응해야만 하는 것은 아님.
    // 모든 패키지가 레이어드 아키텍처의 레이어에 일대일로 대응해야 하는 것은 아님.
    project
    └── src.main.java
                └── com.demo.cafe
                            ├── presentation
                            ├── business
                            ├── domain
                            ├── infrastructure
                            ├── aop		// AOP(관점 지향 프로그래밍) 관련 코드를 모아두는 패키지
                            ├── config	// 프로그램 개발에 필요한 설정 클래스를 모아두는 패키지
                            └── util	// 유틸리티 클래스를 모아둔 패키지
    • 도메인 레이어에 있는 객체들을 작성할 때는 순수 자바 코드로 작성해야 함. 도메인 레이어를 외부 라이브리러에 의존하지 않고 자유롭게 만들기 위함임. 외부 연동이 필요하다면 의존성 주입을 사용해 연동된 컴포넌트를 언제든 교체할 수 있게 만듦. 스프링이나 JPA 없이 도메인 레이어를 개발할 수 있음.
    • 도메인 없는 비즈니스 레이어는 비즈니스 레이어라고 부를수 없음. 그래서 비즈니스 레이어의 이름을 애플리케이션(Application, 응용) 레이어라는 이름으로 변경함.

    ▲ 비즈니스 레이어의 이름을 애플리케이션 레이어로 변경한 방식

    비즈니스 레이어 = 애플리케이션 레이어 + 도메인 레이어
    • 위와 같이 비즈니스 레이어를 설명하라는 질문에 구체적이고 실무적인 답을 할 수 있음.
    • 7장에서 서비스는 J2EE 패턴 중 하나인 비즈니스 서비스 파사드처럼 사용될 수 있다고 함. 즉, 애플리케이션 레이어에 위치한 서비스 컴포넌트는 도메인 레이어의 파사드가 되었음.
    • JPA나 스프링 없이도 도메인 레이어에 애플리케이션에 필요한 주요 기능들을 개발할 수 있음. 그러니 어떤 시스템을 만들어 달라는 요청을 받으면 이 도메인 레이어를 어떻게 만들지부터 고민하면 됨. 풍부한 도메인 객체를 먼저 만든 후, 그 객체들을 뒷받침할 JPA 엔티티나 스프링 컴포넌트를 추가하면 됨.
    • 영속성 객체와 도메인 객체를 변환하는 매핑 메소드를 통해 도메인 영역 개발과 스프링/JPA를 이용한 개발을 분리해서 개발할 수 있음.
    • 도메인 레이어가 인프라스트럭처 레이어 위에 존재하지만 도메인 레이어는 인프라스트럭처 레이어를 참조하지 않음. 도메인이 의존하는 외부 레이어가 존재하지 않음. 즉, 도메인 레이어는 JPA 라이브러리나 스프링 라이브러리를 임포트하면 안 됨.

    8.3.2 JPA와의 결합 끊기

    • 인프라스트럭처 레이어에 위치한 JPA 코드를 수정한다면, 변경에 다른 영향 범위는 프레젠테이션 레이어와 애플리케이션 레이어임. 인프라스트럭처 레이어의 구성이 달라져도 애플리케이션 레이어가 영향을 받지 않는 구조로 애플리케이션을 설계해야 함. → 의존성 역전 사용

    ▲ 주력 데이터베이스를 MongoDB로 변경한 후 JPA에서 MongoDB 라이브러리로 변경해도 애플리케이션의 항상성 유지 가능

    8.3.3 웹 프레임워크와의 결합 끊기

    • 애플리케이션 레이어와 인프라스트럭처 레이어에 의존성 역전을 적용함으로써 데이터베이스의 형태에 영향을 받지 않는 애플리케이션 설계를 얻음. 이 원리를 프레젠테이션 레이어에도 적용하는 것에 2가지 해석이 존재함.
      1. 긍정적 의견:
        • 경계를 강제할 수 있게 됨.
        • 외부 세계와 내부 세계에서 벌어지는 모든 일에 일관된 패턴을 적용할 수 있음.
        • 프레젠테이션 레이어에 있는 컴포넌트를 테스트해야 할 때 테스트가 쉬워짐.
        • 헥사고날 아키텍처를 근거로 프레젠테이션 레이어와 애플리케이션 레이어에 의존성 역전을 적용해도 됨.
      2. 부정적 해석:
        • 의존성 역전을 적용했을 때 얻을 수 있는 실효성이 모호함.
        • 의존성 역전을 적용하지 않아도 도메인 모델은 외부 세계에 독립적임.
        • 애플리케이션 레이어가 프레젠테이션 레이어에 의존하는 것이 부자연스러움.
        • 프레젠테이션 레이어의 코드는 보통 재사용될 수 없음.
      3. 평가: 문제 상황에 놓였을 때 선택할 수 있는 가능성을 나열하고 장단을 비교해 적용 여부를 판단하면 됨.

    8.4 새로운 접근법

    • 레이어드 아키텍처의 문제를 해결하기 위해 도메인 레이어부터 개발하는 것은 상향식 접근법임. 도메인을 우선 개발하는 상황에서 도메인을 개발하고, 애플리케이션 서비스를 개발하고, 애플리케이션 서비스가 사용될 인터페이스를 구성함. 마지막으로 이에 대응하는 컨트롤러, JPA를 만들어 시스템을 완성해야 함.
    • 아키텍처의 핵심은 생김새가 아니라 왜 이런 형태를 띠고 있는지가 중요함.

    8.5 빈약한 도메인

    • 실무에서 발생하는 모든 시간 투자는 전부 비용으로 연결됨. 프로젝트의 성공 실패를 장담할 수 없는 상황이라면, 복잡한 아키텍처와 유연한 설계보다 고정된 기술 스택과 직관적인 아키텍처를 사용하는 편이 더 나음. 하지만 이러한 주장은 아래와 같이 반박될 수 있음.
      1. 프로젝트의 성공 실패를 장담할 수 없음. → 프로젝트가 안정화되고 나면 프로젝트를 언젠가 확장할 수 있는 상태로 빠르게 전환해야 함. 아니면 후발 주자에게 기회를 빼앗길 수 있음.
      2. 요구사항이 단순함. → 우리 서비스는 빈약한 도메인을 갖고 있다고 말하는 것과 다를 바 없음. 누구나 비슷한 서비스로 경쟁에 뛰어들 수 있으므로, 성공한 서비스는 진화하면서 대개 요구사항이 점점 다양하고 복잡해질 수밖에 없음.

     

    유형 1처럼 JPA 엔티티를 우선으로 설계를 시작했던 스스로를 반성하게 만드는 것 같습니다. 책에서 지적하고 있는 프로젝트를 시작할 때 엔티티부터 설계하고 컨트롤러부터 만드는 방식을 모두 제가 수용하고 있었다는 것을 깨닫게 된 것 같습니다.

    이 글은 『자바/스프링 개발자를 위한 실용주의 프로그래밍』 책을 학습한 내용을 정리한 것입니다.
    Comments