애플리케이션 코드에서 UI·프레임워크·데이터베이스를 분리해 디커플링하자는 주장과 이에 대한 반론에 답하며, 테스트 용이성과 유연성, 의사결정의 연기 가능성 등 실질적 이점을 설명한다.
아키텍처를 정리할 필요성에 대해 이야기하기 시작한 이후 몇 주 동안, 나는 이 아이디어에 대한 놀라운 저항을 목격했다. 프레임워크, UI, 데이터베이스를 애플리케이션 코드로부터 숨기는 것이 좋은 생각이라는 notion이 보편적으로 받아들여지는 것은 아닌 듯하다.
이 주제에 대해 처음 블로그에 글을 쓴 것은 여기이고, cleancoders.com에서 에피소드 하나를 통째로 이 주제에 할애했다. 또한 이 주제로 기조연설도 여러 번 했고, 그 슬라이드는 여기, 영상 녹화는 여기에 있다.
약간은 이견을 보인 글로는, _The Frustrated Architect_가 그의 coding {the} architecture 블로그에 쓴 이 글이 있다. 그는 그림 하나를 보여주는데, 여기에도 반복해 싣겠다:
그가 말하려는 요지는, 만약 UI와 데이터베이스가 비즈니스 규칙보다 시스템에서 훨씬 큰 부분을 차지한다면 시스템의 아키텍처는 그 더 큰 요소들을 중심으로 구성되어야 한다는 것이다. 물론 나는 동의하지 않는다. 시스템의 어느 한 부분이 아무리 커도 다른 부분들은 그것으로부터 디커플링되어 있어야 한다.
다른 이견들(혹은 “회의적”이라는 말이 더 나을지도 모른다)은 덜 공식적이었다. 누군가는 그냥 나에게 “이걸 실제로 해 본 적 있나요 – Rails 프로젝트에서”라고 물었다. 마치 Rails가 뭔가 특별해서 게임의 법칙을 완전히 바꿔 놓아 좋은 설계의 일반 규칙이 적용되지 않는다는 듯이 말이다.
또 어떤 사람들은 내 조언의 순 효과가 코드 중복과, 시스템 계층 사이에서 한 데이터 구조에서 다른 데이터 구조로 데이터를 기계적으로 복사하는 일의 증가일 것이라고 걱정했다. 물론 나도 그런 걸 원하지 않는다. 그리고 내가 제안한 어떤 것도 데이터 구조의 반복이나 과도한 필드 복사를 불가피하게 만들지 않는다. 그 이유는 아래에서 설명하겠다.
특히 인상적인 불만 하나는 다음과 같았다. “이건 독단적 푸념처럼 들립니다. 코드를 보고 싶어요.” 그 관점에 공감하지만, 여기의 개념은 이해하기 그리 어려운 게 아니다. 사실 코드를 잔뜩 보여주는 것이 오히려 개념을 흐리게 만들 뿐이다.
이건 로켓 과학이 아니다. 기본 아이디어는 아주 단순하다. 단순한 데이터 구조를 주고받아 UI와 비즈니스 규칙을 분리한다. 컨트롤러가 비즈니스 규칙에 대해 아무것도 알도록 두지 않는다. 대신 컨트롤러는 HttpRequest 객체를 단순한 바닐라 데이터 구조로 풀어내고, 그 데이터 구조를 인터랙터 객체에 전달한다. 인터랙터는 비즈니스 객체를 호출하여 유스케이스를 구현한다. 그런 다음 인터랙터는 응답 데이터를 또 다른 바닐라 데이터 구조에 모아 UI로 돌려준다. 뷰는 비즈니스 객체를 알지 못한다. 그저 그 데이터 구조를 들여다보고 응답을 표현할 뿐이다. 물론 그보다 더 많은 세부사항이 있고, 위의 참고 자료들에 잘 설명되어 있다. 하지만 근본적으로는, 딱 이게 전부다.
그 이점은 분명하다. 애플리케이션 코드는 UI로부터 완전히 디커플링된다. UI 없이도 애플리케이션 코드를 테스트할 수 있다. 테스트를 실행하기 위해 웹 서버나 컨테이너, Rails, 그 밖의 프레임워크를 기동할 필요가 없다. 게다가 현재 UI가 마음에 들지 않으면 다른 것으로 교체해 바꿀 수 있다.
이게 완벽한 방식인가? 물론 아니다. 어떤 유형의 UI는 다른 것과 너무 달라서 공통 인터페이스를 공유할 수 없을 수도 있다. 물론 그럴 수 있다. 그렇다고 이런 디커플링이 헛수고인가? 농담하지 마라.
아니다. 절대 아니다. 제발 좀, 이건 당신의 속도를 높여준다. 지연 없이 테스트를 실행할 수 있다. UI에 대한 판단을 미룰 수 있다. UI 없이도 비즈니스 규칙을 테스트할 수 있다. 그런 종류의 유연성과 디커플링은 항상 속도를 높여준다. 지난 50년 동안 결합에 대해 우리가 배운 것이 하나 있다면, 당신을 느리게 만드는 데 결합만큼 좋은 것은 없다는 것이다.
아키텍처에 관해 내가 했던 가장 강경한 주장 중 하나는, 좋은 아키텍처는 UI, 프레임워크, 데이터베이스 등과 같은 중대한 결정을 미룰 수 있게 해준다는 것이다. 여러 사람이 지적하듯이, 고객은 UI가 미뤄지는 것을 원하지 않는다. DBA는 데이터베이스가 미뤄지는 것을 원하지 않는다. 이터레이션마다 UI, 데이터베이스, 프레임워크를 포함한 전체 시스템이 동작하는 모습을 보고 싶어 한다. 단지 비즈니스 규칙에만 이터레이션을 쓰는 것을 원치 않는다. 실제로 좋은 애자일 관행은 아키텍처 전체를 관통하는 길고 얇은 슬라이스를 명시적으로 요구한다.
물론 그 모든 말에 동의한다. 하지만 길고 얇은 슬라이스가 결합되어 있어야만 하는 것은 아니다. 좋은 아키텍처는 중대한 결정을 미루도록 _허용_하지만, 그것들을 미루도록 _강제_하지는 않는다. 다만, 그것들을 미룰 수 있다는 것은 유연성이 크다는 뜻이다. 예를 들어, 처음 몇 스프린트 동안 임시의 단순한 UI를 만들고, 나중에 더 강력한 UI로 교체할 수도 있다.
Rails의 “설정보다 관습(Convention over Configuration)”이라는 만트라는 강력한 아이디어이며, 나도 전적으로 동의한다. 하지만 그렇다고 시스템을 결합시켜야 한다는 뜻은 아니다. 관습이 반드시 결합을 야기하는 것은 아니다! 예를 들어, Rails의 모델 객체들이 비즈니스 규칙 메서드를 품고 있어야 할 이유는 없다. 비즈니스 규칙을 ActiveRecord 파생 클래스들과 분리해 디커플링하는 것은 어떤 Rails 관습도 위배하지 않는다. 설령 위배한다고 하더라도, 나는 디커플링이 관습보다 우선한다고 생각한다.
가장 좋은 소프트웨어 설계 서적 중 하나는 Steve Freeman과 Nat Pryce의 “Growing Object Oriented Software”다. 그들은 시스템을 개발할 때 바깥에서 안으로 들어오는 접근(Outside-In)을 권한다. 인터페이스에서 시작해 비즈니스 규칙으로 들어가는 식이다.
처음엔 이것이 내 조언과 상충되는 것처럼 들릴 수 있다. 결국 나는 유스케이스에 집중하고 UI를 성가신 작은 디테일로 여긴다. 하지만 그 성가신 작은 디테일을 먼저 작업하더라도, 비즈니스 규칙을 그것들로부터 _디커플링_하기만 하면 아무 문제가 없다. GOOS의 이념 어디에도 비즈니스 규칙을 UI로부터 디커플링하는 것에 반대하는 내용은 없다.
사실을 말하자면, 나는 GOOS 방법론을 쓰지 않는다. 나는 안에서 밖으로(Inside-Out) 접근하는 것을 선호한다. 먼저 비즈니스 규칙에 집중하고, 그 위에 나중에 UI를 얹는 걸 좋아한다. 그렇다고 해서 GOOS 기법이 나쁘다는 뜻은 아니다(나쁘지 않다). GOOS를 따른다고 해서 디커플링된 아키텍처를 갖지 못하는 것도 아니다(그렇게 해야 한다!).
아니다, 그건 아니다. 내가 당신에게 몇 달씩 UML 다이어그램을 그리라고 말하는 게 아니다. 내가 말하는 건 _디커플링하라_는 것이다. 그 디커플링은 코드를 작성하고 테스트를 통과시키는 동안에도 할 수 있다. 잘 디커플링된 아키텍처를 만들기 위해 큰 사전 계획이 필요한 것은 아니다. 코드를 작성하는 동안 _생각_만 하면 된다.
다만, 시스템의 형태를 며칠, 아니면 하루 이틀 정도 곰곰이 생각하는 데 아무런 문제가 없다는 점은 짚고 넘어가고 싶다. 시스템이 어떻게 구조화되어야 하는지 아이디어를 얻기 위해 약간의 UML이나 다른 다이어그램을 그리는 것도 전혀 문제 없다. 몇 달씩 그렇게 하라는 건 아니지만, _생각_하는 것 자체는 나쁠 게 없다. (참고: Hammock Driven Development)
이 아이디어들에 대한 반응은 나를 놀라게 했다. 사람들은 본능적으로 변화를 거부하고, 많은 프로그래머들이 디커플링이라는 개념에 익숙하지 않다는 것을( 그 절을 몇 번이고 읽고 눈물 흘리라 ) 이해하긴 한다. 하지만 이것은 어느 날 문득 떠오른 새로운 아이디어가 아니다. 이 아이디어들은 오래된 것이다. David Parnas, Tom Demarco, Grady Booch, Ivar Jacobson, 그리고 수많은 다른 사람들에게서 비롯됐다. 그 아이디어들이 오래되었다고 해서 곧바로 좋다는 뜻은 아니지만, 이 경우에는 – 좋다.
우리에게 무슨 일이 있었던 걸까? 어떻게 우리는 이 규칙들을 잊어버렸을까? 결합과 응집에 관한 예전 규칙들은 언제 우리 의식에서 사라져 버린 걸까? 복잡한 시스템을 작성하는 최선의 방법이, 부품들을 한 봉지에 쓸어 넣고 흔들다 보면 언젠가 돌아가도록 만드는 것이라고 우리가 정말로 순진하게 믿는 걸까?