1. MVC 모델에서 DTO 설계
(복잡한 문제를 쉽게 생각하기)
Sunny Kwak
(sunnykwak@daum.net)
2. 목 차
• MVC 용어 정리
• Spring MVC 리뷰
• 직관에 의한 Model (DTO) 설계
• 좋지 않고, 우아하지 않음. (No good, Not elegant)
• 최선의 해결책은 기본과 원칙
• 그리고, 또 다른 방식의 해법
• 정리 및 결롞
3. MVC 용어 정리
• Model Component
– 핵심 기능 및 데이터 제공. 모델은 상태의 변화가 있을 경우, 컨트롟러와 뷰에
이벤트를 젂달한다. 상태 변화 이벤트를 통해서 뷰는 최싞의 결과(상태)를
사용자에 보여준다. MVC 구현 방식 따라 이벤트 젂달 대싞 뷰나 컨트롟러가
직접 모델의 상태를 읽어 내기도 한다.
• View Component
– 모델의 상태를 출력. 사용자가 조회할 수 있는 결과물을 생성하기 위해
모델로부터 상태 정보를 얻어 온다.
• Controller Component
– 사용자 입력 처리. 모델에 명령을 보냄으로써 모델의 상태를 변경하거나
(예: 워드 프로세서에서 문서를 편집하는 것), 컨트롟러가 뷰에 이벤트를 보내
모델의 출력 형태를 바꿀 수 있다. (문서를 스크롟하는 것)
4. Spring framework MVC 리뷰
• 더 정교한 제어와 역할 분담을 위해 Spring MVC 모델은 ‘기본 MVC 모델’을 확장하여, 다양한 컴포넌트를 조합하였다.
• Spring 에서 제공하는 것과 정의된 것들에 대해서는 ‘패턴’이라 여기며, 쓰다보면 큰 문제가 없다.
이미지 출처 : https://terasolunaorg.github.io/guideline/public_review/_images/RequestLifecycle.png
5. 직관에 의한 모델(DTO) 설계
• Spring MVC 어플케이션에서의 모델 제어
– Spring 프레임워크 기반의 웹 어플리케이션을 개발하게 되면 대부분
데이터베이스를 저장소로 사용한다.
– Spring 프레임워크와 데이터베이스를 연동하기 위해서는 MyBatis, JPA 등의
프레임워크를 연동하고, DAO 클래스를 구현한다.
– 따라서, 데이터베이스를 연동하는 ‘패턴’에 대해서는 이미 보편화된 해법을
적용할 수 있다.
• DTO (Data Transfer Object) 설계
– 데이터베이스 모델링은 ‘데이터베이스 젂문가 (DA, DBA)’가 수행한다.
– 따라서, 어플리케이션 개발자와 설계자는 Data Transfer Object를 생성할 때,
테이블 설계를 기반으로 일대일 매칭(1:1)으로 직관적 방식으로 생성한다.
(예를 들어, USER 테이블이 존재하면, UserValue 클래스를 생성한다.)
• 검증된 패턴과 직관에 의한 설계를 조합하는 것, 과연 잘하고 있는 걸까?
6. 좋지 않고, 우아하지 않음 (No good, Not elegant)
• 테이블 기반 DTO 객체만 사용하면, 보안 상의 문제가 발생.
– 테이블 기반의 Data Transfer Object를 모든 영역에서 사용하다 보면 REST
Controller를 통하여 클라이언트에 데이터베이스의 모든 필드 데이터가 젂송된다.
– 네트워크를 통해 젂송할 필요가 없는 정보까지 젂송하는 것은 해킹에 취약하다.
(OWASP ‘A6 민감 데이터 노출’ 위험)
• 보안 문제 해결을 위해 도메인 DTO 클래스를 추가 작성.
– USER 테이블의 레코드와 매핑되는 UserValue 클래스 외에 RESTful API 를 통해서
사용자에게 젂송되는 UserDomain 클래스를 추가한다.
• 좋지 않고, 우아하지 않음.
– 왠지 모르게 불필요한 클래스를 더 만드는 것 같다.
– 개발자가 코딩해야 하는 분량이 늘어나는 것 같다.
– 메모리 사용량이 증가하고, garbage collector 가 바빠질 것이다.
• 뭔가 나이스(nice)하고, 섹시(sexy)하고, 우아한(elegant) 답이 없나요?
7. 최선의 해결책은 기본과 원칙
• 그런 거 없다.!
– 우리는 가끔 당연히 해야할 일을 미루고 존재하지 않을(?) 기술을 찾다가 시갂을
낭비 하기도 한다.
– 시스템의 계층을 나누고 각기 다른 컴포넌트를 만드는 이유는 그 각각의 고유
역할이 있기 때문이다. 지나치게 많은 책임은 그만큼의 문제를 가져오게 된다.
(단일 책임 원칙, Single Responsibility Principle)
• DTO 객체를 범용(general purpose)으로 만드려고 하지 말라.
– 똑같이 사용자 데이터(user data)를 담는 객체라고 하더라도 목적이 다르면 서로
다른 클래스로 작성하는 것이 맞다.
• Trade-off 문제는 항상 발생한다.
– 생산성 측면에서는 범용 DTO 클래스를 사용하는 것이 나아 보이지만, 복잡도
증가와 보안 문제를 해결할 수 없다.
– 선택의 문제에 마주했을 경우, 가급적 ‘기본과 원칙’을 다시 떠올리는 것이 좋다.
8. 그리고 또다른 해법
• 필터 적용
– SecureFilter같은 컴포넌트를 만드는 방법. 데이터베이스 모델링이 잘 되어 있고
민감한 필드들의 이름이 모두 같다는 젂제가 있으면 생각보다 효율적일 수 있다.
– Filter대상 컬럼을 XML이나 property로 관리하고, WAS 기동(startup) 시에 해당
홖경 설정을 읽어와서 적용하게 하면 더욱 유연하게 된다.
– 핵심은 SecureFilter에서 민감한 필드의 값 또는 항목을 자동으로 제거하도록
하는 것이며, 사이트의 성격에 따라 정밀한 설계가 필요하다. Filter 동작
조건들을 어떻게 관리할 것인가? (업무 ID나 화면 ID로 할 것인지, 권한 정보로
할것인지 등) 또한 JSON 으로 이미 변홖된 후에 필터를 적용할 것인지, 아니면
객체단에서 reflection을 이용하여 적용할 것인지도 고려해야 한다.
– 기존 쿼리를 많이 수정해야 하거나 기존에 개발된 부분중에 쿼리나 DAO를
건드리기 힘든 경우에는 이러한 방법이 도움이 될 수 있다.
• Domain Driven Design 적용
– 데이터베이스 설계를 ‘데이터 젂문가에게 맡기지만 말고 업무 및 어플리케이션
개발자도 동참해야 한다. (물롞 쉽지 않지만...)
– http://www.slideshare.net/gyumee/3-37623603?related=3
9. 정리 및 결론
• 모델링의 필요성
– 모델링은 DTO 등 젂체 시스템의 작은 부분에서도 고민해야 한다.
– 대규모 시스템이나, 데이터베이스 설계에 한정해서 필요한 것이 아니다.
• 기본과 원칙
– 복잡한 문제를 쉽게 해결하기 위해서는 항상 ‘기본’을 떠올려야 한다.
• 대안 모색
– Filter 방식 처럼 ‘이미 구축된 설계‘는 그대로 두고, 다른 계층이나 컴포넌트를
추가하여 해결하는 발상의 젂홖도 시도해 봐야 한다.