////
Search
Duplicate
🌜

Chapter 08. 레이어드 아키텍처

이 장에서는 일반적인 개발자들이 생각하는 레이어드 아키텍처는 무엇이며 그로 인해 발생하는 문제점이 무엇인지 살펴본다.
그리고 레이어드 아키텍처를 어떻게 개선할 수 있는지 함께 살펴본다.

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

레이어드 아키텍처는 단순하며서도 직관적인 구조로, 많이 소개되곤 하는 아키텍처로 어플리케이션을 레이어로 나눠, 각 레이어의 역할을 정한다.
대표적인 레이어로는 프레젠테이션, 비즈니스, 인프라스트럭쳐 같은 레이어가 있다.
레이어드 아키텍처와 관련해 한 가지 유념해야 할 사실은, 이를 만든 사람이 존재하지 않는다는 것이다. 이 아키텍처는 누군가의 철학에 의해 만들어진 것이 아닌, 여러 개발자의 필요에 의해 발전된 아키텍처다.
누군가는 레이어드 아키텍처를 헥사고날 아키텍처 수준으로 사용하고, 누군가는 이 아키텍처를 폴더를 관리하는 수준으로밖에 사용하지 못한다.
레이어드 아키텍처에서 중요한 것은 레이어 유형을 외우고 그에 맞게 컴포넌트를 배치하는 것이 아니라 다음과 같은 사항을 지키는 것이 중요하다.
레이어 구조를 사용한다.
레이어 간 의존 방향은 단방향으로 유지한다.
레이어 간 통신은 인접한 레이어에서만 이뤄지게 한다.
레이어드 아키텍처에서는 이같은 제약 조건이 중요하다. 아키텍처는 제약 조건으로 만들어지기 때문이다.
그렇다면 아키텍처는 왜 제약 조건으로 이뤄지는 걸까? 아키텍처는 제약 조건을 이용해 개발자가 해도 되는 것과 하지 말아야 하는 것을 결정한다. 더 나아가 해서는 안 되는 일이 개발 단계에서 발생하지 않게 원천 차단한다.
저자는 이러한 이유로 아키텍처를 정책과 제약을 정하는 과정이라고 해석한다. 따라서 아키텍처를 적용한다는 것은 제약 조건을 만든다는 것이며 이를 프로젝트에 적용해 코드를 일관되고 논리적으로 만드는 것이라 생각한다.
또한 아키텍처는 제약 조건을 목적을 달성하기 위해 사용한다. 즉, 같은 아키텍처를 사용하더라도 목적에 따라 제약 조건이 달라질 수 있다는 의미다.
저자에게 있어서 레이어드 아키텍처를 위한 최소 제약 조건은 다음과 같다.
레이어 구조를 사용한다.
레이어 간 의존 방향은 단방향으로 유지한다.

2. 잘못된 레이어드 아키텍처

계정을 만들어 달라는 요구사항이 들어왔을 때

1. JPA 엔티티 우선 접근

이는, 테이블을 어떻게 만들지 고민하거나 JPA 엔티티가 어떻게 생겨야 하는지 고민했다는 의미다.
이러한 접근 방식은 객체지향스럽지 않다. 데이터 위주의 사고 방식이기 때문이다.
이러한 접근법으로 만들어진 어플리케이션은 요구사항에 맞는 데이터베이스가 선정되는 것이 아니라 데이터베이스에 맞는 기능을 개발하는 방향으로 발전할 수 밖에 없다.
이를 두고 프로그램이 데이터베이스에 종속되었다고 한다.
즉, JPA 엔티티를 우선으로 개발하겠다는 것은 레이어드 아키텍처에서 인프라 → 비즈니스 → 컨트롤러 순의 접근 방식을 채택하겠다는 의미다.

2. API 엔드포인트 우선 접근

이는 시스템을 인터페이스 관점에서 어떻게 사용해야 할지를 먼저 떠올린다. 그래서 컨트롤러를 먼저 생각한다.
생각의 흐름은 자연스럽게 컨트롤러가 어떻게 만들어져야 하는지를 고민한 뒤, 비즈니스 로직을 고민하고 마지막으로 인프라스트럭처와 JPA 엔티티를 고민하는 식으로 이뤄진다.
이는 컨트롤러 → 비즈니스 → 인프라 순의 접근 방식을 선택하게 되며 이런 접근 방식 또한 결국 특정 프레임워크에 종속되는 결과를 낳는다.
객체지향스러운 코드를 얻기 위한 첫 단추로 무엇을 고민해야 할까? DB나 UI같은 레이어의 세부사항에 의존하지 않는 본질적인 것은 뭘까?

3. 본질을 다시 생각하기

레이어드 아키텍처 구조에서 상향식이든 하향식이든 썩 괜찮은 결과를 얻기는 힘들다는 결론에 다다른다.
상향식에서는 DB를 먼저 고민하게 되어 프로그램이 영속성 프레임워크에 과하게 의존하게 되며 반대로 하향식에서는 컨트롤러를 먼저 고민해 어플리케이션 프레임워크에 과하게 의존하게 된다.
진정한 의미의 백엔드 개발자가 되고 싶다면 어떤 툴에 종속되지 않고도 성립할 수 있는 어플리케이션을 만들 수 있어야 한다.
TCP/IP를 직접 구현해서 웹 어플리케이션 서버를 만들어야 한다는 의미가 아니다.
어플리케이션이 특정 기술에 종속되지 않아야 한다는 것이다. 그러기 위해서 순수 자바 코드로 객체지향적인 어플리케이션을 만들 수 있어야 한다.
어플리케이션의 본질은 도메인이다. 개발은 결국, 도메인을 파악하고 이에 따른 도메인 모델을 구성하고, 도메인 모델을 표현하는 데 적합한 언어를 선택해 도메인 모델을 만들고, 도메인 기능을 제공할 기술을 선택하는 것이다.
아키텍처에 관한 격언 중, 세부 사항에 대한 결정은 최대한 뒤로 미뤄라라는 말이 있다. 여기서 스프링과 JPA는 세부 사항이다. 도메인에 따른 기술 스택이 결정되어야 한다.
그래서 결국 시스템 개발을 위한 첫 단추는 무엇이 되어야 하는 걸까?

3. 진화하는 아키텍처

당연하게도 시스템 개발의 첫 단추를 도메인으로 두면 된다.
어플리케이션에서 가장 중요한 것은 도메인이다. 그래서 시스템 개발은 도메인 분석과 도메인 개발에서 출발해야 한다.

1. 인지 모델 변경하기

개발의 첫 시작인 도메인부터 개발하려면 어떤 레이어에서부터 시작하는 것이 좋을까?
비즈니스 레이어부터 개발하면 된다고 생각할 것이다. 여기서 의구심이 하나 들텐데, 일반적으로 비즈니스 레이어에 해당하는 컴포넌트는 스프링의 서비스 컴포넌트라는 인식이 많다.
서비스 컴포넌트는 분명 비즈니스 레이어에 속하는 컴포넌트지 서비스 컴포넌트가 곧 비즈니스 레이어는 아니기 때문이다. 비즈니스 레이어는 도메인까지 포함하는 개념이다.
이런 인지 모델을 변경해야 한다. 컨트롤러 → 비즈니스 → 인프라의 계층에서 서비스를 도메인과 서비스로 분할하는데, 도메인은 객체지향적인 도메인 모델들이 활동하는 영역이 된다.
그리고 이러한 도메인 레이어들은 순수 자바 코드로 작성되어야 한다. 이는 도메인 레이어가 외부 라이브러리에 의존성을 가지지 않고 충분히 자율적인 객체가 되게끔 하기 위함이다.
저자는 여기서 비즈니스 레이어 = 어플리케이션 레이어 + 도메인 레이어라는 인지 모델을 제안한다.
이를 통해 우리는 도메인을 어플리케이션으로부터 분리할 수 있고, 그 책임을 명확하게 할 수 있다.
순수 자바 코드로 작성하게 되면서 얻는 장점이 하나 더 있는데, 이는 도메인 레이어를 스프링이나 JPA 없이도 개발할 수 있다는 점이다.
⇒ 롬복은 괜찮나? 싶었는데, 저자분께서 표현력 측면에서 사용해도 괜찮지 않나라는 입장이시며 조금 더 엄격한 조직이라면 롬복 또한 배제될 수 있음을 언급해주셨다.
우리는 JPA나 스프링 없이도 도메인 레이어에 어플리케이션에 필요한 주요 기능들을 개발할 수 있다. 그러니 이제는 요구사항이 들어왔을 때, 도메인 레이어를 어떻게 만들지부터 고민하자.
마지막으로 주의할 점이 하나 있는데, 도메인 레이어가 인프라 레이어 위에 존재하지만 도메인 레이어는 인프라 레이어를 참조하지 않는다는 사실이다.
더 나아가 도메인 레이어는 참조하고 있는 외부 레이어가 존재하지 않는다. 오직 참조될 뿐이어야 한다.

2. JPA와의 결합 끊기

의존성 역전을 사용해서 의존성 흐름을 역전시켜 결합도를 낮추는 방식을 이용해, 어플리케이션 레이어를 격리시키라는 내용이었다.

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

의존성 역전의 원리를 프레젠테이션 레이어에도 적용시킨 것이다.
이에 대해선 상반된 견해가 존재한다.
긍정적 해석
의존성 역전을 이용해 더 유연한 구조를 갖게 됐으니 좋은 구조다라는 해석이다.
분명 타당한 해석으로, 이 주장을 뒷받침할 수 있는 이론으로 헥사고날 아키텍처도 있다.
이렇게 진화된 레이어드 아키텍처는 시스템의 변경 사항이 최소화되고 유지보수 및 테스트가 용이해진다. 더불어 점점 헥사고날 아키텍처로 그 진화의 방향성이 결정된다.
부정적 해석
굳이 프레젠테이션 레이어에 의존성 역전까지 적용할 필요가 있느냐는 주장이다.
이 주장의 요지는 의존성 역전을 적용해 얻을 수 있는 이점이 모호하다는 것이다.
스프링은 웹 어플리케이션 서버를 만드는 프레임워크다. API에 종속된 개념이 아니므로 충분히 변경될 요지는 존재한다는 것이다.
⇒ 실행 주체가 컨트롤러가 아닌 메시지 리스너로 변경된다던지 말이다.
결과적으로 프레젠테이션 레이어에 의존성 역전을 적용하지 말지는 개발자마다 의견이 다를 수 있으며 앞서 해석들을 정리하면 다음과 같다.
긍정적 의견
경계를 강제할 수 있게 된다.
외부 세계와 내부 세계에서 벌어지는 모든 일에 일관된 패턴을 적용할 수 있다.
프레젠테이션 레이어에 있는 컴포넌트를 테스트해야 할 때 테스트가 쉬워진다.
부정적 의견
의존성 역전을 적용했을 때, 얻을 수 있는 실효성이 모호하다.
의존성 역전을 적용하지 않아도 도메인 모델은 충분히 외부 세계에 독립적이다.
어플리케이션 레이어가 프레젠테이션 레이어에 의존하는 것이 부자연스럽다.
양측 의견 모두 정당하며 어느 쪽이 맞거나 틀리다고 할 수 없다. 문제상황에서 자신이 뭘 더 중요시 여기냐에 따라 더 적합한 결정을 선택하면 되는 일이다.
때문에 원리를 이해하고 해결 방법을 여럿 알아두는 것이 중요하다. 결국 소프트웨어를 개발하면서 벌어지는 모든 의사결정은 상충관계에 있기 때문이다.
이런 의사결정 과정이 반복되다 보면 그러한 경험이 곧 우리의 개발 노하우로 자리잡고 나만의 무기가 되는 것이다.

4. 새로운 접근법

이는 무슨 접근법일까? 중간에서부터 시작하니 전파식 접근법이라 불러야할까? 상향식도 하향식도 아니라고 생각한다. 도메인을 가장 위에 두면 하향식, 아래에 두면 상향식이다.
접근법이 중요한게 아니라, 왜 우리가 지금까지 진화시켜온 레이어는 왜 이런 형태를 띠게 되었을까?라는 고민이 중요한 것 같다.
접근법에 그렇게 큰 의의를 두지 말자.

5. 빈약한 도메인

앞서 얘기했듯, 이 아키텍처는 특정한 문제를 잘 풀어낼 수 있는 아키텍처다. 그 문제는 앞으로 도메인이 충분히 어려워지고 복잡할 예정일 때다.
도메인이랄것도 없이 빈약하다면 트랜잭션 스크립트 방식을 선택해도 전혀 문제가 없다.
대부분의 소프트웨어 개발은 언더 엔지니어링으로 이뤄지는 경우가 많으므로 이를 경계해야 하지만 마찬가지로 오버 엔지니어링도 반드시 경계해야 한다.
모든 상황에 적합한 아키텍처란 존재하지 않으며 시스템의 복잡도와 요구사항에 따라 어플리케이션을 진화시키는 것은 프로그래머인 나의 몫이다. 아키텍처에는 문제와 문제 해결과정만이 존재할 뿐이라는 점을 명심하자.