Introduction
Bounded contexts have a crucial role in managing complexity, maintaining a clear separation of concerns, and ensuring that different parts of a system can communicate effectively without causing conflicts or confusion. Bounded contexts are a fundamental concept in Domain-Driven Design (DDD) and are particularly relevant when building complex systems.
In this article, the bounded contexts will be explored using a practical example in Ruby, where we'll demonstrate how to consume and wrap a Plan object between two different contexts: the Plan Management context and the Sales context.
Understanding Bounded Contexts
A bounded context is a conceptual boundary within which a particular domain model is defined and applicable. Different parts of a software system may have different understandings of specific terms, rules, and behaviors. Bounded contexts help avoid ambiguity and conflicts by isolating other models within their own context, making sure they remain consistent and meaningful within that context.
In our example scenario, imagine a software application for a company that offers subscription plans to its customers. There are two primary bounded contexts: Plan Management and Sales.
Plan Management Context: This context is responsible for creating, updating, and managing subscription plans. It focuses on the administrative aspects of plan creation and modification.
Sales Context: This context is responsible for handling customer interactions, including the sale of subscription plans. It deals with pricing, availability, and customer-specific details.
Consuming and Wrapping Plan Objects
Let's dive into the example scenario to understand how bounded contexts work in Ruby. We'll begin by creating a simplified Plan class that holds basic plan information. Then, we'll demonstrate how to consume and wrap a Plan object between the two contexts.
# Plan class in the Plan Management context
module PlanManagement
class Plan
attr_reader :id, :name, :price
def initialize(id, name, price)
@id = id
@name = name
@price = price
end
def update_price(new_price)
@price = new_price
end
end
end
# Plan class in the Sales context
module Sales
class Plan
attr_reader :customer, :plan_dto
def initialize(customer, plan_dto)
@customer = customer
@plan_dto = plan_dto
end
def calculate_discount
(customer.credit / plan_dto.price) * 100
end
def name
plan_dto.name.upcase
end
def price
plan_dto.price - customer.credit
end
end
end
In this example, we have two classes defined in different contexts, the Plan class in the Plan Management context and the Plan in the Sales context. Each class is tailored to its respective context's needs.
To maintain the separation between the contexts and ensure smooth communication, we need to wrap Plan objects when transitioning between contexts. Let's illustrate how this can be done:
# Plan Management context
plan = PlanManagement::Plan.new(1, "Basic Plan", 10.0)
# Sales context
customer = Customer.new("John Doe")
sales_plan = Sales::Plan.new(customer, plan)
# Example usage in the Sales context
discount = sales_plan.calculate_discount
puts "Customer #{customer.name} gets a discount of #{discount}% on the #{sales_plan.name} plan."
puts "Plan details:"
puts "Name: #{sales_plan.name}"
puts "Price: $#{sales_plan.price}"
In this example, the Sales::Plan
class provides a bridge between the Sales context and the Plan Management context. It wraps the Plan object from the Plan Management context and exposes only the methods relevant to the Sales context, such as calculating discounts based on a customer's profile.
Conclusion
By defining boundaries around different domain models and using wrapper classes when transitioning between contexts, we can maintain consistency, reduce conflicts, and promote a better understanding of how other parts of the system interact. In our Ruby example, we've demonstrated how bounded contexts can be applied to a Plan object, showcasing the practical benefits of this concept in real-world software development.
References
Domain-Driven Design: Tackling Complexity in the Heart of Software by Eric Evans This book is often considered the authoritative source on Domain-Driven Design (DDD) and introduces the concept of bounded contexts along with various other DDD principles.
Bounded Context - Martin Fowler's blog is a valuable resource for software design patterns and concepts. His article on bounded contexts provides a comprehensive explanation with examples.
Link: https://martinfowler.com/bliki/BoundedContext.html
Top comments (0)