从 DDD 的角度来看,如何处理 DB 特定类型?
From a DDD perspective, how to handle DB specific types?
我正在尝试在我的项目中实施 DDD,并且我正在使用 Firestore 作为我的持久性基础架构。 Go 中的 Firestore 有一些特定的类型,例如 *firestore.DocumentRef
.
我认为我应该把它放在我的 entity 结构中,因为它应该代表我的模型,但我的实体也应该与数据库无关(我认为)。
那么我应该如何从 DDD 的角度来处理这个 entity/struct:
type Holder struct {
SocialReason string `firestore:"social_reason" json:"social_reason"`
Contact value.Contact `firestore:"contact" json:"contact"`
Location value.Location `firestore:"location" json:"location"`
SubmissionDatetime time.Time `firestore:"submission_datetime" json:"-"`
UpdateDatetime time.Time `firestore:"update_datetime" json:"-"`
Status string `firestore:"status" json:"status"`
LastModifier *firestore.DocumentRef `firestore:"last_modifier" json:"-"`
CEP string `firestore:"cep,omitempty" json:"cep,omitempty"`
Country string `firestore:"country" json:"country"`
Region string `firestore:"region,omitempty" json:"region,omitempty"`
City string `firestore:"city,omitempty" json:"city,omitempty"`
}
您应该避免在您的域中出现任何类型的特定于实现的技术选择,除非 - 可能但不太可能 - 它们 确实是 所述无处不在的语言的一部分域(在您的示例中似乎不是这种情况)。
有一个关于使用 Golang 实现 DDD 的很棒的博客系列,随着该系列引入更多与 DDD 相关的概念,附带的代码库也在不断发展。检查 Wild Workouts 示例。
您可以直接从这段代码中学习,因为他们也在他们的 Ports and Adapters 架构中使用 Firebase 作为存储实现之一。他们还有 SQL 和 InMemory(对测试有用)存储实现。
那么,它们如何在存储库实现之外表示 firestore.DocumentRef
?好吧,作为一个简单的string
。例如参见 [=16=] ..
/internal/users/firestore.go
type db struct {
firestoreClient *firestore.Client
}
func (d db) GetUser(ctx context.Context, userID string) (UserModel, error) {
doc, err := d.UserDocumentRef(userID).Get(ctx)
// More stuff to get the user model.
}
重要的是要注意,对于用户管理,他们不使用 DDD,而是使用基本的 CRUD(通过简单的用户管理用例,他们选择放弃 DDD 会引入的额外复杂性)。
Trainer 和 Training 域中有完整的 DDD 设计示例。这里有点复杂(例如处理交易),所以我参考了 The Repository pattern: a painless way to simplify your Go service logic 来解释这些概念。
但是您可以清楚地看到领域概念(存储库接口)和实现(存储库适配器)之间的划分方式。例如在培训领域,实施 Hour
:
我正在尝试在我的项目中实施 DDD,并且我正在使用 Firestore 作为我的持久性基础架构。 Go 中的 Firestore 有一些特定的类型,例如 *firestore.DocumentRef
.
我认为我应该把它放在我的 entity 结构中,因为它应该代表我的模型,但我的实体也应该与数据库无关(我认为)。
那么我应该如何从 DDD 的角度来处理这个 entity/struct:
type Holder struct {
SocialReason string `firestore:"social_reason" json:"social_reason"`
Contact value.Contact `firestore:"contact" json:"contact"`
Location value.Location `firestore:"location" json:"location"`
SubmissionDatetime time.Time `firestore:"submission_datetime" json:"-"`
UpdateDatetime time.Time `firestore:"update_datetime" json:"-"`
Status string `firestore:"status" json:"status"`
LastModifier *firestore.DocumentRef `firestore:"last_modifier" json:"-"`
CEP string `firestore:"cep,omitempty" json:"cep,omitempty"`
Country string `firestore:"country" json:"country"`
Region string `firestore:"region,omitempty" json:"region,omitempty"`
City string `firestore:"city,omitempty" json:"city,omitempty"`
}
您应该避免在您的域中出现任何类型的特定于实现的技术选择,除非 - 可能但不太可能 - 它们 确实是 所述无处不在的语言的一部分域(在您的示例中似乎不是这种情况)。
有一个关于使用 Golang 实现 DDD 的很棒的博客系列,随着该系列引入更多与 DDD 相关的概念,附带的代码库也在不断发展。检查 Wild Workouts 示例。
您可以直接从这段代码中学习,因为他们也在他们的 Ports and Adapters 架构中使用 Firebase 作为存储实现之一。他们还有 SQL 和 InMemory(对测试有用)存储实现。
那么,它们如何在存储库实现之外表示 firestore.DocumentRef
?好吧,作为一个简单的string
。例如参见 [=16=] ..
/internal/users/firestore.go
type db struct {
firestoreClient *firestore.Client
}
func (d db) GetUser(ctx context.Context, userID string) (UserModel, error) {
doc, err := d.UserDocumentRef(userID).Get(ctx)
// More stuff to get the user model.
}
重要的是要注意,对于用户管理,他们不使用 DDD,而是使用基本的 CRUD(通过简单的用户管理用例,他们选择放弃 DDD 会引入的额外复杂性)。
Trainer 和 Training 域中有完整的 DDD 设计示例。这里有点复杂(例如处理交易),所以我参考了 The Repository pattern: a painless way to simplify your Go service logic 来解释这些概念。
但是您可以清楚地看到领域概念(存储库接口)和实现(存储库适配器)之间的划分方式。例如在培训领域,实施 Hour
: