2. 계층 및 처리흐름

2.1. 소개

이 문서는 백엔드 프로그램의 논리적인 계층과 계층간 처리 흐름을 설명합니다.

2.2. 계층 구분

우리는 .NET MVC 프레임워크의 아키텍처를 사용함으로써 뷰, 모델, 컨트롤러 계층을 나누어 사용하고 있습니다. 그렇기에 컨트롤러가 모델(비지니스모듈)을 선택하여 처리할 때, 모델이라는 하나의 계층에서 비지니스 로직을 처리할 때 발생하는 MVC 아키텍처의 한계점을 공유하고 있었습니다.

복잡한 비지니스 구현 시, 단시 하나의 계층과 객체에서 모든것을 보기쉽게 구현하기에는 쉬운일이 아닙니다. 때문에, 우리는 모델에 몇가지 계층을 더 추가하여 복잡성을 제거하고 코드의 응집력을 높이려 합니다.

Controller는 물리적인 계층으로 구분되지만, 실질적인 비지니스 처리의 시작 되므로 논리적인 계층에 포함시키고 있습니다. 그리고 Service, DataAccess 계층으로 나누어져 있습니다. 각각의 논리적인 계층은 DDD(도메인주도설계)의 사상을 공유합니다.

2.2. 티쿤의 각 계층이 특별하게 존재하는 이유

우리의 레거시 코드는 .NET WebForm 아키텍처로 부터 시작하였습니다. 물리적인 UI계층과 DataAccess 계층으로 이루어진 2계층의 구성으로 부터 MVC로 넘어왔고 이러한 아키텍처의 전환과정에서 나타나기 시작한 계층간 설계와 책임 그리고 그에 따른 복잡성 문제는 우리의 레거시 코드에 고심한 흔적이 그대로 남아 있습니다.

WebForm에서 MVC로 전환 시, 레거시 코드의 재설계 등의 리팩토링 작업을 하지 않고 필요 시에만 진행되었습니다. 때문에 레거시 코드들의 이러한 물리적, 논리적 구조의 모순은 현재 소스코드에 아직 지배적으로 남아 있습니다.

때문에, 많은 레거시 코드들은 다양한 기술부채를 가지고 있습니다. 코드들은 강결합 되고, 여러 서비스 코드들의 파편이 이곳저곳 산재하여 응집도는 매우 낮은 코드들이 존재합니다.

우리는 새로운 개발은 물론 레거시 코드들의 지속적인 리팩토링을 통해 좀 더 나은 코드 관리를 하려 합니다. 그러한 방법의 일환으로 논리적, 물리적인 계층을 점진적으로 구성하며 비지니스 개발을 제어 하고 있습니다.

2.3. 계층의 아키텍처적 이해 (처리흐름)

2.3.1. DataAccess 계층

DataAccess 계층은 위 그림의 Database에 접근할 수 있는 최상위 계층이고 마지막 계층입니다. 티쿤은 ADO.NET과 Spring.NET의 ADO.NET 지원 기술을 사용하고 있으며, 이들 기술에서 보편적으로 사용하는 DataAccess 계층 구성을 사용하고 있습니다. 이 계층의 자세한 설명은 4. DataAccess 계층 장에서 설명합니다.

2.3.2. Service 계층

보통 비지니스 처리는 데이터베이스에서 데이터를 읽은 후에 적절한 처리를 거처 다시 데이터베이스에 저장하거나 합니다. Service 계층은 비지니스 처리 로직이 적절히 응집되어 풀이하는 역활을 당담합니다. 보통의 3티어 계층에서 사용되는 비지니스로직레이어(BLL)의 구성과 같습니다.

이 계층은 DataAccess 계층에 접근할 수 있는 최상위 계층입니다. 그리고 자식으로 Module 계층을 두어 기능적으로 좀더 안정된 모듈화를 할 수 있는 기회를 갖습니다. 다른 Service 계층을 호출할 수도 있습니다. 하지만, 다른 Service 객체의 자식 Module 객체는 호출 할 수 없습니다. 이 계층의 자세한 설명은 3. Service 계층 장에서 설명합니다.

Service의 Module

Module은 Service 계층의 자식 계층입니다. Service가 복잡해지지 않도록 모듈화할 필요가 있을 때, 사용합니다. 이 계층의 구현 사상과 Rule은 서비스 계층의 그것과 같습니다. 다만, 호출관계에 있어 제한을 두고자 논리적으로 구분합니다.

2.3.3. Controller 계층

Controller는 논리적인 계층으로 구성되는데 이견이 있을 수 있으나 Controller가 에플리케이션에 종속되어 Service를 호출하는 역활을 담당합니다. 때문에 논리적인 계층으로 구분하고 이 계층에서 웹 에플리케이션에 종속된 처리를 합니다. 예를 들면 File, Session, Cookie 와 같은 처리 입니다. 그리고 제한적으로 DataAccess 계층을 직접 호출할 수 있습니다. 하지만, 그러한 방법은 지향하지 않습니다.

2.4. 계층별 호출 가능여부

각 계층과 계층에서 생성하는 객체는 호출간 제약이 존재 합니다.

호출가능여부
(△: 주의)
Controller Service    Module     DataAccess       
Controller × ×
Service ×
Module × ×
DataAccess × × × ×

2.4.1. 주의해야 하는 호출관계

Controller -> DataAccess

Controller 계층에선 DataAcces 계층을 직접 호출 하지 않고, 가능한 한 Service를 통해 비지니스를 제어해야 합니다. Controller 계층은 논리적으로 구분되며 때문에 개발효율을 위해 간단한 CRUD는 Service계층에서 DataAccess계층을 직접호출 하고 있습니다만, 그렇다고 해서 이런 방식을 지향하는 것은 아닙니다. 항상 사용자의 요구사항이 Service 계층에 구현된다는 점을 고려한다면, 이 방식을 좋아하지 않을 것입니다.

Service -> Module

Module은 서비스에서 필요한 비지니스 구현이 거대해 질 때, 필요하게 됩니다. 서비스가 필요한 구현 작업을 그룹화 하여 복잡도를 감소시킬 때 사용하며, 보통 객체지향 개발을 함으로써 이러한 복잡도의 감소가 필요하게 됩니다. 때문에, Module은 상위 Service가 가지고 있는 namespace 하위에 놓이게 됩니다. 그렇기에 Module은 상위 Service가 구현과 호출 책임을 가지며 다른 namespace의 Service는 호출해서는 안됩니다.

Module -> Module

위의 Service -> Module 의 호출관계처럼 Module간 호출은 같은 namespace에서 만으로 제한합니다. 구현 및 호출 책임이 상위 서비스로만 전파됨으로 다른 namespace에 소속된 Service나 Module은 호출해서는 안됩니다.

그리고 모듈은 복잡도 감소를 위해 사용합니다. 이 것은 다른말로 Module간의 의존 관계가 강결합 되지 않도록 주의 해야 함을 의미합니다.