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