비즈니스 객체/데이터베이스 액세스 계층을 위한 아키텍처

StackOverflow https://stackoverflow.com/questions/118955

  •  02-07-2019
  •  | 
  •  

문제

여러 가지 이유로 우리는 새로운 비즈니스 객체/데이터 저장 라이브러리를 작성하고 있습니다.이 계층의 요구 사항 중 하나는 비즈니스 규칙의 논리와 실제 데이터 저장 계층을 분리하는 것입니다.

동일한 개체에 대한 액세스를 구현하는 여러 데이터 저장소 계층이 있을 수 있습니다. 예를 들어 대부분의 개체를 구현하는 기본 "데이터베이스" 데이터 저장소 소스와 사용자 개체를 구현하는 또 다른 "ldap" 소스가 있습니다.이 시나리오에서 사용자는 선택적으로 약간 다른 기능(예: 사용자 개체를 저장/업데이트할 수 없음)을 사용하여 LDAP 소스에서 올 수 있지만 그렇지 않으면 응용 프로그램에서 동일한 방식으로 사용됩니다.또 다른 데이터 저장 유형은 웹 서비스 또는 외부 데이터베이스일 수 있습니다.

이를 구현하는 데는 두 가지 주요 방법이 있는데, 저와 동료는 근본적인 수준에서 이것이 올바른지에 대해 의견이 다릅니다.어느 것을 사용하는 것이 가장 좋은지 조언을 듣고 싶습니다.나는 여기서 객관적인 관점을 찾고 있기 때문에 각각에 대한 설명을 가능한 한 중립적으로 유지하려고 노력할 것입니다.

  • 비즈니스 개체는 기본 클래스이며 데이터 저장소 개체는 비즈니스 개체를 상속합니다.클라이언트 코드는 데이터 저장 개체를 처리합니다.

    이 경우 공통 비즈니스 규칙은 각 데이터 저장 객체에 상속되며, 클라이언트 코드에서 직접 사용하는 것은 데이터 저장 객체입니다.

    이는 클라이언트 코드가 해당 개체 유형에 대한 인스턴스를 명시적으로 선언해야 하기 때문에 특정 개체에 사용할 데이터 저장 방법을 결정한다는 의미를 갖습니다.클라이언트 코드는 사용 중인 각 데이터 저장소 유형에 대한 연결 정보를 명시적으로 알아야 합니다.

    데이터 저장 계층이 특정 객체에 대해 다른 기능을 구현하는 경우 클라이언트 코드는 객체가 다르게 보이기 때문에 컴파일 타임에 이에 대해 명시적으로 알게 됩니다.데이터 저장 방식이 변경되면 클라이언트 코드를 업데이트해야 합니다.

  • 비즈니스 개체는 데이터 저장소 개체를 캡슐화합니다.

    이 경우 비즈니스 개체는 클라이언트 응용 프로그램에서 직접 사용됩니다.클라이언트 애플리케이션은 기본 연결 정보를 비즈니스 계층에 전달합니다.주어진 객체가 어떤 데이터 저장 방법을 사용하는지에 대한 결정은 비즈니스 객체 코드에 의해 이루어집니다.연결 정보는 구성 파일에서 가져온 데이터 덩어리(클라이언트 앱은 세부 사항을 실제로 알지 못하거나 신경 쓰지 않음)로, 데이터베이스에 대한 단일 연결 문자열이거나 다양한 데이터 저장소 유형에 대한 여러 조각의 연결 문자열일 수 있습니다.추가 데이터 저장소 연결 유형은 다른 지점(예: 다양한 웹 서비스에 대한 URL을 지정하는 데이터베이스의 구성 테이블)에서 읽을 수도 있습니다.

    여기서의 이점은 새로운 데이터 저장 방법이 기존 객체에 추가되는 경우 런타임에 구성 설정을 설정하여 사용할 방법을 결정할 수 있으며 이는 클라이언트 애플리케이션에 완전히 투명하다는 것입니다.해당 객체의 데이터 저장 방식이 변경되더라도 클라이언트 앱을 수정할 필요가 없습니다.

  • 비즈니스 개체는 기본 클래스이며, 데이터 소스 개체는 비즈니스 개체에서 상속됩니다.클라이언트 코드는 주로 기본 클래스를 다룹니다.

    이는 첫 번째 방법과 유사하지만 클라이언트 코드는 기본 비즈니스 개체 유형의 변수를 선언하고 비즈니스 개체의 Load()/Create()/etc 정적 메서드는 적절한 데이터 소스 유형의 개체를 반환합니다.

    이 솔루션의 아키텍처는 첫 번째 방법과 유사하지만 주요 차이점은 특정 비즈니스 개체에 사용할 데이터 저장소 개체에 대한 결정이 클라이언트 코드가 아닌 비즈니스 계층에서 이루어진다는 것입니다.

이 기능 중 일부를 제공하는 기존 ORM 라이브러리가 이미 있다는 것을 알고 있지만 지금은 해당 라이브러리를 할인해 주시기 바랍니다(데이터 저장 계층이 이러한 ORM 라이브러리 중 하나로 구현될 가능성이 있습니다). 또한 의도적으로 말씀드리지 않는다는 점에 유의하세요. 여기에는 어떤 언어가 사용되는지, 강력하게 입력된 언어는 제외됩니다.

여기서는 어떤 방법을 사용하는 것이 더 나은지(또는 자유롭게 다른 것을 제안할 수 있음), 그리고 그 이유에 대한 몇 가지 일반적인 조언을 찾고 있습니다.

도움이 되었습니까?

해결책

더 나은 분리가 가능한 다른 대안을 제안해도 될까요?비즈니스 객체 사용 데이터 개체 및 데이터 개체 구현하다 저장 객체.이는 비즈니스 객체의 비즈니스 규칙을 유지해야 하지만 스토리지 소스나 형식에 의존하지 않고 데이터 객체가 스토리지 객체를 동적으로 변경하는 것을 포함하여 필요한 모든 조작을 지원할 수 있도록 허용해야 합니다(예:온라인/오프라인 조작용)

이는 위의 두 번째 범주에 속하지만(비즈니스 개체는 데이터 저장소 개체를 캡슐화함) 데이터 의미론을 저장소 메커니즘과 더 명확하게 구분합니다.

다른 팁

고객이 업체에 직접 전화할 수 없도록 외관을 유지할 수도 있습니다.또한 이는 귀하의 비즈니스에 대한 공통 진입점을 만듭니다.

말했듯이 귀하의 비즈니스는 DTO 및 Facade 외에는 어떤 것에도 노출되어서는 안 됩니다.

예.귀하의 클라이언트는 DTO를 처리할 수 있습니다.이는 애플리케이션을 통해 데이터를 전달하는 이상적인 방법입니다.

나는 일반적으로 "비즈니스 개체가 데이터 개체/저장소를 캡슐화합니다"를 가장 선호합니다.그러나 간단히 말해서 가치가 없어 보일 수 있는 데이터 개체와 비즈니스 개체의 높은 중복성을 발견할 수 있습니다.이는 DAL(데이터 액세스 계층)의 기반으로 ORM을 선택한 경우 특히 그렇습니다.그러나 장기적으로 볼 때 실제 보상은 다음과 같습니다.애플리케이션 수명주기.그림과 같이 "데이터"가 하나 이상의 스토리지 하위 시스템(RDBMS에 국한되지 않음)에서 나오는 것은 드문 일이 아니며, 특히 클라우드 컴퓨팅의 출현과 함께 분산 시스템에서 흔히 발생합니다.예를 들어 Restful 서비스에서 가져온 일부 데이터, RDBMS에서 가져온 또 다른 청크 또는 개체, XML 파일, LDAP 등에서 가져온 데이터가 있을 수 있습니다.이러한 인식을 통해 이는 비즈니스의 데이터 액세스를 매우 효과적으로 캡슐화하는 것이 중요함을 의미합니다.c-tors 및 속성을 통해 어떤 종속성을 노출(DI)하는지 주의하세요.

그렇긴 하지만, 제가 고려하고 있는 접근 방식은 아키텍처의 "핵심"을 비즈니스 컨트롤러에 넣는 것입니다.현대의 데이터 액세스를 전통적인 생각보다 리소스로 생각하면 컨트롤러는 비즈니스 개체에 대해 관리해야 하는 데이터 리소스가 무엇인지 파악하는 데 사용할 수 있는 URI 또는 ​​기타 형식의 메타데이터를 받아들입니다.그러면 비즈니스 개체 자체가 데이터 액세스를 캡슐화하지 않습니다.오히려 컨트롤러가 그렇습니다.이를 통해 비즈니스 개체를 가볍고 구체적으로 유지하고 컨트롤러가 최적화, 구성 가능성, 트랜잭션 환경 등을 제공할 수 있습니다.그러면 컨트롤러는 많은 ORM의 컨트롤러 부분과 마찬가지로 비즈니스 개체 컬렉션을 "호스트"합니다.

또한 비즈니스 규칙 관리도 고려하십시오.UML(또는 나처럼 머릿속에 있는 모델 :D)을 자세히 살펴보면 비즈니스 규칙 모델이 실제로는 다른 모델이고 때로는 영구적일 수도 있음을 알 수 있습니다(예를 들어 비즈니스 규칙 엔진을 사용하는 경우). .비즈니스 컨트롤러가 실제로 규칙 하위 시스템도 제어하도록 하고 비즈니스 개체가 컨트롤러를 통해 규칙을 참조하도록 하는 것을 고려해 보겠습니다.그 이유는 규칙 구현에서 타당성을 확인하기 위해 조회 및 교차 확인을 수행해야 하는 경우가 많기 때문입니다.종종 수화된 비즈니스 개체 조회와 백엔드 데이터베이스 조회가 모두 필요할 수 있습니다.예를 들어 "새" 항목만 수화되는 중복 항목을 검색해 보세요.비즈니스 컨트롤러가 규칙을 관리하도록 두면 "도메인 모델"의 깔끔하고 깔끔한 추상화를 희생하지 않고도 필요한 대부분의 작업을 수행할 수 있습니다.

의사 코드에서:

using(MyConcreteBusinessContext ctx = new MyConcreteBusinessContext("datares://model1?DataSource=myserver;Catalog=mydatabase;Trusted_Connection=True ruleres://someruleresource?type=StaticRules&handler=My.Org.Business.Model.RuleManager")) {

User user = ctx.GetUserById("SZE543");
user.IsLogonActive = false;
ctx.Save();
}

//a business object
class User : BusinessBase {
  public User(BusinessContext ctx) : base(ctx) {}

  public bool Validate() {
    IValidator v = ctx.GetValidator(this);
    return v.Validate();
  }
}

// a validator
class UserValidator : BaseValidator, IValidator {
 User userInstance;
 public UserValidator(User user) {
  userInstance = user;
 }

 public bool Validate() {
   // actual validation code here
   return true;
 }
}

클라이언트는 저장소 개체를 직접 처리해서는 안 됩니다.DTO를 직접 처리할 수 있지만 비즈니스 개체에 래핑되지 않은 저장소 논리가 있는 개체는 클라이언트에서 직접 호출하면 안 됩니다.

Rocky Lhotka의 CSLA.net을 확인하세요.

글쎄요, 동료 Greg가 언급한 바로 여기 있습니다.

Greg는 우리가 고려하고 있는 대안을 매우 정확하게 설명했습니다.상황 설명에 몇 가지 추가 고려 사항을 추가하고 싶습니다.

클라이언트 코드는 비즈니스 개체가 저장된 데이터 저장소에 대해 인식하지 못할 수 있지만 데이터 저장소가 하나만 있거나 동일한 비즈니스 개체 유형에 대한 데이터 저장소가 여러 개 있는 경우(로컬 데이터베이스 및 외부 LDAP에 저장된 사용자) 가능합니다. 클라이언트는 이러한 비즈니스 개체를 생성하지 않습니다.시스템 분석 측면에서 이는 동일한 유형의 객체에 대한 두 개의 데이터 저장소가 존재하면 사용 사례 흐름에 영향을 줄 수 있는 사용 사례가 없어야 함을 의미합니다.

서로 다른 데이터 저장소에 생성된 개체를 구별해야 하는 필요성이 발생하자마자 클라이언트 구성 요소는 해당 유니버스에 있는 데이터 저장소의 다양성을 인식해야 하며 개체 생성 순간에 사용할 데이터 저장소를 결정하는 데 필연적으로 책임을 지게 됩니다. (그리고 내 생각에는 데이터 저장소에서 객체를 로드하는 것입니다.)비즈니스 계층은 이러한 결정을 내리는 것처럼 가장할 수 있지만 의사 결정 알고리즘은 클라이언트 구성 요소에서 나오는 정보의 유형과 내용을 기반으로 하여 클라이언트가 결정에 대한 실질적인 책임을 지도록 합니다.

이 책임은 다양한 방법으로 구현될 수 있습니다.각 데이터 저장소에 대한 특정 유형의 연결 개체일 수 있습니다.새로운 BO 인스턴스 등을 생성하기 위해 호출하는 분리된 메소드일 수 있습니다.

문안 인사,

남자 이름

CLSA는 오랜 시간 동안 존재해 왔습니다.그러나 나는 Eric Evans 책에서 논의된 접근 방식을 좋아합니다.http://dddcommunity.org/

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top