본문 바로가기

Back-End/토비의 스프링3

9.3. 스프링 웹 애플리케이션 아키텍처에 관하여

들어가기 전

스프링 프로젝트를 하면, 일단 기본적으로 생각없이 Controller, Service, Repository 3단계로 나누어 코딩을 한다.

 

어떤 역할로 나눈지는 이해하고 있었지만, 어떻게 서로 결합도를 낮추고, 어떠한 방식으로 아키텍처를 정하는지에 대한 이해도는 거의 없었다.

 

그래서 토비의 스프링에 있는 9.3. 애플리케이션 아키텍처를 읽게 되었다.

 

계층형 아키텍처

우리는 스프링을 공부하면서 관심, 책임, 성격, 변하는 이유와 방식이 서로 다른것들을 분리함으로써 결합도는 낮추고 응집도는 높이는 코드를 만들어 왔다.

 

웹 애플리케이션에서도 이처럼 성격이 다른 것은 아키텍처 레벨에서 분리해주는 것이 좋다.

만약, 분리하지 않고 JSP 처럼 HTML, JDBC 코드가 함께 존재한다면? 유지보수는 거의 불가능에 가까워 진다.

 

이를 계층형 아키텍처라고 부르기도 하고 3-tier 애플리케이션 아키텍처라고 부르기도 한다.

 

  • 프리젠테이션 계층
    • 클라이언트의 종류와 상관없이 HTTP 프로토콜을 사용하는 서블릿이 바탕이 됨
  • 서비스 계층
    • 이상적인 서비스 코드는 DB와 연결되는 데이터 엑세스 계층이 바뀌거나 클라이언트와 연결되는 프레젠테이션 계층이 모두 바뀌어도 그대로 유지 될 수 있어야 함
    • 기반 서비스 계층(트랜잭션,보안,메일,메시징 등)의 구현에 종속되면 안됨. 인터페이스를 사용하거나 AOP를 통해서 서비스 계층의 코드를 침버하지 않아야 한다.
  • 데이터 엑세스 계층
    • 장기적인 데이터 저장을 목적으로 하는 DB이용이 주된 책임
    • 아래 그림처럼 같은 데이터 엑세스 계층이지만 역할에 맞게 수직적으로 나눌 수 있음 ( 추상화 레벨에 따라 분류 )

 

계층형 아키텍처 설계의 원칙

객체지향 설계의 원칙과 같이 아키텍처 레벨의 계층에도 그 원칙이 적용된다. 즉, 각 계층은 자신의 계층의 책임에만 충실해야 한다.

 

예를 들어, 데이터 엑세스 계층에서 비즈니스 로직을 담거나 웹 파라미터를 파싱하는 코드나 결과를 화면에 어떻게 뿌릴지 결정하는 코드가 들어간다면 응집도가 낮아진다.

 

좋지 않은 코드를 살펴보자

다음과 같이 코드를 작성하게 되면 데이터 엑세스 계층 기술에 종속되는 서비스 계층 코드가 되고 만다. 이렇게 되면 둘 간의 결합도는 높아지게 되고 각 계층의 내부 구현이 변경되면 자연스럽게 다른 계층의 코드도 수정을 필요로 하게 된다.

다음과 같이 데이터 엑세스 계층 코드를 수정한다면 특정 계층에 종속되지 않는 단순한 오브젝트 형태로 전달하게 된다. 

 

좋지 않은 코드2를 살펴보자. 나도 가끔 이런 실수를 저지르고 한다.

바로 프레젠테이션 계층의 오브젝트를 그대로 서비스 계층으로 넘기는 경우이다. 서블릿의 HttpServletRequest, HttpServletResponse를 파라미터로 쓰는 경우를 말한다.

 

애플리케이션 정보 아키텍처

애플리케이션에서 정보를 어떤식으로 다룰지를 결정하는 일도 아키텍처를 결정할 때 매우 중요한 기준이 된다.

존재하는 정보를 데이터로 다루는 경우와 오브젝트로 다루는 경우로 나눌 수 있다.

  • 데이터로 다루는 경우 : 
    • DB에 무게를 두는 경우
    • 서비스 계층의 코드에 무게를 두는 경우
  • 오브젝트로 다루는 경우 : 도메인 모델을 반영하는 오브젝트 구조를 만들어주고 이걸 사용

오브젝트 중심 아키텍처

객체지향 분석과 모델링의 결과로 나오는 도메인 모델을 오브젝트 모델로 활용한다.

 

카테고리 하나에 여러 개의 상품이 포함되는 (1:N) 도메인 모델을 만들어보자.

먼저 테이블을 만든다면, 상품에 카테고리와 관계를 만들어주는 FK를 둬야 한다.

 

데이터 중심 아키텍처에서는 SQL과 DB 관점에서 생각을 하게 된다. 즉, SELECT ... JOIN ... 실행을 통해 결과를 담는다.

아래와 같이 List 형태로 만들어 서비스 계층에 넘겨주게 된다. 이렇게 DAO가 만드는 SQL의 결과에 모든 계층의 코드가 존재하게 된다.

 

오브젝트 방식에는 아래와 같이 구현할 수 있다.

 

  • 자바 언어의 특성을 최대한 활용할 수 있음 ( 레퍼런스 )

하지만 이 방식에도 단점은 있다.

  • 최적화된 SQL에 비해 성능면에서 조금의 손해
  • 모든 필드 값을 다 채워서 전달함

하지만 이런 문제를 해결하는 접근 방법이 또 있다.

  • Lazy loading : 오브젝트가 필요한 경우에 다이나믹하게 DB에서 읽어드림
  • 가장 이상적인 방법은 JPA, JDO, 하이버네이트와 같은 ORM 기술을 사용하는 것
    • 지연 로딩 직접 만들지 않아도 됨
    • 복잡한 DAO 코드 만들지 않아도 됨
    • 자주 변경되지 않으면서 많은 로직에서 참조되는 레퍼런스 테이블을 캐시해줌으로써 성능 향상
    • 결론 : 사용하기 쉽고 직관적이며 코드의 양이 대폭 줄어듬

그런데 도메인 오브젝트도 결국은 자바 오브젝트이다. 자바 오브젝트는 속성뿐만 아니라 행위에 대한 것도 가지고 있다. 

행위에 관한 코드를 작성하는 것도 적극 활용해야 된다고 생각한다.

이를 활용한 것이 '풍성한 도메인 오브젝트 방식'이다.

 

풍성한 도메인 오브젝트 방식

예를 들어, Category가 가지고 있는 전체 Product의 값을 필요로 하는 경우를 살펴보자. 비즈니스 계층에 이 코드를 작성할 수도 있지만, Category 클래스 내부에 함수를 작성할 수도 있다.

  • 좋은 점 1 : 재활용하기 좋다 ( Service에 담아도 되지만 다른 개발자가 찾지 못할 수도 있고, DI 해야되는 번거러움 )
  • 좋은 점 2 : 코드 중복이 발생하지 않는다 + 객체지향적이다