Skip to product information
Functional Programming for Domain-Driven Design
Functional Programming for Domain-Driven Design
Description
Book Introduction
Real-world functional DDD, even with sample code overhauled

This book naturally connects domain modeling and the functional paradigm, guiding you through the process of implementing complex real-world problems with simple, secure code.
In particular, it presents a software design method that reduces errors and reveals business rules more clearly through the philosophy of expressing domain knowledge as types.

Scott Blasin's famous book, Domain Modeling Made Functional, explains this philosophy using examples based on F#, but there was a language barrier to its use in the domestic practical environment.
In this newly translated Korean edition, we have overcome this barrier and rewritten all examples in TypeScript and Kotlin.
The biggest difference is that it is not a simple grammar substitution, but rather a result of redesign and implementation using the type system and idioms of each language, and is reborn in a form that can be immediately applied in practice.

Thanks to this, readers can not only gain a conceptual understanding of domain-driven design, but also experience the modeling process naturally by following code written in a familiar language.
Additionally, through the "concept → code → improvement (refactoring)" flow that follows each chapter, you can learn the mindset to build models and designs suitable for practical use, rather than simply learning theories.

It's okay if you don't have a deep understanding of functional programming.
This book uses intuitive examples rather than complex abstractions, guiding developers to transition to a domain-centric mindset. This is a rare practical guide that pushes the topics of DDD, FP, and type systems down to the actual code level, offering refreshing insights even to developers who have felt the limitations of traditional object-oriented DDD.

This is a must-read for developers who want to view complex problems simply and clearly implement domains through safe code.

  • You can preview some of the book's contents.
    Preview

index
Translator's Preface xii
Recommendation xv
Beta Reader Review xvi
Preface to the Korean Edition xviii
Preface xix

PART I Understanding Domains
CHAPTER 1 Introduction to DDD 3
1.1 The Importance of the Sharing Model 4
1.2 Understanding Domains as Business Events 7
__1.2.1 Exploring the Domain with Event Storming 8 / 1.2.2 Exploring the Domain: The Order-Taking System 8 / 1.2.3 Extending Events to the End 12 / 1.2.4 Documenting Commands 13
1.3 Dividing a domain into subdomains 15
1.4 Creating Solutions Using Boundary Context 17
__1.4.1 Getting the Context Right 18 / 1.4.2 Creating a Context Map 19 / 1.4.3 Focusing on the Most Important Context 21
1.5 Creating a Common Language 21
1.6 Summary of DDD Concepts 22
1.7 Final 23
__1.7.1 Events and Processes 23 / 1.7.2 Subdomains and Boundary Contexts 24 / 1.7.3 Common Language 24 / 1.7.4 Guide to the Next Chapter 24

CHAPTER 2 Understanding Domains 25
2.1 Interviewing Domain Experts 25
__2.1.1 Understanding Non-Functional Requirements 27 / 2.1.2 Understanding the Rest of the Workflow 28 / 2.1.3 Thinking About Input 29
2.2 Avoiding Database-Centric Design 30
2.3 Avoiding Class-Centric Design 31
2.4 Domain Documentation 32
2.5 Digging Deeper into the Order Acceptance Workflow 33
2.6 Modeling Complex Domains 36
__2.6.1 Expressing Constraints 37 / 2.6.2 Expressing the Order Life Cycle 39 / 2.6.3 Specifying the Steps of a Workflow 41
2.7 Conclusion 43
__2.7.1 Next Chapter Guide 44

CHAPTER 3 FUNCTIONAL ARCHITECTURE 45
3.1 Boundary Context as Autonomous Software Components 46
3.2 Communication across boundary contexts 47
__3.2.1 Data Transfer Between Boundary Contexts 48 / 3.2.2 Trust Boundaries and Verification 49
3.3 Contracts between Boundary Contexts 50
__3.3.1 Anti-Corruption Layer 51 / 3.3.2 Context Map Representing Inter-Contextual Relationships 51
3.4 Workflow of the Boundary Context 52
__3.4.1 Workflow Input and Output 53 / 3.4.2 Prohibiting Domain Events Within Boundary Contexts 54
3.5 Code Structure in the Boundary Context 55
__3.5.1 Onion Architecture 56 / 3.5.2 Removing External I/O to Context Boundaries 57
3.6 Final 57
__3.6.1 Next Chapter Guide 58

PART II Domain Modeling
CHAPTER 4 Understanding Types 61
4.1 Understanding Functions 61
__4.1.1 Understanding Functions 62
4.2 Types and Functions 63
4.3 Type Synthesis 66
__4.3.1 AND type 67 / 4.3.2 OR type 67 / 4.3.3 Simple type 69 / 4.3.4 Algebraic type system 69
4.4 Handling TypeScript and Kotlin Types 70
4.5 Creating a Domain Model with Type 73
4.6 Modeling Missing Values, Errors, and Collections 77
__4.6.1 Modeling Optional Values ​​78 / 4.6.2 Modeling Errors 79 / 4.6.3 Modeling the Absence of Values ​​80 / 4.6.4 Modeling Lists and Collections 81
4.7 Final 83

CHAPTER 5: Modeling Domains with Types 85
5.1 Revisiting the Domain Model 85
5.2 Finding Patterns in the Domain Model 87
5.3 Simple Value Modeling 87
__5.3.1 Using Wrapper Types 89 / 5.3.2 Constrained Values ​​90 / 5.3.3 Mitigating Performance Issues with Simple Types 90
5.4 Complex Data Modeling 92
__5.4.1 Record Modeling 92 / 5.4.2 Unknown Type Modeling 93 / 5.4.3 Selected Type Modeling 94
5.5 Modeling Workflows with Functions 95
__5.5.1 Handling Complex Input and Output 96 / 5.5.2 Documenting Effects in Function Signatures 99
5.6 On Identity: Value Objects 100
__5.6.1 Equality of Value Objects 102
5.7 On Identity: Entity 103
__5.7.1 Entity IDs 103 / 5.7.2 Including IDs in Data Definitions 104 / 5.7.3 Equality of Entities 106 / 5.7.4 Immutability and Identity 108
5.8 Assembly 110
__5.8.1 Aggregates Responsible for Consistency and Invariance 112 / 5.8.2 Aggregate Reference 112
5.9 Putting it all together 115
__5.9.1 Rethinking the Challenge: Can Types Really Replace Documents? 119
5.10 Finish 120

CHAPTER 6 Domain Integrity and Consistency 121
6.1 Integrity of Simple Values ​​122
6.2 Units of Measurement 126
6.3 Enforcing Immutability with the Type System 128
6.4 Integrating Business Rules into the Type System 128
__6.4.1 Modifying the example domain to prevent incorrect states 133
6.5 Consistency 135
__6.5.1 Consistency within a single collection 135 / 6.5.2 Consistency across different contexts 137 / 6.5.3 Consistency across collections in the same context 138 / 6.5.4 Multiple collections handling the same data 140
6.6 Finish 140

CHAPTER 7 Modeling Workflows with Pipelines 141
7.1 Workflow Input 142
__7.1.1 Using Commands as Input 143 / 7.1.2 Generalizing Common Structures 144 / 7.1.3 Bundling Multiple Commands into a Single Type 145
7.2 Modeling Orders as State Sets 146
__7.2.1 Adding new state types based on changing requirements 149
7.3 State Machine 149
__7.3.1 Why Use a State Machine? 151 / 7.3.2 How to Implement a Simple State Machine with TypeScript and Kotlin 151
7.4 Modeling Individual Steps of a Workflow with Type 153
__7.4.1 Validation Step 153 / 7.4.2 Pricing Step 156 / 7.4.3 Order Confirmation Step 157 / 7.4.4 Creating Events to Return 160
7.5 Documenting Effects 162
__7.5.1 Effect of the Verification Step 162 / 7.5.2 Effect of the Pricing Step 164 / 7.5.3 Effect of the Order Confirmation Step 165
7.6 Synthesizing a Workflow from Individual Steps 166
7.7 Should Dependencies Be Included in Your Design? 167
7.8 Complete Pipeline 169
__7.8.1 Internal Step 171
7.9 Long-running workflows 175
7.10 Final 176
__7.10.1 Next Chapter Guide 177

PART III Implementing the Model
CHAPTER 8 Understanding Functions 181
8.1 Functions, Functions Everywhere 182
8.2 Function is the main character 183
__8.2.1 Functions as Protagonists 184 / 8.2.2 Functions as Input 185 / 8.2.3 Functions as Output 186 / 8.2.4 Currying 187 / 8.2.5 Partial Application 188
8.3 Complete Functions 189
8.4 Function Composition 192
__8.4.1 Function Composition in TypeScript and Kotlin 193 / 8.4.2 Composing Entire Applications with Functions 195 / 8.4.3 Not-So-Easy Function Composition 196
8.5 Finish 198

CHAPTER 9 Implementation: Combining Pipelines 199
9.1 Handling Simple Types 200
9.2 Guide to implementing with function types 202
9.3 Implementing the Validation Step 204
__9.3.1 Generating a Valid Address 207 / 9.3.2 Creating an Order Item 209 / 9.3.3 Creating a Function Adapter 211
9.4 Implementing the remaining steps 214
__9.4.1 Implementing the Approval Step 218 / 9.4.2 Creating an Event 220
9.5 Assembling All Pipeline Stages 224
9.6 Dependency Injection 227
__9.6.1 Overflowing Dependence 235
9.7 Dependency Testing 237
9.8 Assembled pipeline 240
9.9 Finish 244

CHAPTER 10 Implementation: Error Handling 247
10.1 Exposing Errors with Either Types 247
10.2 Handling Domain Errors 249
__10.2.1 Modeling Domain Errors with Types 251 / 10.2.2 Handling Errors That Clutter Your Code 253
10.3 Connecting functions that output Either types 255
__10.3.1 Implementing an Adapter Block 258 / 10.3.2 Managing Either Functions 260 / 10.3.3 Function Composition and Type Checking 261 / 10.3.4 Converting to Common Error Types 262
10.4 Assembling a Pipeline with FlatMap and Map 266
10.5 Adapting Other Types of Functions to the Dual-Track Model 269
__10.5.1 Exception Handling 269 / 10.5.2 Dead-End Function Handling 273
10.6 Handling Complex Pipelines 275
__10.6.1 fp-ts's do notation 275 / 10.6.2 arrow-kt's either block 277 / 10.6.3 arrow-kt's Raise context 278 / 10.6.4 Order checking with Either type 282 / 10.6.5 Validating Either lists 283
10.7 Monads and Other Concepts 286
__10.7.1 Parallel Synthesis with Applications 287
10.8 Adding Asynchronous Effects 287
10.9 Finish 291

CHAPTER 11 SERIALIZATION 293
11.1 Persistence and Serialization 293
11.2 Design for Serialization 294
11.3 Connecting Serialization Code to a Workflow 295
__11.3.1 DTO 296 as a Contract Between Boundary Contexts
11.4 Complete Serialization Example 297
__11.4.1 Wrapping a JSON Serialization Library 301 / 11.4.2 A Complete Serialization Pipeline 302 / 11.4.3 Managing Multiple Versions of a Serialization Type 306
11.5 How to Convert a Domain Type to a DTO 306
__11.5.1 Simple Types 306 / 11.5.2 Optional Values ​​307 / 11.5.3 Records 307 / 11.5.4 Collections 308 / 11.5.5 Enumerations 310 / 11.5.6 Tuples 311 / 11.5.7 Choice Types 312 / 11.5.8 Serializing Record and Choice Types with Maps 317 / 11.5.9 Generics 320
11.6 Finish 321

CHAPTER 12 Perpetuation 323
12.1 Pushing Persistence Code to the Edge 324
__12.1.1 Input-Based Decision Making 329 / 12.1.2 Where Does the Repository Pattern Fit? 330
12.2 Separating Update Commands and Inquiry Queries 331
__12.2.1 Command-Query Responsibility Separation 334 / 12.2.2 CQRS and Database Separation 336 / 12.2.3 Event Sourcing 336
12.3 Owning a Reader Data Store for Each Boundary Context 337
__12.3.1 How to use data from multiple domains 337
12.4 Working with Document Databases 339
12.5 Working with Relational Databases 339
__12.5.1 Mapping Selection Types to Tables 341 / 12.5.2 Mapping Nested Types to Tables 344 / 12.5.3 Reading from a Relational Database 345 / 12.5.4 Reading Selection Types from a Relational Database 352 / 12.5.5 Writing to a Relational Database 355
12.6 Transaction 358
12.7 Finish 360

CHAPTER 13 Developing Designs Cleanly 361
13.1 First Change: Adding Shipping Costs 362
__13.1.1 Simplifying Business Logic with Separation of Concerns 363 / 13.1.2 Adding a New Step to a Workflow 364 / 13.1.3 Another Reason to Add a New Step to a Pipeline 368
13.2 Second Change: Adding VIP Customer Support 368
__13.2.1 Adding a New Input to a Workflow 371 / 13.2.2 Adding a Free Shipping Rule to a Workflow 373
13.3 Third Change: Added Promo Code Support 374
__13.3.1 Adding a Promotion Code to the Domain Model 374 / 13.3.2 Changing the Pricing Logic 376 / 13.3.3 Implementing the GetPricingFunction 378 / 13.3.4 Documenting Discounts on Order Items 379 / 13.3.5 More Complex Pricing Systems 381 / 13.3.6 Modifying a Contract Between Boundary Contexts 382 / 13.3.7 Printing Orders 384
13.4 Fourth Change: Added Business Hours Restrictions 384
13.5 Handling Additional Requirement Changes 386
13.6 Finish 386
13.7 Book Ending 387

Search 390

Detailed image
Detailed Image 1

Into the book
Most people probably think that what a programmer does is write code.
But I disagree.
A programmer's job is to solve problems with software, and coding is only one aspect of software development.
Good design and communication are just as important as coding.
/ If we think of software development as a process that takes input called requirements and outputs the final result, the law of 'garbage in, garbage out' applies here as well.
No code will produce the desired result with incorrect inputs, such as unclear requirements or faulty design.

--- p.3

It's a good time to take a quick look at how to implement a domain model in software.
In rapid development cycles, you often find yourself implementing parts of a domain before you understand the entire domain.
So before we build all the components, we need to figure out how to combine them.
There's also a lot to be said for creating a "walking skeleton," a rough prototype that demonstrates how the entire system might work.
Exploring what and how to implement it early is the best way to figure out what you don't yet fully understand.

--- p.45

Now that you've taken the effort to properly model your domain, you need to take some precautions to ensure that all data in your domain is valid and consistent.
We will ensure that only trusted data exists within a perimeter context, separated from the untrusted external world.
If you can be sure that all data within a context is always valid, you can avoid unnecessary defensive code and have a cleaner implementation.

--- p.121

So far, we've identified the requirements for our order processing workflow and modeled them into types.
Now the next task is to implement that design in a functional programming manner.
/ Before we dive in, it's important to understand what functional programming is and the tools and strategies needed to implement it.
By the end of this chapter, you will have a solid grasp of the core concepts of functional programming.
These concepts are useful not only for domain-driven design, but for all kinds of programming.

--- p.181

Each stage of the pipeline is implemented as an independent function.
Functions should be implemented without state or side effects, so that they can be tested and reasoned about independently.
Next, we combine these small functions into one large function.
It's easy to say, but when you actually do it, you often run into problems where the output of the designed functions and the input of the next function don't match.
To solve this problem, you need to learn how to manipulate the inputs and outputs of each step so that the functions are composable.

--- p.200

This chapter explains how to persist your domain model.
Let's first discuss general principles, such as command-query separation, and then look at implementation details.
In particular, we explore two implementations for persisting domain models in NoSQL document databases and traditional SQL databases.
By the end of this chapter, you will have all the knowledge you need to integrate persistence mechanisms.
--- p.323

Publisher's Review
● How to properly understand domains
Revisiting DDD with Functional Thinking
● Modeling technique for designing by type
● Business logic expressed as a pipeline
● Design to block errors at compile time
● Flexible integration with databases
● Domain modeling where code and documentation become one
GOODS SPECIFICS
- Date of issue: November 20, 2025
- Page count, weight, size: 416 pages | 188*245*20mm
- ISBN13: 9791194587897

You may also like

카테고리