무늬만 계층형 아키텍처

“DAO 단에서 화면에 필요한 데이터를 미리 다 준비해서 가져온다.”

Dao, Service, Controller가 별개의 클래스로 구성되어 있고 또 인터페이스까지 만들어 놨다고 해서 계층형 아키텍처를 지키고 있는 아니다.

나도 잘 몰랐거나 오해했던 내용을 사부님과 이야기 나누며 다시 개념을 정리하고 있다. 이야기의 시작은 OSIV 패턴을 사용하는게 게층형 아키텍처를 위반한 것이냐 아니냐 였다. 나는 위반했다는 입장이었고, 사부님은 아니라는 것이었다. 결론부터 말하자면 내가 틀렸다.

우선 나의 생각은 이랬다. 어떤 블로거의 글처럼, 뷰 단에서 DB 쿼리가 발생할 수 있으니 DAO 계층에서 할 일을 뷰 단에서 한 것이나 마찬가지이고, 그래서 계층형 아키텍처가 깨졌다고 주장했다.

하지만 사부님은 간단하게 반론을 제기했다. 그렇다면 Transparent Persistence(TP) 기술 자체가 계층형 아키텍처를 위반한 것이라는 건데, 예를 들어 서비스 계층에서 Lazy loading하는 것도 그럼 계층형 아키텍처 위반이냐?

오히려 내 생각에 반전을 일으키는 말씀을 하셨다. TP 때문에 오히려 계층형 아키텍처가 굳건해 진다는 것이다. TP가 없었다면 오히려 도메인 객체만 전달하는게 아니라, 서비스나 컨트롤러 혹은 뷰 단에서 필요한 데이터를 전달하게 되는 것이고, 그렇게 되면 계층 간에 필요한 데이터가 무엇인지 분명히 알고 있어야 하기 때문에 그로인한 결합도가 생긴다는 것이다. 맞는 말이다. 계층 간에 주고받는 데이터가 구체적일 수록 변경에 민감하게 반응하게 될 것이다. 결국 겉으로만 분리되어 있고 실제로는 데이터를 중심으로 강하게 결합된 구조가 된다. 화면에서 보여줄 데이터가 바뀌면 결국 컨트롤러, 서비스, DAO 전부 바뀌게 되는 것이다. 그런데 JPA를 사용하면 얼마든지 TP가 가능하기 때문에 도메인 객체만을 주고 받게 되고, 그렇게 되면 데이터 중심의 개발 방법에 비해서 변경될 여지가 적다. 결국 유지보수성이 뛰어나다.

결국 TP는 계층형 아키텍처의 취지에 완벽하게 부합하는 것이다. 그리고 OSIV는 TP를 뷰 랜더링 시점까지로 연장시켜줄 뿐, 어차피 거의 기본적으로 서비스 계층의 오퍼레이션 마다 TP가 적용되고 있다. 그리고 애초에 뷰단에서 쿼리가 날아갔을 때 뷰단에서 JDBC Connection 객체를 가지고 코딩한 것도 아니고 그저 도메인 객체 그래프를 가지고 네비게이션 했을 뿐 아닌가? 코드 레벨에서 전혀 계층형 아키텍처를 위반하지도 않았다.

이야기는 계속 이어져서, 데이터 중심 개발 방법과 도메인 중심 개발 방법의 차이점과 특징에까지 이르렀다. 그리고 도메인 중심 개발 방법에서도 도메인 계층을 벗어날 때 DTO를 사용하자는 집단과 그러지 말고 그냥 도메인 객체 그대로 쓰자는 집단의 주장과 흐름까지도 이야기를 들었다.

“화면에서 어떤 데이터를 보여줄지 DAO가 다 알고 그에 맞게 SQL을 미리 다 짠다면 이미 DAO가 뷰 단과 강한 결합이 생겼다는 증거다. 이런건 계층형 아키텍처가 아니다.”

데이터 중심 개발을 하면 위에서 예를 든 것처럼 계층간의 결합도가 높아서 변경될 여지가 많다. 하지만 모든 계층에서 도메인 객체를 사용한다면 이야기는 달라진다. 모든 데이터는 이미 도메인 객체에 들어가서 메모리에 들어가 있다는 가정하에 도메인 객체를 네비게이션 하면서 비즈니스 로직을 처리하고 뷰에서 랜더링을 하는 것이다. 따라서 필요한 데이터가 도메인 객체 네비게이션으로 참조할 수 있는 한도 내에서는 전혀 코드를 변경할 필요가 없다.

“DAO, Service, Controller, 뷰를 전부 도메인 모델만 공유한 상태에서 각자 다른 팀에서 개발한다고 가정하고 코딩을 하면 도메인 중심 개발 방법에 가장 잘 맞는 형태의 코드가 나올 것이다.”

결국 OSIV로 얻을 수 있는 장점은 다음과 같다.

1. 개발 속도 향상

2. 이상적인 계층 구조 확보

3. 적절한 엔티티 캐시 활용

그러나 전제가 더 중요하다. “도메인 중심 개발 방법”을 적용했을 때에야 이런게 의미가 있지, 앞서 말한것처럼 “데이터 중심 개발 방법”을 사용하면서 하이버네이트나 OSIV를 사용하겠다는 것은 권장하지 못할 시도인것 같다. 그래가지고는 오히려 하이버네이트에 대한 악담과 비화만 늘어날 뿐이다.

사부님이 권장하는 하이버네이트 개발 스타일은 다음과 같다.

1. Entity 캐싱을 하고 join fetch 없이 개발

2. 매번 같이 다니는 연관 관계면 아에 매핑을 eager fetching으로 튜닝

3. 가끔씩 같이 다닌다면 런타임시 join fetch

도메인 중심 개발을 할 때 DTO를 쓰자는 입장은 화면단에서 도메인 객체에 setter 호출로 데이터를 조작할 수 있다는 것을 위험하다고 여겨서 함수형 언어에서 주로 사용하는 immutable한 객체를 만들어 넘기도록 DTO를 권장했다. 심지어 OSIV를 사용하는 경우에는 PT에서 도메인 객체를 수정하면 DB에 update 쿼리가 날아가기까지 했었다. 하지만.. 아드리안 콜리어가 등장해서 Aspectj 한줄로 뷰단에서는 setter 호출 불가, DAO 호출 불가 정책을 만들어 적용할 수 있다는 사실을 전파하자. 요즘은 DTO 사용하자는 집단이 조용해짐. 그냥 도메인 객체를 여러곳에서 사용하는 것으로… 고고씽…

위의 내용은 토비의 스프링 9장에 잘 나와있기도 하다. 722페이지부터 읽어보면 될듯하다. 이미 책으로 써주셨는데, 채팅으로 저자 직강을 듣고나니 감회가 새롭다. 문제다. @_@;; 점점 바보가 되가나봐…

12 thoughts on “무늬만 계층형 아키텍처”

  1. 위의 글과 관련된 내용을 예전 회사에 있을 때 토론을 해본 적이 있습니다. OSIV 패턴을 사용하는 것이 계층형 아키텍처를 위반 하느냐? 아니냐? 하는 토론이었죠.

    일단 결론은 OSIV 패턴은 계층형 아키텍처를 위반하는 것이다. 라고 결론을 내렸었습니다.

    첫 번째는 웹단 개발과 비지니스단 개발을 나눠서 개발한다고 하였을 때 웹단 개발자들에 위하여 조작이 가해질 수 있다는 문제점 때문이었습니다.

    두 번째는 웹이 아니라 다른 곳에서 비지니스 로직을 호출할 때였습니다. 클라이언트 — 웹서비스 — 기존비지니스로직 과 같은 순서로 호출한다고 하였을 때 OSIV로 개발된 사이트라면 기존 비지니스 로직 부분에서 추가적인 개발이 필요하다고 생각하였습니다. 웹과 비지니스를 완전히 분리할 수 있어야 레이어를 잘 나눴다라고 생각하였습니다.

    물론, 위에서 적으신 것처럼 도메인 모델을 각 레이어에서 공유하여 사용한다면 이라고 하셨는데 결국 도메인 객체는 레이어 아키텍처에 포함되는 것이 아니라 라고 말하는 것과 같은 말이 아닌가 하는 생각이 듭니다. 레이어 아키텍처에서 그냥 공통으로 이용하는 것이지 레이어 그 자체는 아니라는 의미지요. 그렇기 때문에 레이어 아키텍처라고 말할 수 없다라는 의미입니다. (아 말 참 어렵습니다.)

    특히 SI개발에서는 개발자의 역량이 너무 재각각입니다. 그런 상황에서 사용하기에는 위험한 방법이라는 생각도 듭니다.

    그냥 작은 의견 놓고 갑니다.

    1. 우와.. 정말 오랜만에 논의할 만한 댓글이 달렸군요. 감사합니다.

      첫 번째는 웹단 개발과 비지니스단 개발을 나눠서 개발한다고 하였을 때 웹단 개발자들에 위하여 조작이 가해질 수 있다는 문제점 때문이었습니다.

      => “조작”이라는 말이 애매한데요. 객체를 웹단에서 수정하는 경우를 말씀하시는 거라면.. 그래서 immutable한 DTO 객체를 만들어 사용하는 패턴을 선호하는 분들이 생겨났다는 이야기를 들은것 같습니다. 하지만, AOP의 대가 아트리안 콜리어가 Aspect 하나만 만들면 그런 일 방지할 수 있다. 고 해서 거의 종결된 것으로 알고 있습니다. 그런데 이런 일은 굳이 OSIV가 아니더라도 도메인 객체 중심으로 코딩을 할 때 발생할 수 있는 상황인것 같습니다.

      웹과 비지니스를 완전히 분리할 수 있어야 레이어를 잘 나눴다라고 생각하였습니다.

      => 각 계층이 오직 도메인 객체만 보고, 서로의 계층 사이는 강한 규약에 해당하는 인터페이스만 둠으로써 잘 나눠지지 않을까요? OSIV를 통해서 부가적인 쿼리가 발생하고 어쩌고는 신경쓸 필요 없이, 그저 도메인 객체 네비게이션을 해서 데이터를 조회해서 사용하는 것인데.. 웹과 비즈니스 계층 사이의 의존성은 없지요. 오히려… 둘 사이를 도메인 객체가 아니라 DTO라던가.. 데이터를 주고 받는 형태로 개발해버리면.. 주고 받는 데이터가 바뀌면 그 두 계층도 바뀔테니.. 강하게 결합되어 있는 형태가 아닐까요.. 바로 이런 계층형 아키텍처를 일컬어.. 무늬만 계층형 아키텍처라고 꼬집은 것이었습니다. 겉보기에는 잘 나눠진것 같지만 사실 들여다 보면.. 데이터가 바뀌면 줄줄이 사탕식으로 DAO, 서비스, 컨트롤러, 뷰가 다 바뀌는 엉터리 계층형 구조요.

      물론, 위에서 적으신 것처럼 도메인 모델을 각 레이어에서 공유하여 사용한다면 이라고 하셨는데 결국 도메인 객체는 레이어 아키텍처에 포함되는 것이 아니라 라고 말하는 것과 같은 말이 아닌가 하는 생각이 듭니다.

      => 글쎼요. 제가 봤었던 아주 단순한 계층형 아키텍처 그림들에는 거의다 도메인 객체가 새로 막대기로 서있고.. DAO, Service, Web 계층이 가로 막대리로 모두 도메인 객체와 맞닿아 있더군요. 사실 DDD에서는 별도의 계층으로 정의하기도 하지만.. 글쎼요. 흠.. ‘그냥 공통으로 이용한다..’라고 해서 레이어는 아니다? 라는건 잘 모르겠습니다.. 공통으로 이용할 수 있도록 세로로 세워져 있는 계층으로 그린게 아니었을런지… 싶네요.

      특히 SI개발에서는 개발자의 역량이 너무 재각각입니다. 그런 상황에서 사용하기에는 위험한 방법이라는 생각도 듭니다

      => 제가 SI를 잘 몰라서요. 어떤 상황인지 모르겠지만, 개발자의 역량 차이보다는, 개발을 데이터 중심으로 하면서, 객체지향 어쩌구를 떠들고, 겉모습만 객체 지향을 따라하는 모습을 자주 볼 수 있더라구요.

      역량이 제각각이라는건 사실 어느 분야, 어느 회사, 어느 세상을 가든 다 마찬가지 일꺼라 생각합니다. 그러니 저는 오히려 도메인 객체만 서로 공유하고, 개발자가 SQL로 어떤 데이터를 가져와야 하나 고민하기 전에,.. 먼저. 어떤 도메인 객체를 어떻게 네비게이션하고 어떤 메서드를 만들어서 비즈니스 로직을 구현하면 될까를 먼저 생각해보는 세상이 오면 좋겠습니다.

      의견 주셔서 정말 감사합니다. 나중에 오프라인에서 토론 형태로 진행되면 더 재밌겠네요. 🙂

      1. 긴 글 잘 읽었습니다. 흐으. 각 줄마다 반박을 받으니 정신이 번쩍 드는데요? 😛

        사실, 제대로 분석을 하고 그것을 그대로 설계로 옮긴다면 도메인 모델이 객체 지향적이라고 생각을 합니다.

        그럼, 이 도메인을 어디 시점까지 가져다 사용할 것이냐? 의 문제인데요.

        DTO를 사용하니 강한 결합이 발생한다고 하셨는데, 그건 어떻게 바라보느냐의 차이라고 전 생각합니다.

        또한 도메인 모델을 사용한다는 것은 유지보수가 편하다고 하셨는데요. 그것은 무엇에 비하여 유지보수가 편하다는 이야기일까요?

        모든 고객의 요구사항은 변할 수 있다고 보는 것이 맞지요. 저도 그렇게 생각합니다. 그렇다고 해서 모든 프로젝트가 에자일 스럽게 개발되는 것은 아닙니다. 전 에자일 기법이 항상 옳다고 생각하지도 않는 사람입니다. 전통적인 부분도 좋은 방법이라고 전 생각합니다. 다만, 사람 기술 환경에 맞게 사용해야 좋은 기술 방법론이라고 말할 수 있다고 생각합니다.

        분석/설계/구현

        위의 3가지 단계에서 그렇다면 도메인 모델을 언제 어디서 사용할까? 하는 것은 그럼 결정을 하지 않는 것인가요? 라고 묻고 싶습니다.

        업무가 복잡해질 수록 도메인만 가지고 화면에 결과를 출력하지는 않을 것입니다. 그 도메인을 가지고 가공을 하여 화면에 출력할 일이 많아지겠죠. 그리고, 그 업무를 제대로 개발하기 위하여는 꼼꼼한 분석/설계가 필요하다고 전 생각하고 있습니다.

        비지니스 단에서는 도메인 객체를 이용하여 프리젠테이션 단에서 사용할 결과를 만들어 내고 이 결과는 단순히 Read Only Data로 프리젠테이션 단으로 던져지는거죠. 물론 앞에서 대화했던 것처럼 AOP등을 이용하여 프리젠테이션 단에서 조작을 가하지 못하게 한다던지 하는 방법을 사용하면 좋을 듯 합니다. 이때 집어 던지는 것이 도메인이든, DTO든 전 상관이 없다고 생각합니다.

        프로젝트에 따라서 프리젠테이션단 사용자가 쉽게 이용할 수 있는 구조면 된다. 라고 생각하고 있기 때문입니다. 레이어 아키텍처가 의미하듯이 상위의 레이어에서 하위의 레이어만 호출할 수 있는 구조가 되면 된다는 것입니다.

        그런데 여기서 억울한 일이 벌어집니다. 도메인 객체를 사용하지 않고, DTO를 사용한다고 해서 이것을 데이터 중심의 개발로 보느냐? 이건 아니라는 것입니다.

        데이터 중심의 개발이 아니라 비지니스 객체 중심의 개발이라고 말하는 것이 좋겠지요.

        그런데, 또 이렇게 말할 수 있겠네요. 비지니스 메소드가 변경된다면 그럼 많은 변경이 가해지지 않겠느냐?

        네 그렇습니다. 그래서… 사실 분석/설계가 중요하다고 말하고 싶습니다.

        객체지향의 허구성이 좀 느껴지는 부분이 있습니다. 모든 객체가 재사용 되어야 할까요? 객체와 객체는 강한 연관을 가지면 안되는 것인가요? 그렇다면 연관관계는? 상속관계는 사용하면 안되는 관계인가요?

        데이터 중심의 개발방법에는 저 자신도 그다지 찬성하지는 않지만 도메인 모델이 꼭 답이라고는 생각하지 않아서 글 적어봅니다. 흐으. 이거 또 밑줄 그리면서…. 댓글 다시는거 아니죠???

        1. 내용을 쓰고 읽어보니 매끄럽지 않은 부분이 너무 많네요. -_-;

          정리하자면 OSIV 패턴과 도메인 객체 그 자체는 레이어 아키텍처라고 말할 순 없다라고 말하고 싶구요. 사실 패턴들은 정확히 자기가 무엇을 해야할지 강박적으로 정해져 있죠.

          도메인 모델 vs 데이터 모델

          이라고 하셨는데요. 제가 생각하는 것은

          도메인 모델을 프리젠테이션에서 이용 vs
          비지니스 객체를 잘 정의하고 이용

          으로 말하는 것이 레이어 아키텍처와 도메인 모델의 사용에 대하여 알맞게 잘 비교하는것 아니냐? 하고 말하고 싶었습니다.

          그리고 비지니스 객체와 프리젠테이션 간의 DTO사용이 강한 연관 관계를 맺는다고 하였는데, 그 부분을 도메인 객체를 사용함으로써 좀 더 유연한 구조로 할 수 있다는 것은 동의하지만, 그 자체로 객체지향적이지 않다 라고 말할 수는 없다는 거죠.

          그리고 말씀하신 AOP로 해결하는 방법도 OOP는 아니죠. AOP잖아요? 😛

          1. 아 글을 지울 수는 없나요… 좀 정리해서 다시 쓰려고 하였는데…. 글 쓰레드만 지저분하게 만든것 같아 죄송하군요.

            확실히 이런류의 이야기는 맥친을 먹으면서 빡시게 싸우면서 말해야 하는데 말입니다……….

            글로만 쓰니 너무 오해할 만한 구석이 많군요.

          2. 저는 AOP도 OOP를 보완하는 수단으로 생각합니다. 구체적으로, AOP는 횡단 관심사를 OOP 적으로 잘 다룰 수 있게 도와주는 프로그래밍 기술이 아닐지 싶습니다. 가장 큰 도움을 주는 원칙을 들자면 아마도 SRP가 아닐지 싶네요. 기존에 로깅, 보안, 트랜잭션 등으로 SRP가 위반되기 일수인데.. 그런것들을 한곳에 모아서 단일 책임 원칙을 완성시켜주고, 그렇게 해서, 로깅, 보안, 트랜잭션 로직이 바껴도 본래 핵심 서비스 로직에는 영향을 주지 않도록 해주어, 어느정도 OCP에도 영향을 준다고 생각합니다.

        2. DTO를 사용하니 강한 결합이 발생한다고 하셨는데, 그건 어떻게 바라보느냐의 차이라고 전 생각합니다.

          => 아니옵니다. DTO를 사용해서가 아니라, 계층간에 주고 받는 객체가 데이터 위주의 객체일 경우에 강한 결합이 생긴다는 것입니다. 예를 들어.. 어떤 화면에서 어떤 회원의 정보를 보여주고 있을 때, DAO는 회원의 이름, 이메일을 가져오고, 그걸 DTO에 담던, Map 담아서 서비스로 넘기고 서비스는 할 일이 없으니 그냥 컨트롤러로 넘기죠. 그런데, 이게 요구사항이 바껴서, 이제 화면에서 사용자의 이름, 이메일 뿐 아니라 해당 사용자가 참여하고 있는 그룹 정보까지 출력해야 한다면 어떻게 될까요? DAO가 바뀌겠죠.. 추가적인 정보까지 가져오도록.. 그렇다면 지금 이 구조는 이상적인 계층 구조로 볼 수 있을까요? 저는 아니라고 봅니다. 그리고 왜 이런 이상적이지 못한 계층 구조가 됐을까요? 그건 DAO에서 서비스, 서비스에서 컨트롤러 간에 주고 받는 객체가 데이터를 담고 있는 객체이지 도메인 객체가 아니기 떄문입니다. 그렇다면, 반대로 도메인 객체를 주고 받았다면… Member < --> List 관계가 맺어져 있을테니, 화면에서 추가적으로 Member의 Group 목록 정보를 출력한다고 해서, DAO, Service, Controller를 변경할 필요는 없고, 그저 뷰 단에서 member.groups 를 순회하면 group.name을 출력하면 되겠죠..

          어쿠.. 앞에 몇줄만 읽었을 뿐인데;; 벌써 댓글이 길어지니… 끊어서 달도록 하겠습니다.

          1. 물론, 그럴수 있습니다만. 이 경우엔 Composite VO 를 사용하면 되겠지요. 물론 도메인 객체도 미리 도메인에 대하여 고민을 좀 더 못했다면 도메인도 수정될 수 있지 않을까요?

            Memeber와 그룹의 관계정도는 미리 고민했겠지만. 도메인 모델이 아니더라도 비지니스를 잘 분석했다면 비지니스 객체 자체도 Composite VO를 반환하였을 거란 생각이 들어요.

            그나 저나 이거 쓰레드 너무 길어지는것 아닌가요 😛

          2. 크헉.. 쓰레드가 너무 길어져서 더이상 댓글을 달 수가 없어요;;; 덜덜덜 댓글 스택오버프롤우….

            도메인 객체 자체를 바꿔야 한다면 엄청난 설계의 변경이기 때문에 어쩔 수 없을 것 같습니다. 하지만, 뷰에서 얼마든지 객체 네비게이션으로 보여줄 수 있는 정보가 있는데도, DAO까지 영향을 주게 되는 구조는 좋은 구조는 아니며, 계층형 아키텍처의 근본적인 원리와도 부합하지 않는 결과가 아닐지.. 싶네요. 으하핫 언제 또 치킨 먹으면서 얘기 나눠요~

        3. 그런데 여기서 억울한 일이 벌어집니다. 도메인 객체를 사용하지 않고, DTO를 사용한다고 해서 이것을 데이터 중심의 개발로 보느냐? 이건 아니라는 것입니다.

          => 아.. 이건 아닙니다. 아무래도 글이다 보니 오해가 생길 수 있나본데요.. 음.. 제 생각은 이렇게 나뉘어집니다.

          1. 데이터 중심
          2. 도메인 중심
          2-1. 계층 간에 DTO 사용
          2-2. 계층 간에 도메인 객체 사용

          DTO를 사용한다고 해서 데이터 중심이라는 이야기를 한기억은 없는것 같은데.. 어디선가 꼬였나 보군요. @_@;

Leave a Reply

Your email address will not be published. Required fields are marked *