Patterns, Principles, and Practices of Domain-Driven Design - Scott Millett - E-Book

Patterns, Principles, and Practices of Domain-Driven Design E-Book

Scott Millett

0,0
38,99 €

Beschreibung

Methods for managing complex software construction following the practices, principles and patterns of Domain-Driven Design with code examples in C# This book presents the philosophy of Domain-Driven Design (DDD) in a down-to-earth and practical manner for experienced developers building applications for complex domains. A focus is placed on the principles and practices of decomposing a complex problem space as well as the implementation patterns and best practices for shaping a maintainable solution space. You will learn how to build effective domain models through the use of tactical patterns and how to retain their integrity by applying the strategic patterns of DDD. Full end-to-end coding examples demonstrate techniques for integrating a decomposed and distributed solution space while coding best practices and patterns advise you on how to architect applications for maintenance and scale. * Offers a thorough introduction to the philosophy of DDD for professional developers * Includes masses of code and examples of concept in action that other books have only covered theoretically * Covers the patterns of CQRS, Messaging, REST, Event Sourcing and Event-Driven Architectures * Also ideal for Java developers who want to better understand the implementation of DDD

Sie lesen das E-Book in den Legimi-Apps auf:

Android
iOS
von Legimi
zertifizierten E-Readern

Seitenzahl: 976

Bewertungen
0,0
0
0
0
0
0



CONTENTS

Introduction

Overview of the Book and Technology

How This Book Is Organized

Who Should Read This Book

Source Code

Errata

p2p.wrox.com

Summary

Part I: The Principles and Practices of Domain-Driven Design

Chapter 1: What Is Domain-Driven Design?

The Challenges of Creating Software for Complex Problem Domains

How the Patterns of Domain-Driven Design Manage Complexity

The Practices and Principles of Domain-Driven Design

Popular Misconceptions of Domain-Driven Design

The Salient Points

Chapter 2: Distilling the Problem Domain

Knowledge Crunching and Collaboration

Gaining Domain Insight with Domain Experts

Patterns for Effective Knowledge Crunching

Look For Existing Models

The Salient Points

Chapter 3: Focusing on the Core Domain

Why Decompose a Problem Domain?

How to Capture the Essence of the Problem

How to Focus on the Core Problem

How Subdomains Shape a Solution

Not All Parts of a System Will Be Well Designed

What If You Have No Core Domain?

The Salient Points

Chapter 4: Model-Driven Design

What Is a Domain Model?

Model-Driven Design

Using a Ubiquitous Language to Bind the Analysis to the Code Model

Collaborating on a Ubiquitous Language

How to Create Effective Domain Models

When to Apply Model-Driven Design

The Salient Points

Chapter 5: Domain Model Implementation Patterns

The Domain Layer

Domain Model Implementation Patterns

The Salient Points

Chapter 6: Maintaining the Integrity of Domain Models with Bounded Contexts

The Challenges of a Single Model

Use Bounded Contexts to Divide and Conquer a Large Model

Implementing Bounded Contexts

The Salient Points

Chapter 7: Context Mapping

A Reality Map

Recognising the Relationships between Bounded Contexts

Communicating the Context Map

The Strategic Importance of Context Maps

The Salient Points

Chapter 8: Application Architecture

Application Architecture

Application Services

Application Clients

The Salient Points

Chapter 9: Common Problems for Teams Starting Out with Domain-Driven Design

Overemphasizing the Importance of Tactical Patterns

Missing the Real Value of DDD: Collaboration, Communication, and Context

Spending Too Much Time on What’s Not Important

Making Simple Problems Complex

Underestimating the Cost of Applying DDD

The Salient Points

Chapter 10: Applying the Principles, Practices, and Patterns of DDD

Selling DDD

Applying the Principles of DDD

Exploration and Experimentation

Making the Implicit Explicit

A Problem Solver First, A Technologist Second

How Do I Know That I Am Doing It Right?

The Salient Points

Part II: Strategic Patterns: Communicating Between Bounded Contexts

Chapter 11: Introduction to Bounded Context Integration

How to Integrate Bounded Contexts

Integrating Distributed Bounded Contexts

The Challenges of DDD with Distributed Systems

SOA and Reactive DDD

The Salient Points

Chapter 12: Integrating via Messaging

Messaging Fundamentals

Building an E-Commerce Application with NServiceBus

Maintaining a Messaging Application

Integrating a Bounded Context with Mass Transit

The Salient Points

Chapter 13: Integrating via HTTP with RPC and REST

Why Prefer HTTP?

RPC

REST

The Salient Points

Part III: Tactical Patterns: Creating Effective Domain Models

Chapter 14: Introducing the Domain Modeling Building Blocks

Tactical Patterns

Patterns to Model Your Domain

LifeCycle Patterns

Emerging Patterns

The Salient Points

Chapter 15: Value Objects

When to Use a Value Object

Defining Characteristics

Common Modeling Patterns

Persistence

The Salient Points

Chapter 16: Entities

Understanding Entities

Implementing Entities

Common Entity Modeling Principles and Patterns

The Salient Points

Chapter 17: Domain Services

Understanding Domain Services

Utilizing Domain Services

The Salient Points

Chapter 18: Domain Events

Essence of the Domain Events Pattern

Event Handling Actions

Domain Events’ Implementation Patterns

Testing Domain Events

The Salient Points

Chapter 19: Aggregates

Managing Complex Object Graphs

Aggregates

Defining Aggregate Boundaries

Implementing Aggregates

The Salient Points

Chapter 20: Factories

The Role of a Factory

The Salient Points

Chapter 21: Repositories

Repositories

A Misunderstood Pattern

Aggregate Persistence Strategies

A Repository Is an Explicit Contract

Transaction Management and Units of Work

To Save or Not To Save

The Repository as an Anticorruption Layer

Other Responsibilities of a Repository

Repository Antipatterns

Repository Implementations

The Salient Points

Chapter 22: Event Sourcing

The Limitations of Storing State as a Snapshot

Gaining Competitive Advantage by Storing State as a Stream of Events

Event-Sourced Aggregates

Building an Event Store

Using the Purpose-Built Event Store

CQRS with Event Sourcing

Recapping the Benefits of Event Sourcing

Weighing the Costs of Event Sourcing

Additional Learning Resources

The Salient Points

Part IV: Design Patterns for Effective Applications

Chapter 23: Architecting Application User Interfaces

Design Considerations

Example 1: An HTML API-Based, Server-Side UI for Nondistributed Bounded Contexts

Example 2: A Data API-Based, Client-Side UI for Distributed Bounded Contexts

The Salient Points

Chapter 24: CQRS: An Architecture of a Bounded Context

The Challenges of Maintaining a Single Model for Two Contexts

A Better Architecture for Complex Bounded Contexts

The Command Side: Business Tasks

The Query Side: Domain Reporting

The Misconceptions of CQRS

Patterns to Enable Your Application to Scale

The Salient Points

Chapter 25: Commands: Application Service Patterns for Processing Business Use Cases

Differentiating Application Logic and Domain Logic

Application Service Patterns

Testing Application Services

The Salient Points

Chapter 26: Queries: Domain Reporting

Domain Reporting Within a Bounded Context

Domain Reporting Across Bounded Contexts

The Salient Points

Title Page

Copyright

Dedication

About the Author

Credits

Acknowledgments

Advert

EULA

List of Tables

Chapter 13

Table 13.1

Table 13.2

Chapter 22

Table 22.1

Table 22.2

Chapter 26

Table 26.1

Table 26.2

Table 26.3

List of Illustrations

Introduction

Figure I.1 A blueprint of the problem space of DDD.

Figure I.2 A blueprint of the solution space of Domain-Driven Design.

Chapter 1

Figure 1.1 Complexity in software.

Figure 1.2 Code rot.

Figure 1.3 Applying the strategic patterns of Domain-Driven Design.

Figure 1.4 DDD patterns that are applicable to the problem space.

Figure 1.5 DDD patterns that are applicable to the solution space.

Chapter 2

Figure 2.1 Knowledge crunching.

Figure 2.2 The roles of stakeholders, domain experts, and the development team.

Figure 2.3 An impact map.

Figure 2.4 A Business Model Canvas.

Chapter 3

Figure 3.1 Cuts of a pig.

Figure 3.2 The domain of an online auction site.

Figure 3.3 The domain of an online auction site distilled into subdomains.

Figure 3.4 The distilled domain of an online auction site partitioned into core, generic, and supporting domains.

Figure 3.5 How a solution maps to the subdomains of the auction system.

Figure 3.6 Dealing with legacy.

Chapter 4

Figure 4.1 The role of a domain model.

Figure 4.2 The domain versus the domain model.

Figure 4.3 The binding between the code and analysis model.

Figure 4.4 The problems with upfront design.

Figure 4.5 The code model and the analysis model are kept in synergy.

Figure 4.6 Team modeling.

Figure 4.7 Translation costs of the project.

Figure 4.8 London Tube map bearing little resemblance to the distance between stations.

Chapter 5

Figure 5.1 The code that represents the domain model makes up only a small portion of the overall codebase.

Figure 5.2 Multiple domain models implemented in various patterns inside an application.

Figure 5.3 The domain model pattern.

Figure 5.4 The domain model of an auction site.

Figure 5.5 The transaction script pattern.

Figure 5.6 The transaction script pattern UML.

Chapter 6

Figure 6.1 A model will grow in complexity.

Figure 6.2 Complexity in a model increases with multiple teams.

Figure 6.3 Domain terms mean different things in different contexts.

Figure 6.4 The same concept should be understood within different contexts.

Figure 6.5 A single view of an entity in the domain for all subdomains can quickly become a problem.

Figure 6.6 The product, an implementation of the god object antipattern.

Figure 6.7 The difference between an enterprise model and a domain model.

Figure 6.8 Putting terms into context and identifying multiple models.

Figure 6.9 Define each model within its own context.

Figure 6.10 A layered architecture pattern per bounded context and not per application.

Figure 6.11 The Product class in different contexts.

Figure 6.12 You can apply different architectural patterns to the different bounded contexts.

Figure 6.13 The anatomy of a bounded context.

Chapter 7

Figure 7.1 A context map.

Figure 7.2 The technical integration on a context map.

Figure 7.3 The organizational relationships on a context map.

Figure 7.4 Use an anticorruption layer to integrate with code you don’t own or can’t change.

Figure 7.5 Integration with a shared kernel.

Figure 7.6 Multiple subsystems integrating with similar transformation efforts.

Figure 7.7 Integration with an open host service.

Figure 7.8 A customer-supplier relationship between bounded contexts.

Figure 7.9 A context map showing the types of integration between bounded contexts.

Chapter 8

Figure 8.1 A layered architecture.

Figure 8.2 Dependency inversion within a layered architecture.

Figure 8.3 Domain objects are hidden from clients of the application.

Figure 8.4 Testing layers in isolation.

Figure 8.5 Bounded contexts integrating via a shared data schema.

Figure 8.6 Bounded contexts with their own data schema.

Figure 8.7 Bounded contexts integrating via a separate application layer.

Figure 8.8 Presentation layer composed of bounded contexts.

Figure 8.9 Application logic versus domain logic.

Figure 8.10 A view model mapping to many domain objects.

Figure 8.11 View models queried directly from the data source.

Figure 8.12 View store separated from transactional storage.

Figure 8.13 :Various clients of an application.

Figure 8.14 A system composed of multiple bounded contexts.

Figure 8.15 A process manager.

Chapter 10

Figure 10.1 The process of DDD.

Chapter 11

Figure 11.1 Multiple bounded contexts inside a single solution.

Figure 11.2 Multiple bounded contexts using a shared schema.

Figure 11.3 Autonomous bounded contexts with a shared-nothing architecture.

Figure 11.4 A bubble context.

Figure 11.5 An autonomous bubble context.

Figure 11.6 Exposing a legacy context as a JSON web service.

Figure 11.7 Database integration.

Figure 11.8 Flat file integration.

Figure 11.9 E-commerce system using synchronous RPC.

Figure 11.10 Replacing RPC with reactive.

Figure 11.11 Decomposing the shipping bounded context into business components.

Figure 11.12 Shipping bounded context broken down into business components and components.

Figure 11.13 Possible deployment view of components in the Shipping bounded context.

Figure 11.14 Sharing dependencies is only allowed between components inside the same business component.

Chapter 12

Figure 12.1 Message bus architecture.

Figure 12.2 Adding new event subscribers doesn’t affect existing code.

Figure 12.3 A component diagram showing domain events.

Figure 12.4 A containers diagram for a typical e-commerce application.

Figure 12.5 The basic web page for placing an order.

Figure 12.6 Creating an empty Visual Studio solution.

Figure 12.7 Adding the DDDesign.Web MVC 4 web application.

Figure 12.8 Selecting empty ASP.NET MVC template with the Razor view engine.

Figure 12.9 Adding a reference to the Sales.Messages project from the DDDesign.Web project.

Figure 12.10 Installing NServiceBus with the NuGet package manager console.

Figure 12.11 Adding the Orders controller.

Figure 12.12 Solution structure after adding Orders controller and view.

Figure 12.13 Selecting solution properties.

Figure 12.14 Configuring each project to start up.

Figure 12.15 An NServiceBus server setting up an application.

Figure 12.16 Adding the OrderCreated event to the Sales.Messages project.

Figure 12.17 Adding the two messages to the Billing.Messages project.

Figure 12.18 Setting all your NServiceBus servers to start up.

Figure 12.19 Looks like the payment was processed successfully.

Figure 12.20 Actually, the payment failed twice first.

Figure 12.21 The payment rejected use case.

Figure 12.22 Multiple bounded contexts store the same piece of data locally.

Figure 12.23 Shipping bounded context storing data locally and using it to arrange shipping.

Figure 12.24 Business components have their own APIs.

Figure 12.25 Pages get their data from multiple APIs.

Figure 12.26 Locating the error queue in Visual Studio’s Server Explorer.

Figure 12.27 Viewing the contents of a message in the error queue.

Figure 12.28 Promotions bounded context integrating into e-commerce messaging system.

Figure 12.29 A messaging bridge is like a link.

Figure 12.30 Mass Transit receiving messages via the bridge.

Chapter 13

Figure 13.1 The “find recommended users” use case.

Figure 13.2 Adding the Account Management WCF Service.

Figure 13.3 Visual Studio’s WCF test client.

Figure 13.4 Invoking an RPC in WCF’s test client.

Figure 13.5 Adding a Service Reference in Visual Studio.

Figure 13.6 Generated proxy classes.

Figure 13.7 The RPC must have occurred.

Figure 13.8 Viewing the output of a Web API controller in a browser.

Figure 13.9 Component diagram for the Recommended Accounts use case.

Figure 13.10 Containers diagram of Discovery, Account Management, and Marketing bounded contexts.

Figure 13.11 Flow of HTTP requests for the Add Follower use case.

Figure 13.12 Flow of HTTP requests for polling and consuming the Began Following event feed.

Figure 13.13 Accessing the HAL browser.

Figure 13.14 Viewing the entry point resource in the HAL browser.

Figure 13.15 Following the Accounts link in the HAL browser.

Figure 13.16 Resource’s data fields are represented as plain JSON.

Figure 13.17 The Event Store’s admin UI.

Figure 13.18 The NON-GET button in the HAL browser.

Figure 13.19 Constructing JSON on the NON-GET dialog in the HAL browser.

Figure 13.20 Viewing an event in the Event Store.

Figure 13.21 Feed consumer processing events

Chapter 14

Figure 14.1 Tactical patterns—domain model building blocks.

Figure 14.2 An entity.

Figure 14.3 A value object.

Figure 14.4 Modules used to organize domain concepts within a domain model.

Figure 14.5 A large object graph.

Figure 14.6 A large object graph split into aggregates.

Figure 14.7 An aggregate root acts as the entry point to the aggregate.

Figure 14.8 Aggregates should be based around invariants.

Figure 14.9 An aggregate root acts as the entry point to the aggregate.

Figure 14.10 A factory.

Figure 14.11 A repository.

Figure 14.12 A domain event.

Figure 14.13 Storing events, not snapshots

Chapter 15

Figure 15.1 Value object stored in custom format.

Figure 15.2 Separate table for Customer and Name.

Figure 15.3 Customer foreign key used to join Customer and Name.

Chapter 16

Figure 16.1 Creating a client-side GUID and posting to multiple back-end services.

Chapter 18

Figure 18.1 Ensuring correct transactional behavior

Figure 18.2 Flow of internal and external events in a typical business use case

Chapter 19

Figure 19.1 Complexity-causing bidirectional relationships.

Figure 19.2 Constraining a bidirectional association.

Figure 19.3 Qualifying associations.

Figure 19.4 Qualifying associations with filter criteria from the Ubiquitous Language (UL).

Figure 19.5 Modeling relationships with object references increases complexity.

Figure 19.6 Simplified relationships using IDs instead of object references.

Figure 19.7 Complex domain model with an abundance of unnecessary associations.

Figure 19.8 Clearer domain model based only on essential associations.

Figure 19.9 Locking caused by large transactional boundary.

Figure 19.10 Inconsistent data arising from lack of transactional boundaries.

Figure 19.11 Aligning transactional boundaries with domain invariants.

Figure 19.12 Enforcing consistency with help from aggregate roots.

Figure 19.13 Aggregates are eventually consistent externally.

Figure 19.14 Eventually consistent Loyalty aggregate.

Figure 19.15 eBidder bounded contexts.

Figure 19.16 Listing bounded context aggregates.

Figure 19.17 Question aggregate boundary definition.

Figure 19.18 Auction aggregate boundary definition.

Figure 19.19 Listing aggregate boundary definition.

Figure 19.20 All aggregate boundary definitions.

Figure 19.21 Aligning aggregates with transactional boundaries.

Figure 19.22 Aggregate roots are the gateway into an aggregate.

Figure 19.23 Aggregate roots have global identity.

Figure 19.24 Consumers of an aggregate may not hold a reference to the aggregate’s internal members.

Figure 19.25 Sharing information between aggregates by using copies of internal objects.

Figure 19.26 Non aggregate roots can hold a reference to roots from other aggregates.

Figure 19.27 Aggregates should be loaded from a database entirely to protect their integrity.

Figure 19.28 Loading aggregates versus going directly to the database.

Figure 19.29 Aggregate boundaries are consistency boundaries.

Figure 19.30 Eventual consistency using database integration.

Chapter 21

Figure 21.1 An ORM maps between the domain and persistence model.

Figure 21.2 An ORM maps between the domain and the persistence model.

Figure 21.3 An aggregate can be serialized and stored.

Figure 21.4 The memento pattern enables you to map a snapshot of the domain model to the persistence model.

Figure 21.5 Save the events that have occurred to an aggregate.

Figure 21.6 The unit-of-work pattern.

Figure 21.7 The repository acts as an anticorruption layer.

Figure 21.8 Solution object model.

Figure 21.9 Visual Solution project structure

Figure 21.10 NuGet Package Manager

Figure 21.11 The Visual Studio solution structure

Figure 21.12 The build action property of the XML Mapping file

Figure 21.13 The database schema

Figure 21.14 The running program

Figure 21.15 Install RavenDB client libraries via NuGet.

Figure 21.16 Solution explorer with an application based on the NHibernate sample.

Figure 21.17 Inspecting the document inside RavenDB Management Studio.

Figure 21.18 Install Entity Framework client libraries via NuGet.

Figure 21.19 Solution explorer with an application based on the NHibernate sample.

Figure 21.20 Install Dapper client libraries via NuGet.

Figure 21.21 Skeleton solution based on the Entity Framework solution.

Figure 21.22 Add a reference to System.Configuration.

Figure 21.23 Add a reference to System.Transactions.

Chapter 22

Figure 22.1 Calculating the state for any point in history by replaying events.

Figure 22.2 Creating projections from multiple event streams.

Figure 22.3 Efficiently restoring state by using snapshots.

Figure 22.4 Event Store’s stream tab indicating the test data was successfully inserted.

Figure 22.5 Result of running a query in the Event Store web UI.

Figure 22.6 Creating a projection in the web UI.

Figure 22.7 One event stream used to support many different queries and use cases.

Figure 22.8 Creating materialized/denormalized views of the event stream to support each use case.

Chapter 23

Figure 23.1 UI for autonomous applications.

Figure 23.2 UI that defers to authority.

Figure 23.3 Composing a web page with HTML provided by bounded contexts.

Figure 23.4 Pulling in data from multiple bounded contexts.

Figure 23.5 Aggregating on the client.

Figure 23.6 Aggregating on the server.

Figure 23.7 The design for this example.

Figure 23.8 Rendering of composite UI.

Figure 23.9 The design for this example.

Figure 23.10 Client-side JSON API composition in action.

Chapter 24

Figure 24.1 A single model fulfilling the read and write sides of an application.

Figure 24.2 The CQRS pattern with a separate read and write model.

Figure 24.3 The command side of CQRS.

Figure 24.4 A user interface pulling data from many aggregates.

Figure 24.5 The query side of CQRS.

Figure 24.6 Using a different data store for querying.

Figure 24.7 An eventually-consistent read model.

Figure 24.8 Consolidate data from many bounded contexts into a single read model.

Figure 24.9 Use a copy of the transactional database for the read model.

Figure 24.10 An asynchronous write side.

Figure 24.11 Scaling out the read and write sides of CQRS.

Chapter 25

Figure 25.1 Where application services fit in.

Figure 25.2 The Recommend-a-Friend use case.

Figure 25.3 Transactional boundary for Recommend-a-Friend.

Chapter 26

Figure 26.1 Denormalized view cache for the loyalty report.

Figure 26.2 Projecting the “diagnoses” event stream onto event streams representing the monthly summary of each diagnosis.

Figure 26.3 Aggregating data from multiple bounded contexts into a single report.

Figure 26.4 Standard reporting context.

Figure 26.5 Complex data-processing reporting context.

Guide

Cover

Table of Contents

Part I

Pages

xxxv

xxxvi

xxxvii

xxxviii

xxxix

xl

xli

xlii

xliii

1

3

4

5

6

7

8

9

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

73

74

75

76

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

105

106

107

108

109

111

112

113

114

115

116

117

118

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

222

223

224

225

226

227

228

229

231

232

233

234

235

236

237

238

239

240

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

283

284

285

286

287

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

307

309

310

311

312

313

314

315

317

318

320

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

357

358

359

361

362

363

364

365

366

367

368

369

371

372

373

374

375

376

377

378

379

380

381

382

384

385

386

387

388

389

390

391

392

393

394

395

396

397

398

399

400

401

402

403

404

405

406

407

408

409

410

411

412

413

414

415

416

417

418

419

420

421

422

423

424

425

426

427

428

429

430

431

432

433

434

435

436

437

439

440

441

442

443

444

446

448

449

450

451

452

453

454

455

456

457

458

459

460

461

462

463

464

465

466

467

468

469

470

471

472

473

474

475

476

477

479

480

481

482

483

484

485

486

487

488

489

490

491

492

493

494

495

496

497

498

499

500

501

502

503

504

505

506

507

508

509

510

511

512

513

514

515

516

517

519

520

521

523

524

525

526

527

528

529

530

531

532

533

534

535

536

537

538

539

540

541

543

544

545

546

547

548

550

551

552

553

554

555

556

557

558

559

561

562

563

564

565

566

567

568

569

570

571

572

574

575

576

577

578

579

580

581

582

583

584

585

588

590

591

592

593

594

595

596

597

598

599

600

601

602

603

604

605

606

607

608

609

610

611

612

613

614

615

616

617

618

619

620

621

622

623

624

625

626

627

628

631

632

633

634

635

636

637

638

639

640

641

642

643

645

646

647

648

649

651

652

653

654

655

656

658

659

660

661

662

663

664

665

666

667

669

670

671

672

673

674

675

676

677

678

679

680

681

682

683

684

685

686

687

688

689

690

691

692

693

694

695

696

697

698

699

700

701

702

703

704

705

706

707

708

709

710

711

712

713

714

715

716

717

718

719

720

721

722

723

724

725

726

727

728

729

730

731

732

733

734

735

736

746

747

Introduction

WRITING SOFTWARE IS EASY— at least if it’s greenfield software. When it comes to modifying code written by other developers or code you wrote six months ago, it can be a bit of a bore at best and a nightmare at worst. The software works, but you aren’t sure exactly how. It contains all the right frameworks and patterns, and has been created using an agile approach, but introducing new features into the codebase is harder than it should be. Even business experts aren’t helpful because the code bears no resemblance to the language they use. Working on such systems becomes a chore, leaving developers frustrated and devoid of any coding pleasure.

Domain-Driven Design (DDD) is a process that aligns your code with the reality of your problem domain. As your product evolves, adding new features becomes as easy as it was in the good old days of greenfield development. Although DDD understands the need for software patterns, principles, methodologies, and frameworks, it values developers and domain experts working together to understand domain concepts, policies, and logic equally. With a greater knowledge of the problem domain and a synergy with the business, developers are more likely to build software that is more readable and easier to adapt for future enhancement.

Following the DDD philosophy will give developers the knowledge and skills they need to tackle large or complex business systems effectively. Future enhancement requests won’t be met with an air of dread, and developers will no longer have stigma attached to the legacy application. In fact, the term legacy will be recategorized in a developer’s mind as meaning this: a system that continues to give value for the business.

Overview of the Book and Technology

This book provides a thorough understanding of how you can apply the patterns and practices of DDD on your own projects, but before delving into the details, it’s good to take a bird’s-eye view of the philosophy so you can get a sense of what DDD is really all about.

The Problem Space

Before you can develop a solution, you must understand the problem. DDD emphasizes the need to focus on the business problem domain: its terminology, the core reasons behind why the software is being developed, and what success means to the business. The need for the development team to value domain knowledge just as much as technical expertise is vital to gain a deeper insight into the problem domain and to decompose large domains into smaller subdomains.

Figure I.1 shows a high-level overview of the problem space of DDD that will be introduced in the first part of this book.

FIGURE I.1 A blueprint of the problem space of DDD.

The Solution Space

When you have a sound understanding of the problem domain, strategic patterns of DDD can help you implement a technical solution in synergy with the problem space. Patterns enable core parts of your system that are crucial to the success of the product to be protected from the generic areas. Isolating integral components allows them to be modified without having a rippling effect throughout the system.

Core parts of your product that are sufficiently complex or will frequently change should be based on a model. The tactical patterns of DDD along with Model-Driven Design will help you create a useful model of your domain in code. A model is the home to all of the domain logic that enables your application to fulfill business use cases. A model is kept separate from technical complexities to enable business rules and policies to evolve. A model that is in synergy with the problem domain will enable your software to be adaptable and understood by other developers and business experts.

Figure I.2 shows a high-level overview of the solution space of DDD that is introduced in the first part of this book.

FIGURE I.2 A blueprint of the solution space of Domain-Driven Design.

How This Book Is Organized

This book is divided into four parts. Part I focuses on the philosophy, principles, and practices of DDD. Part II details the strategic patterns of integrating bounded contexts. Part III covers tactical patterns for creating effective domain models. Part IV delves into design patterns you can apply to utilize the domain model and build effective applications.

Part I: The Principles and Practices of Domain-Driven Design

Part I introduces you to the principles and practices of DDD.

Chapter 1: What Is Domain-Driven Design?

DDD is a philosophy to help with the challenges of building software for complex domains. This chapter introduces the philosophy and explains why language, collaboration, and context are the most important facets of DDD and why it is much more than a collection of coding patterns.

Chapter 2: Distilling the Problem Domain

Making sense of a complex problem domain is essential to creating maintainable software. Knowledge crunching with domain experts is key to unlocking that knowledge. Chapter 2 details techniques to enable development teams to collaborate, experiment, and learn with domain experts to create an effective domain model.

Chapter 3: Focusing on the Core Domain

Chapter 3 explains how to distill large problem domains and identify the most important part of a problem: the core domain. It then explains why you should focus time and energy in the core domain and isolate it from the less important supporting and generic domains.

Chapter 4: Model-Driven Design

Business colleagues understand an analysis model based on the problem area you are working within. Development teams have their own code version of this model. In order for business and technical teams to collaborate a single model is needed. A ubiquitous language and a shared understanding of the problem space is what binds the analysis model to the code model. The idea of a shared language is core to DDD and underpins the philosophy. A language describing the terms and concepts of the domain, which is created by both the development team and the business experts, is vital to aid communication on complex systems.

Chapter 5: Domain Model Implementation Patterns

Chapter 5 expands on the role of the domain model within your application and the responsibilities it takes on. The chapter also presents the various patterns that can be used to implement a domain model and what situations they are most appropriate for.

Chapter 6: Maintaining the Integrity of Domain Models with Bounded Contexts

In large solutions more than a single model may exist. It is important to protect the integrity of each model to remove the chance of ambiguity in the language and concepts being reused inappropriately by different teams. The strategic pattern known as bounded context is designed to isolate and protect a model in a context while ensuring it can collaborate with other models.

Chapter 7: Context Mapping

Using a context map to understand the relationships between different models in an application and how they integrate is vital for strategic design. It is not only the technical integrations that context maps cover but also the political relationships between teams. Context maps provide a view of the landscape that can help teams understand their model in the context of the entire landscape.

Chapter 8: Application Architecture

An application needs to be able to utilize the domain model to satisfy business use cases. Chapter 8 introduces architectural patterns to structure your applications to retain the integrity of your domain model.

Chapter 9: Common Problems for Teams Starting Out with Domain-Driven Design

Chapter 9 describes the common issues teams face when applying DDD and why it’s important to know when not to use it. The chapter also focuses on why applying DDD to simple problems can lead to overdesigned systems and needless complexity.

Chapter 10: Applying the Principles, Practices, and Patterns of DDD

Chapter 10 covers techniques to sell DDD and to start applying the principles and practices to your projects. It explains how exploration and experimentation are more useful to build great software than trying to create the perfect domain model.

Part II: Strategic Patterns: Communicating between Bounded Contexts

Part II shows you how to integrate bounded contexts, and offers details on the options open for architecting bounded contexts. Code examples are presented that detail how to integrate with legacy applications. Also included are techniques for communicating across bounded contexts.

Chapter 11: Introduction to Bounded Context Integration

Modern software applications are distributed systems that have scalability and reliability requirements. This chapter blends distributed systems theory with DDD so that you can have the best of both worlds.

Chapter 12: Integrating via Messaging

A sample application is built showing how to apply distributed systems principles synergistically with DDD using a message bus for asynchronous messaging.

Chapter 13: Integrating via HTTP with RPC and REST

Another sample application is built showing an alternative approach to building asynchronous distributed systems. This approach uses standard protocols like Hypertext Transport Protocol (HTTP), REST, and Atom instead of a message bus.

Part III: Tactical Patterns: Creating Effective Domain Models

Part III covers the design patterns you can use to build a domain model in code, along with patterns to persist your model and patterns to manage the lifecycles of the domain objects that form your model.

Chapter 14: Introducing the Domain Modeling Building Blocks

This chapter is an introduction to all the tactical patterns at your disposal that allow you to build an effective domain model. The chapter highlights some best practice guidelines that produce more manageable and expressive models in code.

Chapter 15: Value Objects

This is an introduction to the DDD modeling construct that represents identityless domain concepts like money.

Chapter 16: Entities

Entities are domain concepts that have an identity, such as customers, transactions, and hotels. This chapter covers a variety of examples and complementary implementation patterns.

Chapter 17: Domain Services

Some domain concepts are stateless operations that do not belong to a value object or an entity. They are known as domain services.

Chapter 18: Domain Events

In many domains, focusing on events reveals greater insight than focusing on just entities. This chapter introduces the domain event design pattern that allows you to express events more clearly in your domain model.

Chapter 19: Aggregates

Aggregates are clusters of domain objects that represent domain concepts. Aggregates are a consistency boundary defined around invariants. They are the most powerful of the tactical patterns.

Chapter 20: Factories

Factories are a lifecycle pattern that separate use from construction for complex domain objects.

Chapter 21: Repositories

Repositories mediate between the domain model and the underlying data model. They ensure that the domain model is kept separate from any infrastructure concerns.

Chapter 22: Event Sourcing

Like domain events in Chapter 18, event sourcing is a useful technique for emphasizing, in code, events that occur in the problem domain. Event sourcing goes beyond domain events by storing the state of the domain model as events. This chapter provides a number of examples, including ones that use a purpose-built event store.

Part IV: Design Patterns for Effective Applications

Part IV showcases the design patterns for architecting applications that utilize and protect the integrity of your domain model.

Chapter 23: Architecting Application User Interfaces

For systems composed of many bounded contexts, the user interface often requires the composition of data from a number of them, especially when your bounded contexts form a distributed system.

Chapter 24: CQRS: An Architecture of a Bounded Context

CQRS is a design pattern that creates two models where there once was one. Instead of a single model to handle the two different contexts of reads and writes, two explicit models are created to handle commands or serve queries for reports.

Chapter 25: Commands: Application Service Patterns for Processing Business Use Cases

Learn the difference between application and domain logic to keep your model focused and your system maintainable.

Chapter 26: Queries: Domain Reporting

Business people need information to make informed business and product-development decisions. A range of techniques for building reports that empower the business is demonstrated in this chapter.

Who Should Read This Book

This book introduces the main themes behind DDD—its practices, patterns, and principles along with personal experiences and interpretation of the philosophy. It is intended to be used as a learning aid for those interested in or starting out with the philosophy. It is not a replacement for Domain-Driven Design: Tackling Complexity in the Heart of Software by Eric Evans (Addison-Wesley Professional, 2003). Instead, it takes the concepts introduced by Evans and distills them into simple straightforward prose, with practical examples so that any developer can get up to speed with the philosophy before going on to study the subject in more depth.

This book is based on the author’s personal experiences with the subject matter. You may not always agree with it if you are a seasoned DDD practitioner, but you should still get something out of it.

Source Code

As you work through the examples in this book, you may choose either to type in all the code manually, or to use the source code files that accompany the book. All the source code used in this book is available for download at www.wrox.com. Specifically for this book, the code download is on the Download Code tab at: www.wrox.com/go/domaindrivendesign. Although code examples are presented in C# .NET. The concepts and practices can be applied to any programming language.

You can also search for the book at www.wrox.com by ISBN (the ISBN for this book is 978-1-1187-1470-6) to find the code. And a complete list of code downloads for all current Wrox books is available at www.wrox.com/dynamic/books/download.aspx.

Errata

We make every effort to ensure that there are no errors in the text or in the code. However, no one is perfect, and mistakes do occur. If you find an error in one of our books, like a spelling mistake or faulty piece of code, we would be very grateful for your feedback. By sending in errata, you may save another reader hours of frustration, and at the same time, you will be helping us provide even higher quality information.

To find the errata page for this book, go to www.wrox.com/go/domaindrivendesign.

And click the Errata link. On this page you can view all errata that has been submitted for this book and posted by Wrox editors.

If you don’t spot “your” error on the Book Errata page, go to www.wrox.com/contact/techsupport.shtml and complete the form there to send us the error you have found. We’ll check the information and, if appropriate, post a message to the book’s errata page and fix the problem in subsequent editions of the book.

p2p.wrox.com

For author and peer discussion, join the P2P forums at http://p2p.wrox.com. The forums are a web-based system for you to post messages relating to Wrox books and related technologies and interact with other readers and technology users. The forums offer a subscription feature to e-mail you topics of interest of your choosing when new posts are made to the forums. Wrox authors, editors, other industry experts, and your fellow readers are present on these forums.

At http://p2p.wrox.com, you will find a number of different forums that will help you, not only as you read this book, but also as you develop your own applications. To join the forums, just follow these steps:

Go to

http://p2p.wrox.com

and click the Register link.

Read the terms of use and click Agree.

Complete the required information to join, as well as any optional information you wish to provide, and click Submit.

You will receive an e-mail with information describing how to verify your account and complete the joining process.

NOTEYou can read messages in the forums without joining P2P, but in order to post your own messages, you must join.

Once you join, you can post new messages and respond to messages other users post. You can read messages at any time on the web. If you would like to have new messages from a particular forum e-mailed to you, click the Subscribe to this Forum icon by the forum name in the forum listing.

For more information about how to use the Wrox P2P, be sure to read the P2P FAQs for answers to questions about how the forum software works, as well as many common questions specific to P2P and Wrox books. To read the FAQs, click the FAQ link on any P2P page.

Summary

The aim of this book is to present the philosophy of DDD in a down-to-earth and practical manner for experienced developers building applications for complex domains. A focus is placed on the principles and practices of decomposing a complex problem space as well as the implementation patterns and best practices for shaping a maintainable solution space. You will learn how to build effective domain models by using tactical patterns and how to retain their integrity by applying the strategic patterns of DDD.

By the end of this book, you will have a thorough understanding of DDD. You will be able to communicate its value and when to use it. You will understand that even though the tactical patterns of DDD are useful, it is the principles, practices, and strategic patterns that will help you architect applications for maintenance and scale. With the information gained within this book, you will be in a better place to manage the construction and maintenance of complex software for large and complex problem domains.

PART IThe Principles and Practices of Domain-Driven Design

1What Is Domain-Driven Design?

WHAT’S IN THIS CHAPTER?

An introduction to the philosophy of Domain-Driven Design

The challenges of writing software for complex problem domains

How Domain-Driven Design manages complexity

How Domain-Driven Design applies to both the problem and solution space

The strategic and tactical patterns of Domain-Driven Design

The practices and principles of Domain-Driven Design

The misconceptions of Domain-Driven Design

Domain-Driven Design (DDD) is a development philosophy defined by Eric Evans in his seminal work Domain-Driven Design: Tackling Complexity in the Heart of Software (Addison-Wesley Professional, 2003). DDD is an approach to software development that enables teams to effectively manage the construction and maintenance of software for complex problem domains.

This chapter will give you a high-level introduction to DDD’s practices, patterns, and principles along with an explanation of how it will improve your approach to software development. You will learn the value of analyzing a problem space and where to focus your efforts. You will understand why collaboration, communication, and context are so important for the design of maintainable software.

At the end of this chapter you will have a solid understanding of DDD that will provide context to the detail of the various patterns, practices, and principles that are contained throughout this book. However, before we delve into how DDD handles complexity it’s important to understand what problems can cause software to get into an unmanageable state.

The Challenges of Creating Software for Complex Problem Domains

To understand how DDD can help with the design of software for a nontrivial domain, you must first understand the difficulties of creating and maintaining software. By far, the most popular software architectural design pattern for business applications is the Big Ball of Mud (BBoM) pattern. The definition of BBoM, as defined by Brian Foote and Joseph Yoder in the paper “Big Ball of Mud,” is “… a haphazardly structured, sprawling, sloppy, duct-tape-and-baling-wire, spaghetti-code jungle.”

Foote and Yoder use the term BBoM to describe an application that appears to have no distinguishable architecture (think big bowl of spaghetti versus dish of layered lasagna). The issue with allowing software to dissolve into a BBoM becomes apparent when routine changes in workflow and small feature enhancements become a challenge to implement due to the difficulties in reading and understanding the existing codebase. In his book, Domain-Driven Design: Tackling Complexity in the Heart of Software (Addison-Wesley Professional, 2003), Eric Evans describes such systems as containing “code that does something useful, but without explaining how.” One of the main reasons software becomes complex and difficult to manage is due to the mixing of domain complexities with technical complexities, as illustrated in Figure 1.1.

FIGURE 1.1 Complexity in software.

Code Created without a Common Language

A lack of focus on a shared language and knowledge of the problem domain results in a codebase that works but does not reveal the intent of the business. This makes codebases difficult to read and maintain because translations between the analysis model and the code model can be costly and error prone.

Code without a binding to an analysis model that the business understands will degrade over time and is therefore more likely to result in an architecture that resembles the BBoM pattern. Due to the cost of translation teams that do not utilize the rich vocabulary of the problem domain in code will decrease their chances of discovering new domain concepts when collaborating with business experts.

WHAT IS AN ANALYSIS MODEL?

An analysis model is used to describe the logical design and structure of a software application. It can be represented as sketches or by using modeling languages such as UML. It is the representation of software that non-technical people can conceptualize in order to understand how software is constructed.

A Lack of Organization

As highlighted in Figure 1.2, the initial incarnation of a system that resembles BBoM is fast to produce and often a well-rounded success, but because there is little focus based on the design of an application around a model of the problem domain, subsequent enhancements are troublesome. The codebase lacks the required synergy with the business behavior to make change manageable. Complexities of the problem domain are often mixed with the accidental complexities of the technical solution.

FIGURE 1.2 Code rot.

The Ball of Mud Pattern Stifles Development

Continuing to persist with an architectural spaghetti-like pattern can lead to a sluggish pace of feature enhancement. When newer versions of the product are released, they can be buggy due to the unintelligible mess of the codebase that developers have to deal with. Over time, the development team increasingly complains about the difficulty of working in such a mess. Even if resources are added to the project, velocity cannot be increased to a level that satisfies the business.

In the end, exasperated by the situation, the request for the dreaded application rewrite is granted. Without due care and consideration, however, even the greenfield project can fall foul of the same issues that created the original BBoM. This entire experience can be frustrating for the business that saw a great return on investment (ROI) in terms of features and speed of delivery at the beginning but over time, even with additional investment in resources, did not see the sustained evolution of the product to meet their needs. Ultimately the BBoM is bad news for you as a developer because it’s a messy bug-prone code base that you hate dealing with. And it’s bad news for the business because it reduces their capability to rapidly deliver business value

A Lack of Focus on the Problem Domain

Software projects fail when you don’t understand the business domain you are working within well enough. Typing is not the bottleneck for delivering a product; coding is the easy part of development. Outside of non-functional requirements creating and keeping a useful software model of the domain that can fulfill business-use cases is the difficult part. However, the more you invest in understanding your business domain the better equipped you will be when you are trying to model it in software to solve its inherent business problems.

WHAT IS A PROBLEM DOMAIN?

A problem domain refers to the subject area for which you are building software. DDD stresses the need to focus on the domain above anything else when working on creating software for large-scale and complex business systems. Experts in the problem domain work with the development team to focus on the areas of the domain that are useful to be able to produce valuable software. For example, when writing software for the health industry to record patient treatment, it is not important to learn to become a doctor. What is important to understand is the terminology of the health industry, how different departments view patients and care, what information doctors gather, and what they do with it.

How the Patterns of Domain-Driven Design Manage Complexity

DDD deals with both the challenge of understanding a problem domain and creating a maintainable solution that is useful to solve problems within it. It achieves this by utilizing a number of strategic and tactical patterns.

The Strategic Patterns of DDD

The strategic patterns of DDD distil the problem domain and shape the architecture of an application.

Distilling the Problem Domain to Reveal What Is Important

Not all of a large software product needs be perfectly designed—in fact trying to do so would be a waste of effort. Development teams and domain experts use analysis patterns and knowledge crunching to distill large problem domains into more manageable subdomains. This distillation reveals the core sub domain—the reason the software is being written. The core domain is the driving force behind the product under development; it is the fundamental reason it is being built. DDD emphasizes the need to focus effort and talent on the core subdomain(s) as this is the area that holds the most value and is key to the success of the application.

This clarity on where to focus effort can also empower teams to look for open source off-the-shelf solutions for some of the less important parts of a system, which means that they have more time to focus on what is important and ensure that the core domain does not become a BBoM.

Discovering the core domain helps teams understand why they’re producing the software and what it means for the software to be successful to the business. It is the appreciation for the business intent that will enable the development team to identify and invest its time in the most important parts of the system. As the business evolves, so in turn must the software; it needs to be adaptable. Investment in code quality for the key areas of an application will help it change with the business. If key areas of the software are not in synergy with the business domain then, over time, it is likely that the design will rot and turn into a big ball of mud, resulting in hard-to-maintain software.

Creating a Model to Solve Domain Problems

In the solution space a software model is built for each subdomain to handle domain problems and to align the software with the business contours. This model is not a model of real life but more an abstraction built to satisfy the requirements of business use cases while still retaining the rules and logic of the business domain. The development team should focus as much energy and effort on the model and domain logic as it does on the pure technical aspects of the application. To avoid accidental technical complexity the model is kept isolated from infrastructure code.

All models are not created equal; the most appropriate design patterns are used based on the complexity needs of each subdomain rather than applying a blanket design to the whole system. Models for subdomains that are not core to the success of the product or that are not as complex need not be based on rich object-oriented designs, and can instead utilize more procedural or data-driven architectures.

Using a Shared Language to Enable Modeling Collaboration

Models are built through the collaboration of domain experts and the development team. Communication is achieved using an ever-evolving shared language known as the ubiquitous language (UL) to efficiently and effectively connect a software model to a conceptual analysis model. The software model is bound to the analysis model by using the same terms of the UL for its structure and class design. Insights, concepts, and terms that are discovered at a coding level are replicated in the UL and therefore the analytical model. Likewise when the business reveals hidden concepts at the analysis model level this insight is fed back into the code model; this is the key that enables the domain experts and development teams to evolve the model in collaboration.

Isolate Models from Ambiguity and Corruption

Models sit within a bounded context, which defines the applicability of the model and ensures that its integrity is retained. Larger models can be split into smaller models and defined within separate bounded contexts where ambiguity in terminology exists or where multiple teams are a working in order to further reduce complexity.

Bounded contexts are used to form a protective boundary around models that helps to prevent software from evolving into a BBoM. This is achieved by allowing the different models of the overall solution to evolve within well-defined business contexts without having a negative, rippling impact on other parts of the system. Models are isolated from infrastructure code to avoid the accidental complexity of merging technical and business concepts. Bounded contexts also prevent the integrity of models being corrupt by isolating them from third-party code.

Compare the diagram in Figure 1.3 to Figure 1.2. The diagram shows how the strategic patterns of DDD have been applied to the software to manage the large problem domain and protect discrete models within it.

FIGURE 1.3 Applying the strategic patterns of Domain-Driven Design.

THE BIG BALL OF MUD IS NOT ALWAYS AN ANTIPATTERN

Not all parts of a large application will be designed perfectly—nor do they need to be. Although it’s not advisable to build an entire enterprise software stack following the BBoM pattern, you can still utilize the pattern. Areas of low complexity or that are unlikely to be invested in can be built without the need for perfect code quality; working software is good enough. Sometimes feedback and first-to-market are core to the success of a product; in this instance, it can make business sense to get working software up as soon as possible, whatever the architecture. Code quality can always be improved after the business deems the product to be a success and worthy of prolonged investment. The key to reaping the benefits of the BBoM is to define a context around the bounded contexts that use the BBoM to avoid them corrupting the core subcomain.

Understanding the Relationships between Contexts