Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 17

Lab Session 3 Software Design Architecture

Domain-Driven Design (DDD) is an approach to software development that emphasizes


understanding the business domain and modeling it in software in a way that closely aligns with the
domain itself. DDD principles guide developers in creating software that reflects the complexity of real-
world domains. Here are some key principles of DDD:

Ubiquitous Language: DDD encourages the use of a common language that is shared by all members
of the development team and stakeholders. This language should be based on domain concepts and
should be used consistently in discussions, code, and documentation. Having a ubiquitous language
helps bridge the gap between technical and non-technical stakeholders and ensures a shared
understanding of the domain.

Bounded Contexts: A bounded context is a boundary within which a particular model or language is
defined and applicable. Different parts of a system may have different models and terminology, and
bounded contexts help to manage this complexity by clearly defining the scope and meaning of terms
within a specific context. Bounded contexts help prevent ambiguity and ensure that models are
consistent within their respective contexts.

Domain Model: The domain model represents the essential concepts and rules of the business
domain. It captures the core entities, their attributes, and the relationships between them. The domain
model is expressed in code and should closely resemble the mental model of domain experts. By
focusing on the domain model, developers can build software that directly reflects the underlying
business domain.

Explicit Contextual Boundaries: DDD emphasizes the importance of clearly defining the boundaries
between different parts of the system. This includes not only bounded contexts but also other types of
boundaries such as modules, aggregates, and services. Explicit boundaries help to manage complexity,
enable independent development and deployment, and support scalability and maintainability.

Continuous Collaboration with Domain Experts: DDD advocates for ongoing collaboration between
developers and domain experts throughout the development process. Domain experts provide valuable
insights into the business domain, helping developers to better understand the problem space and
refine the domain model. Continuous collaboration ensures that the software accurately reflects the
needs of the business and enables developers to respond effectively to changing requirements.

Focus on Core Domain: The core domain represents the most critical and differentiating aspects of
the business. DDD suggests focusing development efforts primarily on the core domain, where the

1|Page
Lab Session 3 Software Design Architecture

greatest business value lies. Non-core domains, sometimes referred to as generic


or supporting domains, can be implemented using existing libraries or frameworks, freeing up resources
to focus on the core domain.

Strategic Design: DDD involves strategic design decisions that shape the overall architecture of the
system. This includes identifying key domain concepts, defining bounded contexts, and designing
aggregate roots and repositories. Strategic design decisions should be based on an understanding of the
business goals and requirements and should support long-term flexibility and maintainability.

Ubiquitous Language:

Definition:

Ubiquitous Language is a central concept in Domain-Driven Design (DDD), referring to a common, shared
language that is used consistently across all aspects of a software project. This language consists of
domain-specific terms and concepts that are understood by all members of the development team,
including domain experts, developers, testers, and stakeholders.

Example:

public class Account {

private String accountNumber;

private String customerName;

private double balance;

public Account(String accountNumber, String customerName) {

this.accountNumber = accountNumber;

this.customerName = customerName;

this.balance = 0;

public void deposit(double amount) {

balance += amount;

System.out.println("Deposited " + amount + " into account " + accountNumber + ". New balance: " +
balance);

2|Page
Lab Session 3 Software Design Architecture

public void withdraw(double amount) {

if (amount <= balance) {

balance -= amount;

System.out.println("Withdrew " + amount + " from account " + accountNumber + ". New balance:
" + balance);

} else {

System.out.println("Insufficient funds.");

public void checkBalance() {

System.out.println("Balance in account " + accountNumber + ": " + balance);

public static void main(String[] args) {

// Creating accounts

Account account1 = new Account("123456", "Alice");

Account account2 = new Account("789012", "Bob");

// Depositing money

account1.deposit(1000);

account2.deposit(500);

// Withdrawing money

account1.withdraw(200);

account2.withdraw(1000); // Trying to withdraw more than the balance

// Checking balances

3|Page
Lab Session 3 Software Design Architecture

account1.checkBalance();

account2.checkBalance();

Bounded Contexts:

In Domain-Driven Design (DDD), a Bounded Context is a specific boundary within which a particular
model or language is defined and applicable. It represents a distinct area of the business domain with its
own concepts, terms, and rules. Bounded Contexts help manage the complexity of large-scale systems
by providing clear boundaries between different parts of the domain and by ensuring that models are
consistent and coherent within their respective contexts.

Role in Managing Complexity:

1. Isolation of Concepts: By defining boundaries around different areas of the domain, Bounded
Contexts isolate concepts and prevent them from interfering with each other. This isolation
simplifies the understanding and maintenance of the system, as developers can focus on one
area of the domain at a time without being overwhelmed by unrelated details.

2. Clear Communication: Bounded Contexts facilitate clear communication between development


teams and domain experts by establishing a common understanding of the domain within each
context. Teams can use domain-specific terminology without ambiguity, leading to more
effective collaboration and reduced risk of misunderstandings.

3. Flexible Evolution: Bounded Contexts allow different parts of the system to evolve
independently, as changes within one context are less likely to impact other contexts. This
flexibility enables teams to iterate on specific areas of the domain without requiring extensive
changes across the entire system, resulting in faster development cycles and reduced risk of
regression.

// Order Management Bounded Context

class Order {

private String orderId;

private String customerId;

private List<String> products;

4|Page
Lab Session 3 Software Design Architecture

private String status;

public Order(String orderId, String customerId, List<String> products) {

this.orderId = orderId;

this.customerId = customerId;

this.products = products;

this.status = "Pending";

public void processOrder() {

// Simulate order processing logic

this.status = "Processed";

System.out.println("Order " + orderId + " processed successfully.");

public void cancelOrder() {

// Simulate order cancellation logic

this.status = "Cancelled";

System.out.println("Order " + orderId + " cancelled.");

// Inventory Management Bounded Context

class Product {

private String productId;

private String name;

private double price;

private int quantity;

5|Page
Lab Session 3 Software Design Architecture

public Product(String productId, String name, double price, int quantity) {

this.productId = productId;

this.name = name;

this.price = price;

this.quantity = quantity;

public void updateQuantity(int newQuantity) {

// Simulate updating product quantity in inventory

this.quantity = newQuantity;

System.out.println("Quantity of product " + productId + " updated to " + quantity + ".");

public void checkAvailability() {

// Simulate checking product availability

if (quantity > 0) {

System.out.println("Product " + productId + " is available.");

} else {

System.out.println("Product " + productId + " is out of stock.");

// Example usage

public class Main {

public static void main(String[] args) {

// Order Management context

Order order1 = new Order("123", "456", Arrays.asList("ABC", "DEF"));

order1.processOrder();

6|Page
Lab Session 3 Software Design Architecture

// Inventory Management context

Product product1 = new Product("ABC", "Product 1", 10, 20);

product1.checkAvailability();

product1.updateQuantity(15);

product1.checkAvailability();

 The Order class represents orders within the "Order Management" Bounded Context. It includes
methods for processing and cancelling orders.
 The Product class represents products within the "Inventory Management" Bounded Context. It
includes methods for updating product quantity and checking availability.
 Each Bounded Context encapsulates its own set of concepts and rules related to its specific area
of functionality.

The code demonstrates how different parts of the system can operate independently within their
respective contexts. For example, processing an order in the "Order Management" context does not
directly affect the availability of products in the "Inventory Management" context. This separation of
concerns helps manage complexity and enables teams to work on different aspects of the system
independently, ensuring clarity and coherence within each Bounded Context.

Domain Model and its Components:


In Domain-Driven Design (DDD), the domain model represents the essential concepts and rules of the
business domain. It provides a structured representation of the domain's key entities, their attributes,
relationships, and behaviors. The domain model is expressed in code and serves as the foundation for
developing software that closely aligns with the business domain.

Components of the Domain Model:

1. Entities: Entities are objects with unique identities that have a distinct lifecycle within the
domain. They are typically nouns and represent core business concepts that have a long-term
existence. Entities are characterized by their identity, state, and behavior. For example, in an e-
commerce system, a Product entity represents a tangible item that can be bought and sold.

7|Page
Lab Session 3 Software Design Architecture

2. Value Objects: Value objects are objects that represent concepts that are
defined by their attributes rather than their identity. They are immutable and are often used to
encapsulate concepts that are part of a larger entity. Value objects do not have an identity of
their own and are compared based on the equality of their attributes. For example, in the same
e-commerce system, a Price value object represents the price of a product and consists of
attributes such as currency and amount.

3. Aggregates: Aggregates are clusters of related objects that are treated as a single unit for the
purpose of data consistency and transactional boundaries. Each aggregate has a root entity,
known as the aggregate root, which serves as the entry point for accessing and modifying the
aggregate's internal objects. Aggregates ensure that the integrity of the domain model is
maintained by encapsulating complex business rules and ensuring consistency across related
objects. For example, in the e-commerce system, an Order aggregate may consist of multiple
line items, with the Order entity serving as the aggregate root.

How to Develop a Domain Model that Accurately Reflects the Business Domain:

Domain-Driven Design Workshops: Conduct workshops with domain experts to gain a deep
understanding of the business domain, identify key concepts, and define relationships between them.
Collaborate closely with domain experts to refine the domain model iteratively based on their feedback
and insights.

 Ubiquitous Language: Use a ubiquitous language to capture domain concepts and terminology
in the code. Ensure that the language used in the domain model aligns closely with the language
used by domain experts and stakeholders. This facilitates communication and ensures that the
domain model accurately reflects the business domain.

 Start Simple and Iterate: Begin by identifying the core entities and value objects in the domain
and modeling them in code. Start with a simple representation of the domain model and iterate
on it based on evolving requirements and feedback from stakeholders. Refine the domain model
over time to capture additional complexities and edge cases as they arise.

 Focus on Business Rules: Identify and encapsulate core business rules within the domain model
to ensure that the software accurately reflects the behavior of the business domain. Use domain
events, validations, and constraints to enforce business rules and maintain data integrity within
the domain model.

8|Page
Lab Session 3 Software Design Architecture

 Test-Driven Development (TDD): Use Test-Driven Development (TDD) to


validate the behavior of the domain model and ensure that it meets the requirements of the
business domain. Write tests that verify the expected behavior of entities, value objects, and
aggregates, and use them as a feedback mechanism to refine the domain model iteratively.

import java.time.LocalDateTime;

import java.util.ArrayList;

import java.util.List;

// Entities

class Product {

private int productId;

private String name;

private Price price;

public Product(int productId, String name, Price price) {

this.productId = productId;

this.name = name;

this.price = price;

// Getters and setters

class Order {

private int orderId;

private int customerId;

private LocalDateTime orderDate;

private List<LineItem> lineItems;

9|Page
Lab Session 3 Software Design Architecture

public Order(int orderId, int customerId) {

this.orderId = orderId;

this.customerId = customerId;

this.orderDate = LocalDateTime.now();

this.lineItems = new ArrayList<>();

public void addLineItem(Product product, int quantity) {

lineItems.add(new LineItem(product, quantity));

// Getters and setters

// Value Objects

class Price {

private double amount;

private String currency;

public Price(double amount, String currency) {

this.amount = amount;

this.currency = currency;

// Getters and setters

class LineItem {

private Product product;

10 | P a g e
Lab Session 3 Software Design Architecture

private int quantity;

private Price totalPrice;

public LineItem(Product product, int quantity) {

this.product = product;

this.quantity = quantity;

this.totalPrice = new Price(product.getPrice().getAmount() * quantity,


product.getPrice().getCurrency());

// Getters and setters

// Aggregate

class ShoppingCart {

private int customerId;

private List<LineItem> items;

public ShoppingCart(int customerId) {

this.customerId = customerId;

this.items = new ArrayList<>();

public void addItem(Product product, int quantity) {

items.add(new LineItem(product, quantity));

public void removeItem(Product product) {

items.removeIf(item -> item.getProduct().equals(product));

11 | P a g e
Lab Session 3 Software Design Architecture

public Price calculateTotalPrice() {

double totalPrice = 0;

for (LineItem item : items) {

totalPrice += item.getTotalPrice().getAmount();

return new Price(totalPrice, "USD");

// Getters and setters

// Example Usage

public class Main {

public static void main(String[] args) {

// Create products

Product product1 = new Product(1, "Laptop", new Price(1000, "USD"));

Product product2 = new Product(2, "Phone", new Price(500, "USD"));

// Create an order

Order order = new Order(123, 456);

order.addLineItem(product1, 2);

order.addLineItem(product2, 1);

// Create a shopping cart

ShoppingCart cart = new ShoppingCart(456);

cart.addItem(product1, 1);

cart.addItem(product2, 1);

12 | P a g e
Lab Session 3 Software Design Architecture

// Calculate total price

Price totalPrice = cart.calculateTotalPrice();

System.out.println("Total price of items in the shopping cart: " + totalPrice.getAmount() + " " +
totalPrice.getCurrency());

We have entities such as Product and Order, representing core business concepts.

 Value objects like Price are used to encapsulate concepts defined by their attributes.
 The LineItem class represents line items in an order or shopping cart.
 The ShoppingCart class serves as an aggregate root, encapsulating line items within a shopping
cart.
 We demonstrate creating products, adding line items to orders and shopping carts, and
calculating the total price of items in a shopping cart.

Explicit Contextual Boundaries:

Discussion on Different Types of Boundaries:

 Bounded Contexts: Bounded contexts define the scope within which a particular model or
language is defined and applicable. They represent distinct areas of the business domain with
their own concepts, terms, and rules. Bounded contexts help manage complexity by providing
clear boundaries between different parts of the domain and ensure that models are consistent
within their respective contexts.

 Modules: Modules are units of organization within a software system that encapsulate related
functionality and data. They help modularize the codebase, improve maintainability, and
facilitate reuse. Modules can be defined based on functional boundaries, such as user interface,
business logic, and data access layers.

 Aggregates: Aggregates are clusters of related objects that are treated as a single unit for the
purpose of data consistency and transactional boundaries. Each aggregate has a root entity,
known as the aggregate root, which serves as the entry point for accessing and modifying the
aggregate's internal objects. Aggregates ensure that the integrity of the domain model is

13 | P a g e
Lab Session 3 Software Design Architecture

maintained by encapsulating complex business rules and ensuring


consistency across related objects.

• Importance of clearly defining boundaries in software design.

Clearly defined boundaries in software design are essential for managing complexity,
encapsulating implementation details, promoting modularity and reusability, enabling scalability
and performance optimizations, and fostering collaboration and communication within
development teams. They simplify understanding, maintenance, and evolution of the software,
reduce dependencies, facilitate easier modification and extension, and promote code
maintainability. Additionally, well-defined boundaries allow for parallel development,
deployment, and scaling, leading to better resource utilization and improved system
performance. Finally, they provide a shared understanding of the system's structure and
functionality, fostering effective teamwork and alignment with project goals and objectives

Example:

// Module: Product Management

class Product {

private String name;

private double price;

public Product(String name, double price) {

this.name = name;

this.price = price;

public void displayInfo() {

System.out.println("Product: " + name + ", Price: $" + price);

// Module: Order Management

import java.util.ArrayList;

import java.util.List;

14 | P a g e
Lab Session 3 Software Design Architecture

class Order {

private String customerName;

private List<Product> products;

public Order(String customerName) {

this.customerName = customerName;

this.products = new ArrayList<>();

public void addProduct(Product product) {

products.add(product);

public void displayOrder() {

System.out.println("Order for " + customerName + ":");

for (Product product : products) {

product.displayInfo();

// Application

public class Main {

public static void main(String[] args) {

// Product Management

Product laptop = new Product("Laptop", 1000);

Product phone = new Product("Phone", 500);

15 | P a g e
Lab Session 3 Software Design Architecture

// Order Management

Order order = new Order("John");

order.addProduct(laptop);

order.addProduct(phone);

// Display Order

order.displayOrder();

 There are two modules: Product Management and Order Management.


 Each module encapsulates related functionality (Product and Order classes) and hides
implementation details.
 The Product class defines products with attributes like name and price, while the Order class
manages orders for customers.
 By clearly defining boundaries between modules, we promote modularity and encapsulation.
Changes to one module won't impact the other, making the code easier to maintain and extend.
 The if __name__ == "__main__": block serves as a boundary between application startup logic
and module implementations.

Exercise Questions:
1. Define a set of domain concepts and terminology that will form the ubiquitous language for your
e-commerce platform. Include terms related to products, orders, customers, and any other
relevant domain concepts.

2. Identify and define at least two bounded contexts within your e-commerce platform. Describe
the scope and purpose of each bounded context, along with the domain concepts and
terminology specific to each context.

16 | P a g e
Lab Session 3 Software Design Architecture

3. Develop a simple domain model for the core functionality of the e-


commerce platform. This should include entities, value objects, and relationships between
them. Use the ubiquitous language defined earlier to ensure consistency and clarity in your
domain model.

4. Define explicit contextual boundaries between different parts of your system, including
bounded contexts, modules, aggregates, and services. Explain why each boundary is necessary
and how it helps manage complexity and promote modularity.

5. Describe strategies for ensuring continuous collaboration with domain experts throughout the
development process. How will you involve domain experts in refining requirements, validating
the domain model, and providing feedback on the evolving software solution?

17 | P a g e

You might also like