ORM을 통해 리치 도메인 모델을 만들 수 있습니까?


21

약 8 년 동안 대부분의 프로젝트에서 Hibernate를 사용한 후, 나는 사용을 권장하지 않고 저장 프로 시저를 통해서만 응용 프로그램이 DB와 ​​상호 작용하기를 원하는 회사에 착륙했습니다.

몇 주 동안이 작업을 수행 한 후, 구축하려는 애플리케이션의 리치 도메인 모델을 만들 수 없었으며 애플리케이션은 (끔찍한) 트랜잭션 스크립트처럼 보입니다.

내가 찾은 문제 중 일부는 다음과 같습니다.

  • 저장 프로 시저가 단지 최소량의 데이터를로드하기 때문에 객체 그래프를 탐색 할 수 없습니다. 이는 때때로 다른 필드를 가진 유사한 객체가 있음을 의미합니다. 예를 들면 다음과 같습니다. 고객으로부터 모든 데이터를 검색하는 저장 프로 시저와 고객으로부터 계정 정보와 몇 가지 필드를 검색하는 저장 프로 시저가 있습니다.
  • 많은 논리가 도우미 클래스로 끝나므로 코드가 더 체계화됩니다 (오래된 C 구조체로 사용되는 엔터티 사용).
  • 저장 프로 시저에서 결과 집합을 추출하여 엔터티에 넣는 프레임 워크가 없으므로 더 지루한 스캐 폴딩 코드입니다.

내 질문은 :

  • 비슷한 상황에 처한 사람이 있고 저장 프로 시저 접근 방식에 동의하지 않았습니까? 뭐 했어?
  • 저장 프로 시저를 사용하면 실제로 이점이 있습니까? "아무도 드롭 테이블을 발행 할 수 없습니다"라는 어리석은 점을 제외하면
  • 저장 프로 시저를 사용하여 리치 도메인을 만드는 방법이 있습니까? 개체 그래프를 탐색 할 수 있도록 AOP를 사용하여 DAO / 리포지토리를 엔터티에 주입 할 가능성이 있음을 알고 있습니다. 부두와 매우 가까워서이 옵션이 마음에 들지 않습니다.

결론

먼저 답변을 주셔서 감사합니다. 내가 도착한 결론은 ORM이 (리치 도메인 모델)을 만들 수는 없지만 (일부 사람들이 언급 한 것처럼) 반복되는 작업량을 단순화한다는 것입니다. 다음은 결론에 대한 자세한 설명이지만 하드 데이터를 기반으로하지는 않습니다.

대부분의 응용 프로그램은 다른 시스템에 정보를 요청하고 보냅니다. 이를 위해 모델 용어 (예 : 비즈니스 이벤트)로 추상화를 작성하고 도메인 모델은 이벤트를 보내거나받습니다. 이벤트에는 일반적으로 모델의 정보 중 일부만 필요하지만 전체 모델은 아닙니다. 예를 들어 온라인 상점에서 지불 게이트웨이는 일부 사용자 정보 및 총계를 요청하여 사용자에게 청구하지만 구매 내역, 사용 가능한 제품 및 모든 고객 기반을 요구하지는 않습니다. 따라서 이벤트에는 작고 구체적인 데이터 세트가 있습니다.

응용 프로그램의 데이터베이스를 외부 시스템으로 사용하는 경우 도메인 모델 엔터티를 데이터베이스에 매핑 할 수있는 추상화를 만들어야합니다 ( NimChimpsky가 언급 한 것처럼 데이터 매퍼 사용). 명백한 차이점은 이제 각 모델 엔터티에 대한 데이터베이스 (레거시 스키마 또는 저장 프로 시저)에 대한 매핑을 수작업으로 만들어야한다는 것입니다. 두 개가 동기화되지 않기 때문에 하나의 도메인 엔터티가 부분적으로 매핑 될 수 있습니다. 데이터베이스 엔터티 (예 : 사용자 이름과 암호 만 포함하는 UserCredentials 클래스가 다른 열이있는 Users 테이블에 매핑 됨)에 연결되거나 하나의 도메인 모델 엔터티가 둘 이상의 데이터베이스 엔터티에 매핑 될 수 있습니다 (예 : 테이블에 하나의 매핑이 있지만 모든 데이터는 하나의 클래스에 있어야합니다.

엔터티가 적은 응용 프로그램에서는 엔터티를 가로 질러야 할 필요가없는 경우 추가 작업의 양이 적을 수 있지만 엔터티를 가로 질러야하는 조건부 필요가있을 때 증가합니다. 적재 '). 응용 프로그램이 더 많은 엔터티를 갖도록 증가함에 따라이 작업은 증가합니다 (비선형으로 증가하는 느낌이 있습니다). 여기서 내 가정은 ORM을 재발 명하려고 시도하지 않는다는 것입니다.

DB를 외부 시스템으로 취급 할 때 얻을 수있는 이점 중 하나는 응용 프로그램마다 서로 다른 매핑이있는 두 가지 버전의 응용 프로그램을 실행하려는 상황을 코딩 할 수 있다는 것입니다. 이것은 생산으로의 지속적인 납품 시나리오에서 더욱 흥미로워집니다. 그러나 이것은 ORM을 통해 가능할 수도 있습니다.

개발자가 데이터베이스에 액세스 할 수없는 경우에도 악의적 인 코드를 삽입하여 시스템에 저장된 모든 정보를 얻을 수는 없지만 대부분의 경우 보안 측면을 무시합니다. 친애하는 주님, 고객의 신용 카드 정보를 기록하는 행을 제거하는 것을 잊어 버렸습니다 .)


작은 업데이트 (2012 년 6 월 6 일)

스토어드 프로 시저 (적어도 Oracle에서)는 테이블 구조를 변경하면 프로 시저 및 트리거가 무효화되므로 가동 중지 시간없이 지속적인 전달을 수행하지 않습니다. 따라서 DB가 업데이트되는 동안 응용 프로그램도 다운됩니다. 오라클은이를 위해 Edition-Based Redefinition 이라는 솔루션 을 제공 하지만,이 기능에 대해 물어 본 소수의 DBA는 제대로 구현되지 않았으며 프로덕션 DB에 넣지 않을 것이라고 언급했습니다.


글쎄, 분명히 당신 Hibernate가하는 일을하고 동적 프록시 객체를 생성하기 위해 상속을 사용하여 객체 그래프를 검색 할 수있다. SP와 함께 그것은 매우 해킹입니다. : D
Max

그래서 나는 최대 절전 모드 팀이 가지고있는 10 년 이상의 경험없이 최대 절전 모드의 절반을 다시 끝낼 것입니다 :).
Augusto

1
모든 DBA는 특정 사용자가 특정 테이블을 삭제하지 못하도록해야합니다. 당신이 그것을 시도하는 방법은 중요하지 않습니다.
JeffO

1
Mybatis를 살펴보십시오 . 필요한 기능을 제공 할 수 있습니다. 매핑 프레임 워크보다 ORM이 적습니다. 그러나 원하는대로 SQL을 작성하고 Mybatis에 객체 모델에 배치 할 위치를 알려줄 수 있습니다. 여러 쿼리를 사용하여 큰 객체 그래프를 처리하므로 현재 상황 (많은 얇은 저장 프로 시저)처럼 들립니다.
Michael K

1
@ 오거스 토 : 나는 SP를 사용하는 것이 아니라 객체 관계를 지원하지 않는 독점 매핑 프레임 워크를 사용했기 때문에 비슷한 상황에 처해 있습니다. 적절한 ORM을 사용하여 몇 분 안에 작성할 수있는 코드를 작성하는 데 며칠이 걸렸습니다. 나는 그 문제를 해결하지 못했습니다.
케빈 클라인

답변:


16

응용 프로그램은 여전히 ​​도메인 기반 설계 원칙에서 모델링되어야합니다. SP를 호출하는 ORM, 직선 JDBC를 사용하든 상관없이 상관 없습니다 . SP에서 모델을 추상화하는 얇은 레이어 가이 경우 트릭을 수행하기를 바랍니다. 마찬가지로 다른 포스터가 언급 한 , 당신은의 SP 및 서비스로 결과를 확인하고 도메인 모델에 결과를 매핑해야합니다.


Martijn, 나는 DDD 원칙을 사용하여 앱을 모델링해야한다는 데 동의하지만, 내가 직면하고있는 문제 (그리고 해결책이 있는지 알려주세요 !!)는 일부 저장된 procs가 DDD 엔터티를 인스턴스화하는 데 거의 정보를 반환하지 않는다는 것입니다. 저장 프로 시저가 반환하는 정보에 대해 조금 더 설명한 이 의견을 참조하십시오 . 저장 프로 시저를 두 개 이상 호출하고 모든 사용자 세부 정보를 검색 한 다음 다른 계정 정보를 검색하여 모든 계정 정보를 검색하여이를 우회 할 수는 있지만 잘못 느낍니다. :).
Augusto

1
@Augusto 음 ... 당신은 응용 프로그램 개발자이므로 특정 필드가 NULL로 설정된 특정 객체가 존재하는지 여부를 결정해야합니다. 이해가된다면 (예를 들어 특정 작업) 그렇게하십시오. 그렇지 않은 경우 SP 작성자에게 더 많은 데이터를 제공하도록 요청하여 개체를 만들 수 있습니다.
Jacek Prucia

Jacek의 의견에 덧붙여 실제로 2 + 저장된 procs를 호출하는 것은 완벽하게 수용 가능합니다. 다시 도메인 모델을 만들기 위해 호출 해야하는 두 개의 원격 서비스로 생각하십시오.
Martijn Verburg

@Martijn : 내 경험상 얇은 층으로는 충분하지 않습니다. 맵핑 코드는 기본 비즈니스 로직보다 상당히 길 수 있습니다.
kevin cline

@ 케빈 클라인-좋은 지적, 대답에 '희망적으로'넣었습니다 :-)
Martijn Verburg

5

저장 프로 시저를 사용하면 실제로 이점이 있습니까?

금융 세계 (및 Sarbanes-Oxley 준수가 필요한 장소 )에서는 시스템이 감사해야 할 작업을 수행하도록 시스템을 감사 할 수 있어야합니다. 이 경우 모든 데이터 액세스가 저장 프로 시저를 통해 수행 될 때 규정 준수가 훨씬 쉬워집니다. 또한 임시 SQL을 모두 제거하면 숨기는 것이 훨씬 어렵습니다. 이것이 "좋은 것"인 이유의 예를 위해, 나는 Ken Thompson의 고전적인 논문 인 Trusting Trust에 대한 Reflections를 참조합니다 .


예 백만 번 예! 또한 테이블에 대한 직접적인 권한이없고 저장된 procs의 도움을 포함하여 사용자가하지 말아야 할 일을 사용자가 할 수 없도록해야합니다.
HLGEM

1
나는 공공 회사에서 일하고 우리는 SOX sompliant입니다. 감사에 대한 지식이 부족할 수 있지만 DB 수준에서 (저장된 procs를 통해) 또는 응용 프로그램 수준에서 감사를 수행하는 것의 차이점은 보이지 않습니다. 각 애플리케이션에는 고유 한 DB 스키마가 있어야하며 해당 스키마는 다른 애플리케이션간에 공유되지 않고 애플리케이션에서만 액세스 할 수 있습니다.
Augusto

끊어진 링크 ...
Alex R

@AlexR, 고정 링크
Tangurena

2

저장 프로시 저는 클라이언트 쪽 SQL 코드보다 훨씬 효율적입니다. 이들은 DB에서 SQL을 사전 컴파일하여 일부 최적화를 수행 할 수도 있습니다.

구조적으로 SP는 작업에 필요한 최소 데이터를 반환합니다. 이는 데이터 전송이 적다는 것을 의미하기 때문에 좋습니다. 이러한 아키텍처가 있다면 DB를 서비스로 생각해야합니다 (웹 서비스라고 생각하면 각 SP는 호출하는 방법입니다). ORM은 원격 데이터를 마치 로컬 인 것처럼 작업하도록 안내하므로주의를 기울이지 않으면 성능 문제가 발생할 수 있습니다.

SP를 완전히 사용한 상황에서 DB가 데이터 API를 제공하고 사용했습니다. 그 특정 응용 프로그램은 매우 큰 규모였으며 놀랍도록 잘 수행되었습니다. 그 후 SP에 대해 나쁜 말을하지 않을 것입니다!

또 다른 장점이 있습니다. DBA는 모든 SQL 쿼리를 작성하고 DB의 모든 관계형 계층 구조를 행복하게 처리하므로 필요하지 않습니다.


3
gbjbaanb, 대부분의 말은 오래된 데이터베이스에 해당됩니다. 대부분의 최신 데이터베이스는 쿼리를 재 컴파일하여 사용할 새 최적화 (저장된 프로덕션에 있더라도)를 결정합니다. DB를 외부 시스템으로 사용하는 것에 대해 말한 것에 동의하지만 응용 프로그램이 데이터베이스를 소유하고 가능한 한 동기화되어야하기 때문에 많은 작업이 필요합니다. 예를 들어 테이블 / 클래스 및 필드 / 열의 이름을 지정합니다. 또한 DBA가 절차를 작성하게하는 접근 방식은 여러 분야의 팀을 구성하는 것이 아니라 개발 사일로와 비슷합니다.
Augusto

7
SP가 항상 더 효율적일 필요는 없으며 SQL을 DBA에 전달하는 것이 좋지 않은 방법이라고 생각합니다. 도메인 전문가로서 개발자는 원하는 데이터와 데이터를 얻는 방법을 알아야합니다.
Martijn Verburg

1
이것은 좋은 대답이지만 필자의 경험에 따르면 대부분의 고객은 실제로 응용 프로그램 계층에서 ORM 도구를 완전히 사용하는 불편 함보다는 저장 프로 시저를 통해 데이터 액세스를 제어하기위한 성능 향상이 필요하지 않습니다. 다른 기술이없는 "회색 수염" 저장 프로 시저 프로그래머 의 부풀린 급여를 정당화 할 필요가있는 소프트웨어 상점에서 이루어진 이러한 아키텍처 결정을 더 자주 볼 수 있습니다.
maple_shaft

1
@Augusto the approach of letting the DBAs write the procedures smells like development silos+ 100의 인터넷이 당신에게 진실의 보석을 제공합니다. 나는 이것을 항상 저장 프로 시저를 통해 데이터 액세스가 제어되는 경우로 보았다.
maple_shaft

1
@maple_shaft : SP를 작성하는 DBA가 개발자 팀의 일부로 간주되지 않는 이유는 무엇입니까? 그것이 작동하는 곳에서 그들은 시스템의 이러한 측면을 실제로 잘 아는 전문 코더이며 대부분의 범용 개발자보다 훨씬 좋습니다. 이것은 ORM의 인기를 높이는 문제 일 수 있습니다. 내 말은, 아무도 디자이너가 GUI를 수행하는 것에 대해 두 번 생각하지 않을 것입니다. 왜 데이터 설계자가 스키마를 싫어하는가?
gbjbaanb

2

개발자가 ORM 객체를 도메인 모델로 잘못 사용하는 경우가 종종 발생합니다.

이것은 올바르지 않으며 도메인을 DB 스키마에 직접 연결합니다.

실제로 필요한 것은 ORM 계층을 원하는만큼 풍부하고 별도로 사용하는 별도의 도메인 모델입니다.

즉, 각 개체 집합간에 매핑이 필요합니다.


1
이것은 좋은 생각이지만 소규모 프로젝트의 경우 실제로 과도한 것으로 느껴지기 시작합니다. 이 방법에는 ORM 지속성 계층과 도메인 모델 간의 변환 계층도 필요합니다.
maple_shaft

@maple_shaft는 동의했고 그것이 "매핑"의 의미입니다 :-)
ozz

@Ozz, 내가 일한 방식은 정확히 엔티티 클래스가 도메인 모델이라는 것입니다 (그리고 나는 많은 성공을 거둘 수 있습니다). 도메인 모델을 스키마에 연결한다는 데 동의하지만 구성에 대한 규칙을 사용하기 때문에 정확히 내가 원하는 것입니다. 엔티티에서 필드를 볼 때 열심히 생각할 필요가 없다는 부작용이 있습니다. 정보가 저장된 테이블 및 열 이름
Augusto

@Augusto 나도 해냈어! maple_shaft가 말했듯이 작은 CRUD 스타일 앱에는 적합하지만 OP가 발견하는 동안 많은 문제가 있습니다. 예를 들어, 다수에서 다수의 매핑 테이블이있는 경우를 예로들 수 있습니다. StudentClasses, 학생을 클래스에 매핑하고 StudentID 및 classID 만 포함하는 경우 도메인에 반드시 매핑하지 않아도됩니다. 그것은 내 머리의 예에서 빠른 것입니다.
ozz

2
@Ozz : 귀하의 의견은 ORM의 아이디어와 모순되는 것 같습니다. ORM은 "도메인 을 DB 스키마에 직접 연결"하지 않습니다 . ORM 은 별도의 DAO 계층 없이도 도메인을 DB 스키마에 매핑 합니다. 이것이 ORM의 요점입니다. 그리고 대부분의 ORM은 다 대다 매핑을 잘 처리하며 매핑 테이블에 도메인 모델이 필요하지 않습니다.
케빈 클라인

1

도메인 개체를 채울 수 있지만 원하는 경우 최대 절전 모드를 사용하지 않아도됩니다. 적절한 용어는 data-mapper 라고 생각합니다 . 지속 된 데이터가 도메인 개체와 완전히 다른 구조 일 수 있습니다.


현재 데이터 매퍼를 사용하고 있지만 문제는 저장된 proc가 최소한의 데이터 집합을 반환한다는 것인데, 때로는 개체를 채우기에 충분하지 않습니다 (저장 프로 시저가 더 많은 정보를 반환하도록 허용해야 함). 예를 들어, 한 상점 프로 시저가 사용자 이메일, 이름, 성을 리턴 할 수 있습니다. 다른 하나는 사용자 ID와 주소를 추가합니다. 데이터가 다르기 때문에 서로 다른 객체를 사용하여 데이터를 저장하고 있습니다. 즉, 'User'클래스가 다릅니다. 상속을 잘못 사용하고 있다고 생각하기 때문에 상속을 피하려고합니다.
Augusto

@Augusto : 인터페이스?
Kramii Reinstate Monica

@Karmii, 다른 클래스의 논리를 복제해야하기 때문에 인터페이스가 여기에 도움이되지 않는다고 생각합니다. 또는 인터페이스를 사용하여 처리를 도우미 클래스에 위임 할 수 있지만 실제로는 OO가 아닙니다. (.
Augusto

1
@Augusto 나는 문제를 이해하지 못한다 : "저장된 procs는 때때로 객체를 채우기에 충분하지 않은 최소한의 데이터 세트를 반환한다."따라서 sproc를 변경하거나 다른 것을 생성 한 다음 데이터 매퍼가 매핑을 수행하게한다
NimChimpsky
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.