Mastering Bounded Contexts: A Practical Guide to DDD Subdomains, Entities, and Value Objects
This article explains Domain‑Driven Design fundamentals, covering how to define bounded contexts and subdomains, the criteria for domain division, practical modeling experiences, and detailed guidance on modeling entities and value objects with illustrative Go code examples.
1. Bounded Context
Domain‑Driven Design (DDD) separates a domain into subdomains and bounded contexts to create a single ubiquitous language.
1.1 Division criteria
Ubiquitous language : terms must have a single meaning; otherwise split contexts.
Domain responsibilities : each context has distinct goals.
Domain roles : required roles (e.g., front‑end, back‑end) differ per context.
Domain knowledge : expertise varies across contexts.
Domain activities : different activities (UI construction vs. data access) belong to different contexts.
Domain focus points : emphasis differs per context.
1.2 Practical example
In a service with two user roles—operations staff (low‑frequency rule configuration) and end users (high‑frequency rule usage)—the initial single bounded context violated the single‑responsibility principle. The solution was to split into two bounded contexts: a configuration platform context and a user‑usage context, sharing overlapping aggregates where appropriate.
1.3 Summary
A domain defines a scope containing roles, knowledge, activities, events, and responsibilities.
Division criteria include responsibilities, focus points, required roles, knowledge, and activities.
Event‑storming helps identify these elements.
2. Entity
2.1 Definition
An entity has a unique identity, a set of attributes, and domain behavior. Identity is immutable and usually a simple ID without business meaning.
2.2 Attributes
Atomic attributes : simple values such as Name or Sex.
Composite attributes : objects that group related data, e.g., Price{Amount, Unit}.
2.3 Domain behavior
Behaviors should be expressed with business‑meaningful method names, not generic getters/setters. They may change state, perform validation, or coordinate with other aggregates.
2.4 Example
type Student struct {
ID uint64
Name string
Sex string
Class string
IsLate int
Sign *Sign
}
type Sign struct {
SignTime time.Time
}
func (stu *Student) StudentSign() {
isLate := TimeCheck()
stu.IsLate = isLate
// flush redis...
}The fields map to database columns; IsLate is cached for high‑frequency queries, while StudentSign updates the entity and performs validation.
3. Value Object
3.1 Definition
A value object is an immutable component of an entity that represents a concept such as a measurement, address, or coordinate. It has no identity and its equality is based on its attribute values.
3.2 Characteristics
Immutable – state cannot change after creation.
Encapsulates domain behavior such as validation, composition, or calculation.
3.3 Example
// NewCoordinateVo initializes a coordinate value object
func NewCoordinateVo(LongitudeStr string, LatitudeStr string) (*VoCoordinate, error) {
Longitude, err := strconv.ParseFloat(LongitudeStr, 64)
if err != nil {
return nil, fmt.Errorf("Longitude_input_err")
}
Latitude, err := strconv.ParseFloat(LatitudeStr, 64)
if err != nil {
return nil, fmt.Errorf("Latitude_input_err")
}
return &VoCoordinate{Longitude: Longitude, Latitude: Latitude}, nil
}The constructor validates inputs, and the resulting VoCoordinate is immutable.
3.4 When to use
Use a value object when equality is determined by its attributes; use an entity when a stable identity is required.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
