본문 바로가기
Engineering/SW Architecture

클린 아키텍쳐 (6) - 세부사항

by 쿨쥰 2023. 3. 31.

이전 글 : 아키텍처 [부분적 경계, 계층과 경계, 메인 컴포넌트, 크고작은 모든 서비스들, 테스트 경계]

2023.03.26 - [Engineering/SW Architecture] - 클린 아키텍쳐 (5) - 아키텍처 [부분적 경계, 계층과 경계, 메인 컴포넌트, 크고작은 모든 서비스들, 테스트 경계]

 

클린 아키텍쳐 (5) - 아키텍처 [부분적 경계, 계층과 경계, 메인 컴포넌트, 크고작은 모든 서비스

이전 글 : 아키텍처 [소리치는 아키텍처, 클린 아키텍처, 프레젠터와 험블 객체] 2023.03.22 - [Engineering/SW Architecture] - 클린 아키텍쳐 (4) - 아키텍처 [소리치는 아키텍처, 클린 아키텍처, 프레젠터와

skidrow6122.tistory.com

 

 


 

 

< 데이터베이스 >

아키텍처 관점에서 볼 때 DB는 엔티티가 아니라 세부사항이라서 아키텍처의 구성요소 수준으로 끌어올릴 수 없다.

어플리케이션 내부의 데이터 구조는 굉장히 중요하지만, DB는 데이터 모델이 아니고 일개 SW일 뿐이다.

즉, DB는 데이터에 접근할 방법을 제공하는 유틸리티다.

역시 아키텍처 관점에서 보면 이러한 유틸리티는 저수준의 메카니즘일 뿐이라서 아키텍처와는 관련이 없다.

관계형 데이터베이스

RDB는 모델 특유의 우아함, 절제됨, 강건함을 무기로 하여 80년대 중반 부터 데이터 저장소의 지배적인 형태가 되었다.

하지만 RDB의 기술이 얼마나 뛰어나든, 적절하고 견고하든 결국은 그저 기술일 뿐이다.

(물론 이는 SW 아키텍처의 입장에서 바라본 DB에 대한 이야기다.)

RDB는 특정 형식의 데이터에 접근하는 경우 매우 편리하지만, 데이터를 테이블에 행단위로 배치한다는 사실 자체는 SW아키텍처 적으로 볼 때 전혀 중요하지 않다.

따라서 어플리케이션의 유스케이스는 이러한 방식을 알아서도, 관여해서도 안 된다.

즉, 데이터가 테이블 구조를 가진다는 사실은 아키텍처의 외부 원에 위치한 최하위 수준의 유틸리티 함수만 알아야 한다.

많은 데이터 접근 프레임워크가 테이블과 행이 객체 형태로 시스템 여기저기서 돌아다니게 허용하는데 이는 아키텍처 적으로 위험하다.

이렇게 되면 유스케이스, 업무규칙, 심지어는 UI까지 RDB구조에 결합되고 말아 버리기 때문이다.

Why RDB?

데이터 베이스 시스템(오라클, MySql 등)이 지금까지 RDB를 중심으로 지배적인 우위를 차지한 배경에는 바로 저장 장소가 ‘디스크’ 였기 때문이다.

하지만 하드웨어 기술의 발전으로 디스크 저장소는 머지않아 자기 테이프, 플로피 드라이브, CD와 같이 소멸의 과정을 따를 것이다.

디스크는 메모리 하드웨어 기술의 발전에 밀려 점차 RAM으로 대체 되어가고 있기 때문이다.

* 저자의 접근이 현 시점에 다소 비약적이라고는 생각하나 컴퓨터 과학의 발전 역사 위에서 바라보면 완전 틀린 접근 같지는 않다는 생각이다.

RAM 저장소를 주로 사용하는 시대가 오면, 데이터들은 연결리스트, 트리, 해시 테이블, 스택 등의 자료 구조 형태로 체계화 되어갈것이다.

사실 우리는 이미 데이터가 DB 또는 파일시스템 안에 있더라도 프로그램에서는 이를 RAM으로 읽어들인 후 어플리케이션에서 다루기 편리한 형태(리스트, 스택, 큐, 트리 등)로 그 구조를 변경해서 사용하고 있다.

DB가 세부사항이라고 말하는 이유는 바로 이러한 현실 때문이다.

데이터베이스는 디스크 표면과 RAM 사이에서 데이터를 이리저리 옮길 때 사용할 뿐이다.

실제 현 시점에서의 DB는 비트를 담는 거대한 그릇이며, 데이터를 장기적으로 저장하는 공간에 지나지 않는다.

따라서 아키텍처 관점에서 본다면 회전식 자기 디스크에 데이터가 있기만 한다면 데이터가 어떤 형태로 존재하는지? 정말로 우리는 디스크 자체가 존재한다는 사실 조차도 인식해서는 안된다.

성능 관점에서의 접근

아키텍처적인 관점에서도 성능은 매우 중요한 사항은 맞다.

하지만 데이터 저장소의 측면에서 성능은 완전히 캡슐화하여 업무규칙과는 분리할 수 있는 관심사다.

데이터 저장소에서 데이터를 빠르게 넣고 뺄 수 있어야 하는 것은 맞지만, 이는 저수준의 관심사다. 이 관심사는 저수준의 데이터 접근 메커니즘 단에서 다룰 수 있으며, 성능은 결과적으로 시스템의 전반적인 아키텍처와는 아무런 관련이 없다.

하지만 client는 이 모든 서비스 클래스에 대해 추이 종속성을 가지게 된다.

정적 언어였다면 서비스 클래스 중 하나에서 소스코드가 변경되면 client도 무조건 재컴파일 해야 할 것이며, 비밀통로 또한 정말 쉽게 만들 수 있게 된다.

체계화된 데이터 구조와 데이터 모델은 아키텍처적으로 중요하다.

반면, 그저 데이터를 디스크에서 RAM으로 이리저리 옮길 뿐인 기술과 시스템은 아키텍처 적으로 중요하지 않다.

데이터를 테이블 구조로 만들고 SQL로만 접근하도록 하는 RDBMS 개념자체는 단지 ‘기술’ 과 ‘시스템’ 에 불과하다.

데이터는 중요하다. 데이터베이스는 세부사항이다.

*물론 2020년대를 살고 있는 현 시점 엔지니어에게 RDBMS는 최우선적으로 검토해야할 사항임은 맞으나, 이 차이를 SA의 철학으로서 항상 염두에 두자.

저자의 경험담 중, 과거 랜덤 액세스 파일 저장소를 주장하던 저자와, 기술적 대세에 따른 시대적 요구사항이었던 RDBMS 도입을 주장하던 관리자의 싸움을 생각하자.

공학적 접근으로는 저자는 옳았지만, 결국 시대의 명령은 RDBMS 였다.

 

 

 

< 웹 >

지난 업계의 역사를 되돌아 보면 모든 연산능력을 중앙 서버에 두는 방식과, 단말에 두는 방식 사이에서 끊임 없이 움직여 왔다.

웹이 눈부시게 발전된 기술이 하이라이트를 받은 이래 지난 십수여년 사이에도 우리는 이러한 진동을 여러차례 목격했다.

  • 처음에는 모든 연산능력이 server farm 에 위치할 것이고 브라우저는 멍청할 것이라고 생각했다. (서버 중심)
  • 그러다가 브라우저에 applet을 추가하기 시작했다. (클라이언트 중심)
  • 그러다가 이 방식이 마음에 들지 않아 동적인 내용은 다시 서버로 내려 보냈다. (서버 중심)
  • 그러다가 또 이 방식이 마음에 들지 않아 웹2.0을 고안했고, ajax 와 자바스크립트를 활용한 처리과정의 많은 부분을 다시 브라우저로 옮겼다. (클라이언트 중심)
    • 지금은 거대한 어플리케이션 전부를 브라우저에서 실행할 수 있도록 코드를 쓸 수 있는 수준까지 다다랐다.
  • 그리고 또 다른 한편으로는 node.js를 이용해 자바스크립트를 다시 서버로 이동시키는 방식에 열광하기도 한다 (서버 중심)

끝없는 반복

이처럼 반복되는 진동이 웹으로부터 시작되었다고 보는 일은 사실 옳지 않은것이 웹이 있기 전에는 클라이언트-서버 아키텍처가 있었기 때문이다.

앞으로도 우리는 연산능력을 어디에 둘지 알 수 없을 것이고 이러한 진동은 한동안 계속 될 것이다.

IT 역사 전체로 시야를 넓혀보면 웹은 사실 아무것도 바꾸지 않았다.

즉, 웹은 우리가 발버둥치면서 생기는 여느 수많은 진동 중 하나였던 것이다.

단지 SA로서 우리는 멀리 내다봐야 하기에, 이 진동은 그저 핵심 업무 규칙의 중심에서 밀어내고 싶은 단기적인 문제일 뿐이라고 간주해야한다.

저자의 Q사 GUI (데스크톱 앱의 UI → 웹 스타일 룩앤필의 UI → 다시 UI 스타일 복귀) 변천을 주도한 마케팅 천재의 사례를 기억하자.

세상에는 마케팅 천재가 진짜 많다. 따라서 SW아키텍처는 어플리케이션의 UI와 업무 규칙을 격리하는 일에 노력을 쏟아야한다.

이 마케팅 천재들은 다음에 무슨일을 할지 우리는 전혀 모르기 때문이다.

요약

GUI는 세부사항이다. 웹은 GUI다. 따라서 웹은 세부사항이다.

따라서 아키텍트라면 이러한 세부사항을 핵심 업무 로직에서 분리 된 경계 바깥에 두어야 한다.

웹은 입출력 장치라 생각하자.

어플리케이션이 장치 독립성을 지녔을때 가지는 가치는 누구나 알 것이다. 이 컨셉에서 웹도 예외가 될 수 없다.

물론 웹 GUI는 다채롭다 + 자바스크립트의 유효성 검증 + ajax + 위젯 등등의 웹 특유의 기능 때문에 웹에서 장치 독립성과의 유사성을 찾는 것이 억지 일 수 도 있다.

이 주장도 어느정도는 옳다. 왜냐하면 어플리케이션과 GUI의 인터랙션은 보다 빈번하며, 인터랙션 방식역시 사용중인 GUI 종류에 따라 차이가 매우 크기 때문이다.

하지만 UI와 어플리케이션 사이에는 추상화 가능한 또 다른 경계가 존재함을 잊지 말자.

업무 규칙은 다수의 유스케이스로 구성되며, 각 유스케이스는 사용자를 대신해서 일부 함수를 수행한다.

각 유스케이스는 입력 데이터, 수행할 처리과정, 출력 데이터를 기반으로 기술 할 수 있다.

UI와 어플리케이션이 함께 춤추는 동안, 어떤 시점이 되면 입력 데이터가 완전히 구성될 것이고, 그러면 유스케이스를 실행할 수 있는 단계가 된다.

유스케이스가 종료되면 해당 입력 데이터에 따른 결과 데이터는 UI와 어플리케이션이 함께 추는 춤으로 다시 되돌려 줄 수 있다.

즉, 완전한 입력 데이터와 그에 따른 출력 데이터는 데이터 구조로 만들어서 유스케이스를 실행하는 처리 과정의 입력 값과 출력 값으로 사용할 수 있다.

이 방식을 따르면, 각 유스케이스는 장치 독립적인 방식으로 UI라는 입출력 장치를 동작시킨다고 간주할 수 있다.

물론 이러한 종류의 추상화는 만들기 쉽지않다. 하지만 가능하다.

그리고 세상은 마케팅 천재들로 가득 차있다는 사실을 항상 기억하자.

 

 

 

< 프레임워크 >

프레임워크는 무료인데다가 강력하고 솔직히 매우 유용하므로 인기가 많다. 하지만 아무리 해도 프레임워크는 아키텍처가 될 수 없다.

프레임워크 제작자의 관점

대다수의 프레임워크 제작자는 커뮤니티에 도움이 되기를 바라는 마음에 자신의 작업물을 무료로 제공한다.

이는 고상한 동기이므로 분명히 칭찬받을 일임에 틀림없다.

하지만 이들은 우리가 풀어야 할 특별한 관심사를 염두에 두지 않는다. 내가 진짜 풀어야할 문제를 알지 못하기 때문이다.

프레임워크 제작자는 자신이 해결해야 할 고유한 문제나 자신의 동료와 친구들의 문제를 알고 있다.

그리고 그러한 문제들을 해결하기 위해 프레임워크를 만든다.

하지만 가장 중요한 것은, 그들은 내 문제를 해결하기 위해 고민하지 않는다.

비대칭성

우리와 프레임워크 제작자 사이의 관계는 놀라울 정도로 비대칭적이다.

우리는 프레임워크를 위해 대단히 큰 헌신을 해야 하지만, 그들은 우리를 위해 아무런 헌신도 하지 않는다.

이 점을 신중하게 생각해야한다. 프레임워크 제작자가 제공하는 문서에서 제작자는 우리가 만들 SW와 프레임워크를 어떻게 통합할 수 있을지 조언한다.

대개의 경우 이들은 프레임워크를 중심에 두고 우리의 아키텍처는 그 바깥을 감싸야한다고 말한다.

예를 들어 프레임워크의 기반 클래스에서 직접 파생하거나, 프레임워크의 기능들을 업무 객체에 바로 import해서 사용하라고 말이다.

이들은 우리의 어플리케이션이 가능하면 프레임워크에 강력히 결합될 것을 역설한다.

제작자는 그 프레임워크에 대해 절대적인 제어권을 쥐고 있기 때문에 그들의 입장에서는 프레임워크와의 이러한 결합이 위험요소가 되지 않는다.

이러한 혼인 관계는 매우 일방적이다.

모든 위험과 부담은 오롯이 우리가 감수할 뿐, 제작자가 감수하는 것은 아무것도 없다.

위험요인

이러한 위험 요인은 어떤것이 있을까?

  • 프레임워크의 아키텍처는 그다지 깔끔하지 않은 경우가 많다.
    • 의존성 규칙을 위반하는 경향이 있기 때문이다. 업무 객체를 만들 때, 프레임워크 제작자는 자신의 코드를 상속할 것을 요구한다.
    • 제작자는 프레임워크가 우리의 가장 안쪽 원과 결합되기를 원하지만, 이것이 한번 안으로 들어오면 다시는 원 밖으로 나오지 않을 것이다.
  • 어플리케이션이 발전해나가면서 우리는 프레임워크와 계속 싸워야만 할 것이다.
    • 초기에는 초기기능을 구현하는데 도움이 될 수도 있다.
    • 하지만 제품이 성숙해지면서 프레임워크가 제공하는 기능과 틀을 점점 벗어날 수 밖에 없다.
  • 프레임워크는 우리에게 도움되지 않는 방향으로 진화할 수 도 있다.
    • 도움 되지 않는 신규버전으로 업그레이드 하느라 정작 중요한 일을 못할 수도 있다.
    • 심지어 사용중이던 기능이 사라지거나 반영이 힘든 형태로 변경될 수도 있다.
    • 이러한 lock in 이 깊어진 다음, 다른 더 좋은 프레임워크로 갈아 타고 싶어 질 수 도 있다.

해결책

“프레임워크와 결혼하지 말라!”

프레임워크를 사용할 수는 있지만 결합해서는 안되고 적당히 거리를 두자.

프레임워크는 아키텍처 바깥쪽 원에 속하는 세부사항으로 취급하라.

업무 객체를 만들때 프레임워크가 그들의 기반 클래스로로부터 파생하기를 요구한다면 거절하라.

대신 proxy를 만들어 업무 규칙에 플러그인 할 수 있는 컴포넌트에 이들 proxy를 위치시켜라.

spring은 매우 훌륭한 의존성 주입 프레임워크다.

주로 의존성을 연결할때 @autowired 어노테이션을 사용하는데, 업무 객체 도처에 이것이 산재 해서는 안된다. 업무 객체는 절대 스프링에 대해 알면 안되기 때문이다.

업무 객체 보다는 메인 컴포넌트에서 의존성을 주입하는 것이좋다.

메인은 아키텍처 내에서 가장 지저분한, 최저 수준의 컴포넌트이기 때문에 스프링을 알아도 상관이 없다.

사실, 제품을 구현하기 위해서는 프레임워크를 써야만 하는 경우가 대부분이다.

이러한 관계는 지극히 정상이지만 선택적이어야 한다.

어플리케이션이 프레임워크와 결혼하고자 한다면, 그 어플리케이션의 남은 생에 동안 그 프레임워크와 항상 함께 해야 한다는 사실을 반드시 명심하자.

결혼하기에 앞서 잠시 동안 연애를 해보던가 가급적 프레임워크를 가급적 오랫동안 아키텍처 경계 너머에 두자.

댓글