이 글은 Chad Z. Hower 가 2005년 6월 25일 코드프로젝트(codeproject.com)에 작성한 '친구, 나의 비즈니스 로직은 어디에 있는가? Dude, where's my business logic?' 라는 제목의 글을 번역한 것입니다.
비즈니스 로직이 어디에 있어야만 하는가에 대해서 아쉬워 하며 5년 전에도 작성된 글이 있음에도 불구하고,
이 주제에 대한 무지와 논쟁이 여전히 계속되고 있어 비즈니스 레이어의 개념과 어디에 위치해야 하는가에 대한 글을 쓰고 싶은 생각도 있었으나,
5년이 지났지만 아직도 최고의 글이라고 판단되어 번역 포스트 합니다. 러프하지만 양해해서 읽어 주세요.
거의 모든 부분에서 Chad Z. Hower의 의견에 동의하며, DBA에 대한 생각은 Chad Z 만큼 강성적이지는 않습니다.
비즈니스 로직이란 무엇이며 어디에 위치해야 하는가, 3-tier 구성에 대한 Chad Z의 견해를 보도록 하시죠.
원글 :http://www.codeproject.com/KB/architecture/DudeWheresMyBusinessLogic.aspx
Introduction
수년 동안 우리는 데스크톱에서 클라이언트 서버로 , 3-tier 에서 n-tier, 서비스 지향적으로 이전해 왔다. 그 과정에서 많은 것이 변했지만, 많은 버릇은 여전히 남아 있다. 이 버릇은 종종 습관적으로 이 변화에 저항하며, 빈번히 일어나는 과정 이다. 이 글은 우리가 무엇을 잘못 하고 있고, 해결책은 무엇인지에 대한 것이다.
이 문서에 대해서. About this article.
여기에서 나는 디자인과 아키텍처에서 n-tier 시스템을 만드는 방법 중 한가지를 말하려 한다. 이 글은 code에 포커스가 있지 않다. n-tier 시스템을 완성시키는 데에는 여러 가지 방법이 있다. 이 방법은 그 중에 하나이다. 당신이 시스템을 만든다면 여기의 방법을 이용해서 좋은 충고와 연습, 패턴을 찾을 수 있기를 바란다.
이 글의 몇 가지는 표준실무(standard practices)와는 거리가 먼 것일 수도 있다. 이 글의 모든 것은 Microsoft Patterns and Practices 의 Designing Data Tier Components and Passing Data through Tiers 와 그 외의 문서에 기술되어 있는 것을 기반으로 한다.
여기에 기술된 모든 것을 채택하지 않더라도, 몇 가지는 선택해서 채택할 수도 있을 것이다.
목적 Goal
비지니스 로직이 어디에 위치해 있어야 하냐고 어떤 개발자에게 물어봐도, 대답은 "당연히 비즈니스 레이어지" 라고 대답할 것이다.
그들에게 당신 회사의 비즈니스 로직은 어디에 있나요 라고 물어봐도 "당연히 비즈니스 레이어지"라고 답할 것이다.
비즈니스 로직이 어디에 있어야 하는 지를 제외하고 이야기 해 보자. 비즈니스 레이어는 몇 개의 비즈니스 로직이 아니라 모든 비즈니스 로직을 포함해야 한다. 이 글을 읽은 후에 어떤 것이 시스템에 옳았고, 옳지 않았는지 깨달을 것이다.
용어들 Terms
용어들은 종종 혼재된 개념을 가지고 있다. 이 글에서는 아래에 정의를 참조 한다.
티어 Tier
tier 라는 단어를 사용 할 때 , 물리적 서버에 정의된 물리적 티어를 의미한다. 또는 같은 기능을 수행하는 확장을 위한 서버 그룹을 의미한다.
레이어 Layer
레이어라는 단어를 사용할 때는 프로세스 또는 배포 단위를 담고 있는 시스템의 한 부분(section)을 의미한다 . 여러 레이어는 하나의 티어에 함께 존재할 수 있지만 리모팅 능력 같은 것들이 요구되어 진다면 쉽게 이전 할 수 있는 것을 말한다.
문제의 진화. Evolution of a problem.
데스크 톱 Desktop
데스크톱 어플리케이션에서, 비즈니스 로직은 하나의 티어에 모든 레이어들과 함께 담겨 졌다. 레어어를 나눌 필요도 없었고, 나누어졌다 하더라도 레이어는 일반적으로 혼재되어 있었고, 경계 랄 것이 없었다.
클라이언트 서버 Client Server
클라이언트 서버 환경에서는 두 개의 티어가 존재 했고, 이는 적어도 두 개의 레이어를 구현하도록 강제했다. 초창기의 서버는 단순 원격 데이터베이스 뷰에 불과 했다. 그리고 어플리케이션(client) 과 스토리지(server)로 구분 되어 졌다. 일반적으로 모든 비즈니스 로직은 유저 인터페이스와 같은 여러 레이어들과 혼합되어 클라이언트에 남겨졌다.
클라이언트로 부터 비즈니스 로직을 제거하는 것이 네트워크 대역폭과 지속적인 클라이언트 재배포를 줄일 수 있다는 것을 깨닫는 것 에는 오랜 시간이 걸리지 않았다. 오로지 두 개의 레이어 만이 존재 했다. 비즈니스 로직이 옮겨갈 유일한 장소는 서버였다. 서버로 이전하는 것이 클라이언트 서버 시스템에서 구조적으로 적절했다. 그러나 데이터베이스 플랫폼으로서는 부적절한 선택이었다. 데이터베이스는 저장(store)과 조회(retrieve)의 필요성으로 디자인 된 것이었다. 데이터베이스 저장 프로시저 언어(Stored Procedure Language)는 SQL이 실행 할 수 없는 기본적인 데이터 전송을 위해 디자인 된 것이다. 저장 프로시저 언어는 복잡하지 않은 비즈니스 로직을 빠르게 실행 시킬 용도로 디자인 된 것이다.
하지만, 저장프로시저로 비즈니스 로직을 배치하는 두 가지 선택을 가지는 것은 좋아 보였다. 사실 비즈니스 로직을 저장프로시저에 억지로 끼워 넣는 것이 실용적이냐는 논쟁의 대상이다. Two Tier 세상은 완벽하지는 않았지만 진화된 것이었다.
3-Tier
클라이언트 서버 접근법이 문제가 있다는 것이 명확해 졌고, 3 - tier 디자인이 유명해 졌다. 그 순간 커넥션 수(connection count)는 가장 큰 문제가 되었다. 최근의 데이터베이스들은 수 천개의 동시접속 연결을 핸들링 할 수 있다. 1990년대의 대부분의 데이터베이스들은 500개의 연결만 되어도 버거워 했다. 서버들은 종종 연결당 라이센스를 요구했다. 이는 연결 수를 줄이도록 요구했다.
연결 풀링(Connectioin pooling)이 유명해졌다. 연결 풀링은 개개의 클라이언트(또는 벤더)에 의해 구현되어 졌고, 세번째 tier는 클라이언트와 서버 사이에 삽입되어 졌다. 이 중간의 tier는 미들-티어 "middle-tier"라고 알려졌다. 많은 경우에 미들-티어는 연결 풀을 조정하기 위한 용도로만 존재했었다. 다른 경우로 비즈니스 로직은 미들-티어로 이동하기 시작했다. C++, VB, Delphi, Java와 같은 개발 언어들은 저장 프로시저 언어 보다 비즈니스로직에 더 잘 맞았기 때문이다. 곧 미들-티어가 비즈니스 로직을 넣을 최고의 장소라는 것이 밝혀 졌다.
미들-티어는 또한 저대역폭의 클라이언트 연결도 지원했다. 직접 데이터베이스 연결은 전형적으로 빠른 속도(high speed)와 낮은 연결 지연(low latency) 네트워크 연결을 요구했다.
비즈니스 로직이란 무엇인가 What is business logic?
더 진행하기 전에 비즈니스 로직이란 정확히 무엇인가 정의해 보자. 내가 컨퍼런스나 회사에서 비즈니스 로직을 소개할 때 깨달은 것은, 모든 사람들이 정확히 비즈니스 로직이 무엇인지 동의하고 있지 않다는 것이다. 게다가 무엇이 비즈니스 로직이고, 무엇이 아닌지 생각조차도 하지 않는다는 것이다.
데이터베이스 서버는 저장 레이어이다. 데이터베이스는 데이터를 가능한 효율적으로 저장하고 조회하고, 업데이트 하도록 디자인 된 것이다. 이 기능은 보통 CRUD(Create, Retrieve, Update, Delete)라고 불리 운다. 물론 몇몇 데이터베이스는 CRUD 그 자체 이다. 하지만 이는 다른 주제이니 넘어가도록 하자.
데이터베이스는 매우 빠르고(very fast) 효율적인(efficient) CRUD 작업을 위해 디자인 되어 있다. 데이터베이스는 전화번호 포메팅, 계산 최적화, 피크 시기에 유틸리티 사용, 지리적 목표 결정하기, 배송경로 할당 등의 작업을 위해 디자인 되진 않았다. 나는 이 모든 경우와 심지어는 더욱 복잡한 모든 것이 저장 프로시저에 들어 있는 것을 봤다.
고객 삭제하기 Delete customer
복잡한 경우는 아니지만, 비즈니스 로직이 아니라고 생각 되어지는 한가지 간단한 케이스를 생각해 보자. 그것은 고객 삭제하기 이다. 거의 모든 시스템에서 고객 삭제하기는 저장프로시저가 독점적으로 핸들링 한다. 고객을 삭제하는 데는 많은 비즈니스 로직 고려사항이 필요하다. 이 고객을 삭제해도 되나? 삭제 전과 삭제 후에 수행 해야만 하는 것은 무엇인가? 제일 먼저 체크해야 하는 안전점검 사항이 무엇인가? 어떤 테이블의 레코드가 삭제되어야 하나? 또는 필수적으로 업데이트 되어야 하는 것이 있나?
데이터베이스는 고객이 누구인지 몰라야 한다. 오로지 고객을 저장하기 위한 요소이다. 데이터베이스는 고객이 어떤 테이블에 저장 되어야 하는지 알 수 없어야 한다. 그리고 고객 오브젝트는 테이블과 독립적으로 취급되어져야 한다. 데이터베이스의 역할은 고객을 표현하는 정보를 테이블에 한 줄로써 저장하는 것이다. 참조 제약 사항, 데이터 타입, null 가능, 데이터 조회를 편리하게 만드는 인덱스 이외에 데이터베이스는 고객이 비즈니스 레이어에서 어떻게 구성되어 져야 하는지 기능적 지식을 몰라야 한다.
만약 존재한다면 저장 프로시저는 한 개의 테이블에 대해서만 작업 해야 한다. 데이터를 반환할 목적으로 'SELECT' SQL을 이용한 Join 테이블을 제외하고는 말이다. 이런 경우에 저장프로시저는 뷰(View) 처럼 동작한다. 뷰 와 저장프로시저는 값의 기본 표로써만 사용 되어져야 한다. 하지만 더 빠르고 더욱 효율적인 데이터 조회와 업데이트는 비즈니스 레이어에 의해 지원 되어야 한다.
심지어 최신의 설계와 기술을 자랑으로 삼는 많은 회사에서도 그들의 비즈니스 로직이 모두 비즈니스 레이어에 위치하고 있다고 헛소리 하는 담당자가 있다. 고객삭제, 고객추가, 고객 비활성화, 고객 일시중지, 그리고 고객 오브젝트가 아닌 여러 비즈니스 오브젝트를 데이터베이스에서 한번만 슬쩍 살펴봐도 그 말이 왜 헛소리 인지 즉시 알 수 있다.
나는 종종 아래와 같은 일을 수행하는 저장 프로시저를 발견한다.
sp_DeleteCustomer(x)
Select row in customer table, is Locked field
If true then throw error
Sum total of customer billing table
If balance > 0 then throw error
Delete rows in customer billing table (A detail table)
if Customer table Created field older than one year then
Insert row in survey table
Delete row in customer table
그리고 수차례에 걸쳐 비즈니스 로직을 비즈니스 레이어로 옮긴다.
Business Layer (C#, etc)
Select row in customer table, is Locked field
If true then throw error.
Sum total of customer billing table
If balance > 0 then throw error.
if Customer table Created field older than one year then
Insert row in survey table
Call sp_DeleteCustomer
sp_DeleteCustomer(x)
Delete rows in customer billing table (A detail table)
Delete row in customer table
이 경우 전부는 아니지만 몇 개의 비즈니스 로직이 이전 되었다. 어떤 테이블은 비즈니스 로직에 의해서 영향을 받았다. 데이터베이스는 어떤 테이블이 비즈니스 레벨에서 고객이 어떻게 구성되어 지는지 몰라야 한다. 이런 것들은 비즈니스 레이어에서 제공 되는 것이 낫다. 세가지 동작, 비즈니스 레이어가 SQL 을 발행 하거나, 세 개의 분리된 저장프로시저를 실행하거나 , 마지막의 sp_DeleteCustomer 함수를 실행 시키기 위해서 말이다.
우리가 모든 로직을 비즈니스 레이어로 옮긴 것이다.
Business Layer (C#, etc)
Select row in customer table, is Locked field
If true then throw error.
Sum total of customer billing table
If balance > 0 then throw error.
if Customer table Created field older than one year then
Insert row in survey table
Call sp_DeleteCustomer
Delete rows in customer billing table (A detail table)
Delete row in customer table
row 삭제하기는 저장프로시저를 사용할 수 있다. 단지 한 개의 테이블에 대해서 수행한다면 말이다. 현대의 데이터베이스는 쿼리 플랜 캐싱을 사용하고, 약간의 성능 잇점이 있다. 게다가 이런 시스템에서 한 개의 테이블에 대해서만 작업하기 때문에 SQL을 전송하는 것은 간단하다. 이런 간단한 쿼리플랜은 성능 최적화 잇점을 거의 얻을 수 없다. 사실 몇몇 데이터베이스는 간단한 SQL 문장을 실행하기 위해 만들어진 너무 많이 로드된 저장프로시저 때문에 고통 받는다 .
테이블 수정을 비즈니스 레이어로 이전함 으로써 , 우리는 아래의 잇점을 얻을 수 있다.
1. 각각의 데이터 베이스로 저장 프로시저를 이전할 필요가 없어지므로 데이터베이스 시스템 이식성이 높아진다.
2. 모든 로직을 한 곳에서 가지고 있으므로 미래의 변경은 더욱 쉬워진다.
3. 로직이 두 군데에 나누어 있지 않으니 디버깅이 쉬워진다.
4. 다른 비즈니스 로직이 저장프로시저로 슬쩍 들어가지 못한다. 더욱 쉬워 졌기 때문이다.
이것은 세가지 연속적인 성공을 요구한다.
당신의 비즈니스 티어는 데이터베이스에 1 gigabit 세그먼트와 같은 고속 세그먼트로 연결 되어 있어야 한다. 300 Byte에 비해 100 Byte를 보내는 것은 차이를 체감하지 못 할 것이다. 모든 데이터베이스는 SQL 일괄 Commit을 지원한다. 3개의 구문은 1개의 일괄 배치로 전송 될 수 있다. 네트워크 호출을 줄여 준다. 데이터 엑세스 레이어는 SQL 구문을 코드에 포함하지 않고도 이러한 SQL을 발행할 수 있다.
몇몇 DBA들과 심지어는 개발자들 조차도 이러한 수준의 통합을 받아들이지 못할 것이다. 그리고 그러한 일괄 업데이트를 저장프로시저에 놔두라고 주장 할 것이다.
물론 통합의 문제는 데이터베이스와 당신의 우선 순위에 의해 결정해야 한다. 현대의 모든 데이터베이스는 이미 수행된 SQL도 쿼리플랜 캐쉬에 의해 최적화 되어지기 때문에, (저장프로시저를 사용 하던 SQL을 사용하던 , 비즈니스 로직에서 사용되던지) 별 차이가 없다. 비즈니스 로직을 저장프로시저에 넣어야 하는 결정적 기술적 이유는 없다. 당신이 일괄 업데이트를 저장프로시저가 실행하도록 결정 했다면 다른 비즈니스 로직이 저장프로시저에 슬쩍 들어 가지 않도록 매우 조심해야 한다. 그리고 저장프로시저를 순수한 CRUD 작업으로만 유지해야 한다. 상태적 동작과, 또 다른 비즈니스 로직이 들어가지 않도록 말이다.
포매팅 Formatting
개발자들 사이에서 그것이 비즈니스 로직인지 아닌지 논쟁을 일으키는 또 다른 아이템에 대해서 고려해 보자. 나는 그것이 유저 인터페이스나 저장이 아닌 비즈니스라고 믿는 이유에 대해서 시연해 볼 것이다. 그것은 간단하지 않은 포매팅( non-simplistic formatting) 이다. 내가 사용할 예제는 전화번호이다.
각각의 국가들은 각기 다른 전화번호 표시 방법이 있다. 대부분의 국가는 한가지 이상의 방법이 있고, 몇 개의 예는 다음과 같다.
Cyprus:
+357 (25) 66 00 34
+357 (25) 660 034
+357 25 660 034
+357 2566 0034
Germany:
+49 211 123456
+49 211 1234-0
North America (USA, Canada, some parts of Caribbean)
+1 (423) 235-2423
+1-423-235-2423
Russia:
+7 (812) 438-46-02
+7 (812) 438-4602
심지어 독일은 DIN 5008 이라 불리는 공식 포맷이 있다.
물론 국가코드는 보통 포함되어 있지 않다. 하지만 우리의 시스템은 국제적이라서 국가코드 까지 포함 할 것이다. 우리는 각 국가마다 번호를 표현할 한가지 포맷을 선택할 것이다.
전화번호를 포매팅하기 위한 고려사항
1. 여러가지 포맷으로 입력될 것이다.
2. 각 국가는 번호를 표현하는 독특한 포맷이 있다.
3. 몇 개 국가의 포맷은 간단하지 않고 앞의 몇 자리에 의해 변경된다.
4. 몇 개의 앞자리 숫자는 항상 고정되어 있지 않다. 예를 들어 러시아에서 812는 St. Petersburg 도시 코드이며, 095는 Moscow , 하지만 Siberia 와 다른 지역은 4자리(3952) 이다. 이런 이유로 전화번호의 전체 길이와 변경할 포맷은 지역코드에 의존한다.
5. 새로운 휴대성 법규, 신규 모발일 사업자, 유럽 통합, 폰 시스템 업그레이드, 추가되는 전화번호 포맷, 국제 변화에 따른 번호 길이 변화, 최근 Cyprus 는 시스템 확장을 위해 지역 코드를 두배로 늘렸다. 그리고 전세계 수 백개의 국가들의 다수의 이동통신 회사 등의 일반적인 변경 등을 예측할 수 있을 것이다.
입력이 어찌 되었건 숫자가 아닌 문자를 제거하여 전화 번호는 아래와 같을 것이다.
Phone: 35725660034
때때로 국가코드는 별도로 분리되어 저장 될 것이다.
PhoneCountry: 357
PhoneLocal: 25660034
아직은 쉬워 보이지만 다른 비즈니스 로직 이슈가 있다. 모든 국가코드의 갯수가 같지 않다는 것이다, 국가코드의 길이 범위는 1~3개이다.
종종 입력을 파싱 하고 표시하는 로직은 클라이언트에 전통적인 언어로 구현 되어 있다. 클라이언트는 국가코드의 길이를 결정하기 위한 대용량의 데이터를 필요로 한다는 것이 문제다. 표시 루틴이 업데이트 될 때 마다 클라이언트를 재배포 해야 된다.
때때로 포매팅을 저장프로시저 만으로도 처리할 수 있다. 이 접근 방법의 문제는 저장프로시저 언어는 이런 타입의 로직에 잘 맞지 않고, 실제 처리 로직에서 비효율적일 뿐만 아니라 버그를 만들 가능성이 있다.
더 나아가 전화번호는 두 번 저장되는 일도 발생한다. 한번은 인덱싱과 쉽게 찾기 위해 원본 데이터로, 두 번째는 표시를 위해서이다. 게다가 중복데이터의 문제가 있으며, 새로운 포맷이 추가된다면 같이 업데이트도 해야 한다.
극단적인 경우로 놀라울 정도로 빈번하게 일어나는 일이 있는데 저장된 전화번호의 포맷에 상관없이 배치 하거나 색인 하거나 정렬하기가 어렵다.
포매팅의 경우 일지라도 이것은 사용자 인터페이스가 아니며, 데이터베이스 측면에서 편할 지라도 명확하게 비즈니스로직 이므로 중요하다. 포메팅을 비즈니스로직에서 구현하면 데이터 중복을 피할 수 있으며, 데이터 언어로 억지로 구겨 넣어지지 않고도 개발언어로서 구현 가능하다.
예외들 Exceptions
특정 일괄 업데이트는 저장프로시저로 구현되어야 몇 배는 빠를 수 있다. 거의 모든 경우는 SQL로 직접 핸들링할 수 있다. 비즈니스 레이어에서 SQL구문을 사용 할 때 몇 종류의 일괄 업데이트는 반복행위(looping behaviour)를 유발한다. 드문 경우지만 저장프로시저가 필요해 지면 가능한 적게 사용해야 하고, 특별히 관리해야 한다.
이 주제에 대해서는 다음에 다룰 예정이다.
오늘날의 클라이언트 서버 시스템. Systems of today
Client Server
클라이언트 서버 시스템에서는 비즈니스 로직이 클라이언트와 서버 양쪽으로 분리된다.
엔터프라이즈 어플리케이션의 매우 많은 경우가 앞에서 예를 든 것 처럼 구현되어 있다. 많은 비즈니스 로직이 저장프로시저에 구현되어 있고, 비즈니스 로직은 보여주는 역할을 한다. 그러나 많은 비즈니스 규칙은 저장프로시저나 SQL로는 쉽게 구현될 수 없고, 사용자 인터페이스에서 빠르게 실행 될 수 없다. 이런 잘못으로 인하여 비즈니스 규칙은 클라이언트와 서버 양쪽으로 쪼개진다.
N-Tier
다양한 이유가 있기 때문에 논란이 있는 이 주제에 대해서는 나중에 다루겠지만, n-tier 시스템에서 비즈니스 로직을 통합시키는 것은 잘 못될 가능성이 크다. 통합되는 대신에 오히려 비즈니스로직은 잘게 나누어 지기 쉽기 때문이다.
물론 각각의 시스템은 각각의 비즈니스 로직의 상황, 레이어의 구성에 따라 달라진다. 하지만 한가지 공통점은 이제 비즈니스 로직은 두개가 아닌 세개로 나누어진다는 것이다. 몇 개의 일반적인 시나리오를 다음에 설명하겠다.
Scenario 1
n-tier 시스템에서 비즈니스 로직의 일반적인 배치는 다음과 같다.
비즈니스 레이어에 비즈니스 룰이 없다면 진정한 비즈니스 레이어가 아니다. 그저 XML과 데이터베이스 결과 집합을 위한 매퍼일 뿐이다. 데이터베이스 연결 풀링, 데이터베이스 독립, 데이터베이스와의 분리 등의 잇점을 얻을 수는 있어도 비즈니스 로직 레이어는 아니다. 이것은 논리적 레이어가 없는 물리적인 레이어다.
Scenario 2
다른 일반적인 시나리오는 아래와 같다.
일반적으로 볼 수 있는 경우로 몇개의 비즈니스 룰은 비즈니스 레이어로 옮겨지고, 대부분이 데이터베이스에 남아 있는 경우이다.
이런 식으로 설계된 비즈니스 레이어에서 비즈니스 룰을 재사용하면 어플리케이션에는 중복이 발생한다. 이것은 비즈니스 레이어를 구현하는 주요 목표를 퇴색시킨다.
심지어 어플리케이션은 비즈니스 룰을 구현하지 않거나 무시함으로써 위배된 비즈니스 룰을 수행 할 수도 있다.
Consolidation
비즈니스 레이어에 모든 비즈니스 룰을 포함하는 통합된 경우. 이런 경우에 다음의 이득을 얻을 수 있다.
모든 비즈니스 로직이 한 곳에 있다. 쉽게 검증, 디버그, 그리고 수정될 수 있다. 비즈니스 룰을 작성하는데 진짜 개발언어를 사용 할 수 있다. 이런 언어는 저장프로시저와 SQL에 비해 유연하며 더 적절하다.
데이터베이스는 프리젠테이션과 비즈니스로직의 구현에 관계 없이 데이터의 저장과 조회의 효율성에 중점된 저장 레이어가 될 수 있다. 이 시나리오가 바로 n-tier의 목표이다. 그러나 특히 유효성 검사와 같은 것은 여전히 클라이언트에 존재 할 수 있다. 그런 룰 들은 비즈니스 레이어에 의해서 강화 되어야 한다. 더 나아가 몇몇 시스템에서 일괄 업데이트와 같은 경우의 성능 극대화 때문에 데이터베이스에 위치 될 수 밖에 없는 비즈니스 로직의 예외 같은 것을 재정의 할 수도 있다. 좀 더 실제적인 접근법은 다음과 같다. 비즈니스 로직의 100%는 비즈니스 레이어에 위치시키고, 전적으로 성능을 위한 목적일 경우와 사용자 인터페이스를 위할 경우에만 다른 레이어에 중복되는 것을 허용하라.
미들-티어로 이전하기 Moving to the middle tier
위험한 비탈길 Slippery Slope
미들-티어 로 이전하는 작업을 할 때에는 항상 “이건 그냥 저장프로시저로 남겨 놓자” 하는 욕구가 생긴다. 그 다음 “이것도”, “저것도”. 결과적으로 변경하기 이전과 같은 상황에 이른다.
저장프로시저는 SQL을 실행 시키고, 데이터베이스의 결과 집합을 반환하는 데에는 최적화된 저장프로시저가 뷰(View) 보다 좋다. 하지만 결과를 반환 하기 위한 Join 이외의 어떠한 일을 하면 안 된다. 데이터를 정확히 수정하는 일만 해야지 데이터를 재해석하는 일을 해서는 안 된다.
강력한 성능상의 이유로 몇몇 비즈니스 룰은 저장프로시저에 존재할 수 있다. 그러나 저장프로시저로만 처리 해야 할 경우는 매우 드물며 예외적인 상황에서만 쓰여야 한다. 규칙은 아니지만, 이런 예외는 개발자와 데이터베이스 관리자에 의해서 검증되고 승인된 경우에만 허용 될 수 있다.
저렴하다. Cheaper
하드웨어를 구매하는 것이 더 저렴하다는 말을 한다면 이상하게 들릴 수 있다. 하지만 미들-티어 서버를 추가할 때에는 운영체제 이상의 소수의 소프트웨어가 필요할 수 있다.
데이터베이스 용량을 확장할 때 명백히 두 가지 이유의 비용이 발생한다:
데이터베이스 서버는 일반적으로 미들-티어 서버보다 비싸다. 데이터베이스는 추가 CPU당 라이선스나 높은 요금을 요구할 확률이 높다. 라이선스 요금은 CPU당 5천 달러에서 4만 달러에 이를 수 있다. 로직을 미들-티어로 이전 하는 것은 명확하게 데이터베이스 서버의 부하를 줄 일 수 있으며, 어설픈 데이터베이스 확장을 방지할 수 있다.
더 쉽다. Easier
비용과 더불어, 미들-티어를 업그레이드 하는 것은 데이터베이스를 업그레이드 하는 것 보다 쉽다.
데이터베이스는 하드웨어를 추가하는 것 만으로는 확장의 한계가 있다. 어떤 상황에서는 파티셔닝, 클러스터링, 리플리케이션과 같은 기술을 사용하거나 명확히 하드웨어에 투자하는 경우도 있다. 하지만 이것들 중에 간단한 기술은 하나도 없다.
미들-티어 서버를 확장하는 것은 쉽다. 로드 분배기를 한번만 설치하면 능력 확장을 위해 새로운 서버를 추가하는 것은 간단하다.
위상 Topology
아래 다이어그램의 요소에 대해 토론해 보자. 티어 다이어그램의 막대는 방향을 나타내며 자막은 등급을 나타낸다. 장비의 단위 가격은 클라이언트에서 미들-티어, 데이터베이스 순서로 높아진다.
결과 차트를 보면 더욱 쉽게 비교할 수 있다:
각각의 엔터프라이즈의 특성과 연산능력, 네트워크 설정의 의존성 때문에 많은 경우를 배치 할 수는 없었지만, 각각의 특성에 맞게 측정 되었다. 여기서 말하려 하는 것은 각각 측정치에 따른 등급의 일반적인 관계이다. 관계 있는 요소들을 겹쳐 보임으로써 가용량 확장을 위해서는 데이터베이스 보다 미들-티어의 경우가 쉽고 저렴하다는 것을 명확히 알 수 있다.
미들-티어 성장시키기 Grow the middle
비즈니스 로직의 중대한 부분을 데이터베이스에 구현해 놓았다면, 더 거대한 데이터베이스가 필요하며, 시나리오는 다음과 같다:
로직을 미들-티어로 이전함으로써, 데이터베이스 부하를 극적으로 줄일 수 있다. 아래의 숫자들은 예시의 목적이지만 요점을 이해하는데 도움을 줄 것이다. 전체를 표현하기 위해서는 다이어그램에 하드웨어가 더 필요하지만, 배포되는 시스템의 전체 가격이 저렴해지고 쉬워진다는 것을 알 수 있으며, 미들-티어를 성장시키는 것은 더 쉽고, 저렴하다.
병목 Bottleneck
앞의 그래프를 다시 한번 보자:
시스템 확장 관점에서 단일 병목은 무엇인가? 위의 티어 들에서 가용량의 증가 크기를 제한하는 요소는 무엇인가? 명백하게 데이터베이스이다. 모든 것은 데이터베이스로 흘러 들어가고 있다.
연산을 미들-티어로 이전함으로써 데이터베이스의 부하를 줄일 수 있다.
장애물들 Obstacles
통합 설계로 가는 데에는 몇 가지 장애물이 있다.
습관들 Habits
“세 살 버릇 여든 간다”라는 말이 있다. 이것은 팀에도 적용 가능하다. 당신 만이 아닌 팀 전부의 문제이다.
절차들 Procedures
많은 회사들이 보안 요소는 저장프로시저의 제한된 뷰에 의해 제공하며, 데이터베이스에서 통제되어야 한다는 오래된 정책을 가지고 있다. 회사 보안 정책을 n-tier의 세계로 이전시키는 것은 불가능 하거나 매우 어렵다.
.NET 은 전례 없이 보안 요소를 미들-티어 레벨에서 지원하고 있고, 강화할 예정이지만 많은 회사들은 여전히 데이터베이스에서 처리하는 것에 관심을 가지고 있으며, 바꿀 의지조차도 없다.
데이터베이스 관리자들 Database Administrators
이것은 민감한 주제이다. 하지만 언급할 수 밖에 없다. 당신이 DBA이건 개발자이건 내가 말하고자 하는 것이 극단적인 경우 이거나 모든 DBA가 그렇다고 확대해석 하지 않기를 바란다. 그렇지만 지금 말하는 것은 매우 일반적이거나 매우 빈번히 발생하는 경우이다. 당신이 DBA라면 좋다!(Bravo). 당신은 데이터베이스의 책임자이지 데이터베이스의 신은 아니다.
DBA는 종종 작동하는 시스템에 대해서 어떠한 합리적인 변경도 하지 않으려 한다. 시스템을 깨뜨릴 수 있기 때문이다. 많은 엔터프라이즈 시스템에서는 한 명의 DBA와 여러 명의 DA(Database assistants) 가 존재한다. DBA는 도메인의 왕 이자 데이터베이스와 관련한 모든 최종 결정권자 인체 한다. 오로지 관리 임무만이 DBA에게 주어진다. 관리 의무 때문에 DBA는 기술적인 DB 이슈에 대한 평가로부터 면제 받고 있다.
대부분의 DBA는 n-tier 시스템으로의 변경 필요성에 대해 조금의 지식 밖에 없거나, 어떤 티어 모델이건 신경 쓰지도 않으며, 모든 것이 클라이언트 서버 모델 이라고만 생각한다. 그들의 관심사는 오직 데이터베이스가 작동하는 것 뿐이며, 그들이 신경 쓰이지만 않는다면 개발자에게 몇 가지를 해줄 뿐이다.
DBA는 개발자들이나 회사보다 민첩하지 않으며, 그들 대부분은 지난 10년, 20년 동안 기업 데이터베이스를 관리해 왔다. 그들에게 데이터베이스는 매우 중요하며, 데이터베이스 없이는 아무것도 할 수 없다. 그들의 왕국을 관리해 왔으며, 마지 못할 경우에만 그것을 컨트롤 했다. 이런 DBA들에게는 보안 레벨을 낮춘다거나 구현하는 것은 관리에 있어서 매우 큰 고난이다.
어떤 DBA들은 그렇게 까다롭지 않으며, 합리적인 이유를 찾아서 일을 한다. 하지만 매우 많은 기업에서, 특히 개발자가 수 십 명 혹은 백 명이 넘는 개발자들이 있는 기업 에서 한 명 또는 몇 명의 DBA가 명령 계통의 최고 꼭대기에 앉아 있다.
도구들 Tools
오늘날 사용 가능한 도구들이 비즈니스 로직을 지원하거나 이바지 하는 도구들은 아니다. 많은 도구들이 단순히 확장, 연결 풀링, 데이터베이스 임피던스에 초점이 맞추어져 있을 뿐 비즈니스 구현의 목적인 것이 아니다.
해결책들 Solutions
설계 정책 Architect policing
나는 비즈니스 로직을 구현 하는 유용하고 규칙적인 시스템 설계를 찾았다. 머지 않아 완료될 것이며 쉽고 비용을 낮추게 할 것이다. 개발팀에 마스터 설계자가 없다면 개발자중 하나가 팀의 정책을 정할 수 있을 것이다. 부적절한 곳에 무엇 인가가 발견 된다면 개발팀이나 리더에게 경보를 해 줄 수 있다.
DA 교육 DA education
DA를 교육하는 것은 매우 중요하다. DA는 비즈니스 로직을 구현하는 일을 오랫동안 해왔다. 그들이 저장소로부터 비즈니스 로직을 분리하는 것은 기대하는 것은 매우 어렵다. DA는 전형적으로 그들이 필요한 것만 한다. 일반적으로 DBA의 지시를 따르는 일 말이다.
DA가 할 일은 아직 남아 있다. 그들은 JOIN, SQL 최적화, 그리고 데이터베이스를 관리하는 일을 한다. 또한 미들-티어로 부터 요청되는 SQL 과 데이터베이스 성능을 모니터링 한다. 그리고 계속해서 데이터베이스를 설계한다.
관리 교육 Management education
관리에는 종종 방해물이 있다. 비교적 극복하기 쉬운 장애물 일 지라도 말이다. 당신의 일이 쉬워 진다면 관리하는 일은 아무 것도 아닐 수 있다. 하지만 비용, 개발 시간, 비즈니스 수익, 그리고 수 많은 전문 용어들은 문제가 될 수 있다.
가장 큰 장애물은 DBA로 부터 오는 저항일 것이다. 관리를 비싸게 팔아 버리고, DBA 를 신경 써라.
더 읽을 것. Further reading
이 글의 아이디어는 내가 10년 가까이 겪어온 실무와 경험이다. 물론 이 아이디어들은 지속적으로 정제되고, 업데이트 되며, 필요에 따라서 새로운 기술이 채택되고 있다.
내가 일하는 동안 “전문가”라고 써 있는 매우 많은 논문을 읽었다. 불행하게도 대부분의 이런 논문들은 개발자들이 쓴 것이 아니라, 단 한 번의 실무 경험도 없는 이론가들에 의해서 쓰여졌다. 다른 논문들은 경험 많은 개발자들에 의해 쓰여졌지만, 특정 도메인에 한정 되었거나, 광범위한 지식이 부족한 상태 에서 쓰여 졌다. 개발자 들이 이러한 논문을 읽을 때, 모든 문제를 풀 때 한가지 해결책 만이 존재한다고 가정할 수 있다. 개발자들은 열린 마음을 가지고, 문제를 해결하는데는 여러 가지 해결책이 있음을 이해하고, 그러한 논문은 가이드 라인으로 삼을 수 있는 다른 사람들의 경험일 뿐이지 복음이 아님을 알아야 한다.
나는 이 모든 것을 언급 해야만 했다. 덫에 메이지 않고 정말 훌륭한 문서가 없기 때문이다. 근 몇 년 동안에 내가 읽은 최고의 논문은 Microsoft's Patterns and Practices 정도이다. Microsoft's Patterns and Practices는 내가 여기서 말한 , 그리고 다른 글에서 말하는 것의 좋은 친구이다.
제발 [Designing data tier components and passing data through tiers] 챕터를 참조 해라.
결론. Conclusion
큰 기업에서 방향을 바꾼다는 것은 매우 정치적일 수 있고, 위험성도 있다. 개발자 관점에서 다른 사람과 싸우는 것은 쉽다. 다만 많은 개발자들이 지금까지 사용하던 도구(습관, 실무적 경험)를 사용하는 것을 멈추리라는 것은 확신하지 못한다. 이 글을 통하여 당신이 지금까지의 처리 과정을 수정하거나, 적어도 조금이라도 고민하고 결정하는데 도움이 되었기를 간절히 바란다.
여기에 기술한 방법은 새로운 시스템에도 적용할 수 있으며, 전체 시스템의 일부에만 적용할 수도 있다. 이미 존재하는 시스템에는 새로운 디자인이 요구될 때까지 그대로 두는 것이 일반적으로 최고의 방법이다.