Design Patterns and Application Architecture

Hoang Nguyen

February 25, 2025

Agenda

  1. OOP and Principles

  2. Design Patterns

  3. Architecture & Design

  4. Practical Application

Introduction to OOP

Definition: A programming paradigm based on the concept of "objects", which can contain data and code.

Introduction to OOP

Key Principles:

  • Encapsulation: Bundling the data and methods that operate on the data.
  • Abstraction: Hiding complex implementation details and showing only the essential features.
  • Inheritance: Mechanism to create a new class using properties and methods of an existing class.
  • Polymorphism: Ability to present the same interface for different data types.

OOP Anti-patterns

SOLID Principles

  1. Single Responsibility (S)
  2. Open/Closed (O)
  3. Liskov Substitution (L)
  4. Interface Segregation (I)
  5. Dependency Inversion (D)

SOLID Principles

Single Responsibility (S):

  • A class should have only one reason to change
  • Each class should handle one specific functionality
  • Example: Link

SOLID Principles

Open/Closed (O):

  • Software entities should be open for extension but closed for modification
  • Use interfaces and abstract classes to allow extensions
  • Example: Link

SOLID Principles

Liskov Substitution (L):

  • Subtypes must be substitutable for their base types
  • Derived classes must be usable through the base class interface
  • Example: Link

SOLID Principles

Interface Segregation (I):

  • Clients should not be forced to depend on interfaces they don't use
  • Break interfaces into smaller, specific ones
  • Example: Link

SOLID Principles

Dependency Inversion (D):

  • High-level modules should not depend on low-level modules
  • Both should depend on abstractions
  • Example: Link

SOLID Principles

Benefits:

  • Maintainable and scalable code
  • Easier to test and debug
  • More flexible and reusable
  • Reduced coupling between modules

Composition over Inheritance

  • Definition: A design principle that suggests using object composition rather than inheritance for reuse.
  • Benefits:
    • More flexible design
    • Avoids tight coupling
    • Easier to modify at runtime
    • Prevents deep inheritance hierarchies
    • Example: Link

Introduction to Design Patterns

  • Definition of Design Patterns: General repeatable solutions to common problems in software design.
  • Importance: Promote code reuse, better architecture, and efficient communication among developers.

Categories of Design Patterns

  • Creational Patterns
  • Structural Patterns
  • Behavioral Patterns

Creational Patterns

Definition: Creational patterns deal with object creation mechanisms, trying to create objects in a manner suitable to the situation. They help make a system independent of how its objects are created, composed, and represented.

Creational Patterns

Key Characteristics:

  1. Encapsulation: Hide creation logic from client code
  2. Flexibility: Allow system to be independent of how objects are created
  3. Reusability: Promote reuse of object creation code
  4. Complexity Management: Handle complex object creation scenarios

Creational Patterns

Common Creational Patterns:

  • Factory: Creation of objects without specifying the exact class.
  • Abstract Factory: Provides an interface for creating families of related objects.
  • Builder: Separates the construction of a complex object from its representation.
  • Prototype: Creates new objects by cloning an existing object (prototype).
  • Singleton: Ensures a class has only one instance and provides global access to it.

Factory Pattern

  • Purpose: Creates objects without exposing the instantiation logic.
  • Code Example: Link

Factory Pattern

When to Use:

  • Complex/Dynamic Object Creation
  • Decoupling
  • Reusable Creation Logic

Exercise

Complex Document Generation System

Imagine you need to create a system that generates different types of documents (PDF, HTML, Word) with varying content structures like:

- Headers

- Footers

- Main content sections

- Tables

- Images

- Metadata

 

Which pattern can be applied here to initialize a Document object with many configurations?

 

Structural Patterns

Definition: Structural patterns deal with how classes and objects are composed to form larger structures. They help ensure that when parts of a system change, the entire system doesn't need to change.

Structural Patterns

Key Characteristics:

  1. Composition: Focus on how objects and classes can be combined to form larger structures
  2. Relationship Management: Handle relationships between objects effectively
  3. Flexibility: Allow systems to change their composition at runtime
  4. Simplification: Make complex systems easier to manage

Structural Patterns

Common Structural Patterns:

  • Adapter: Allows incompatible interfaces to work together by wrapping an object in an adapter.
  • Composite: Composes objects into tree structures to represent part-whole hierarchies.
  • Proxy: Provides a surrogate or placeholder to control access to an object.
  • Facade: Provides a simplified interface to a complex subsystem.
  • Decorator: Adds new responsibilities to objects dynamically.
  • Flyweight: Reduces the cost of creating and manipulating a large number of similar objects.

Adapter Pattern

  • Purpose: Allows incompatible interfaces to work together by wrapping an object in an adapter to make it compatible with another class.
  • Code Example: Link

Adapter Pattern

When to Use:

  • When you want to use an existing class that doesn't fit your interface
  • When you need to create a reusable class that cooperates with classes that don't share compatible interfaces
  • When you want to create a middle-layer class that serves as a converter between your code and a third-party class

Exercise

Complex Media Conversion System

Imagine you're building a multimedia processing library that supports many methods:

- Convert video formats

- Extract audio

- Generate thumbnails

- Apply filters

- Add watermarks

- Handle metadata

 

How can we reduce the complexity of the use of this library? All a client cares is a simple way to convert video without knowing about many details

Exercise

Imagine you're building a simple document viewer application. Opening and loading document files can be resource-intensive, especially for large files. Additionally, some documents might require special permissions to access.

 

If you load all documents immediately when the application starts, it would be slow and waste memory. You need a way to:

1. Load documents only when the user actually wants to view them

2. Check if the user has permission to view a document before loading it

3. Keep track of which documents are being accessed

 

How can you implement these requirements without changing your existing document handling code?

 

Behavioral Patterns

Definition: Behavioral patterns deal with communication between objects, how objects interact and distribute responsibilities among themselves.

Behavioral Patterns

Key Characteristics:

  1. Communication: Focus on how objects communicate with each other
  2. Responsibility Distribution: Define clear patterns of communication between objects
  3. Loose Coupling: Reduce dependencies between communicating objects
  4. Flexibility: Allow changing behavior at runtime

Behavioral Patterns

Common Behavioral Patterns:

  • Observer: Notifies a group of objects about changes in the state of another object.
  • Strategy: Enables selecting an algorithm's behavior at runtime.
  • Command: Encapsulates actions as objects, allowing parameterization of clients.
  • State: Allows an object to alter its behavior when its internal state changes.
  • Mediator: Reduces coupling between objects by making them communicate via a mediator object.
  • Chain of Responsibility: Passes requests along a chain of handlers until one handles it.

Observer Pattern

  • Purpose: Defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

  • Code Example: Link

Observer pattern

When to Use:

  • Event Handling Systems:

    • GUI frameworks (button clicks, form submissions)

    • System state changes (file system watchers)

    • Real-time data updates (stock prices, sensor readings)

  • Distributed Systems:

    • Message queues

    • Publish/subscribe systems

    • Event-driven architectures

       

Exercise

Payment Processing System

Imagine you're building an e-commerce platform that needs to handle multiple payment methods (Credit Card, PayPal, Cryptocurrency, etc.) with different processing logic for each method.

 

How do we avoid the complexity of the main logic of payment processing with different payment methods like that?

Design patterns anti-patterns

How about the design patterns for complex business/enterprise applications?

Layered Architecture

Layered Architecture

Common Structure:

  • Presentation Layer (UI/API)
  • Application Layer (Services)
  • Domain Layer (Business Logic)
  • Infrastructure Layer (Data Access)
  • Example: Link

Limitations of Layered Architecture

Problems with Scale:

  • Layers become tightly coupled over time
  • Business logic leaks between layers
  • Domain model becomes anemic
  • Changes require updates across all layers
  • Hard to maintain as complexity grows
  • Difficult to enforce boundaries
  • Often leads to "Big Ball of Mud"

Clean Architecture

Definition: A software architecture pattern that emphasizes separation of concerns, organizing code so that it is independent of frameworks, UI, and databases.

Clean Architecture

Clean Architecture

Key Principles:

  • Dependency Rule: Dependencies only point inward
  • Dependency Inversion: High-level modules should not depend on low-level modules. Both should depend on abstractions.
  • Isolation: Business rules isolated from UI and database
  • Testability: The architecture facilitates automated testing by isolating components.

Clean Architecture

Structure:

  1. Entities Layer (Core)
  2. Use Cases Layer
  3. Interface Adapters Layer
  4. Frameworks & Drivers Layer (External)

Clean Architecture

Entities:

  • Contains enterprise-wide business rules and data structures
  • Pure business objects with no dependencies
  • Represents core business concepts (e.g., Customer, Order, Product)
  • Has no knowledge of other layers
  • Most stable layer, changes least frequently
  • Contains validation rules that are universally true for the entity

Clean Architecture

Use Cases Layer:

  • Implements application-specific business rules
  • Orchestrates the flow of data to and from entities

Clean Architecture

Use Cases Layer:

  • Characteristics:
    • One class per use case (e.g., CreateOrderUseCase, UpdateUserProfileUseCase)
    • Independent of UI, database, and external concerns
    • Uses interfaces (ports) to communicate with outer layers
    • Contains input/output boundary interfaces
    • Defines DTOs (Data Transfer Objects) for input/output

Clean Architecture

Use Cases Layer:

  • Responsibilities:
    • Validation of business rules
    • Authorization checks
    • Orchestrating multiple entities
    • Managing transactions

Clean Architecture

Interface Adapters Layer:

  • Converts data between the format most convenient for use cases/entities and the format most convenient for external agencies
  • Contains:
    • Controllers: Handle HTTP requests, CLI commands, or other entry points
    • Presenters: Format data for display (UI, API responses, etc.)
    • Gateways: Abstract interfaces for external services
    • Repositories: Implement data access interfaces defined by use cases

Clean Architecture

Interface Adapters Layer:

  • Characteristics:
    • No business rules
    • Purely technical implementations
    • Implements interfaces defined by inner layers

Clean Architecture

Interface Adapters Layer:

  • Responsibilities:
    • Data format conversion
    • Request/Response handling
    • Input validation
    • Error handling and mapping
    • Database operations
    • External service integration

Clean Architecture

Interface Adapters Layer:

  • Example Components:
    • REST Controllers
    • GraphQL Resolvers
    • Database Repositories
    • External API Clients
    • View Models/DTOs
    • JSON/XML Formatters

Clean Architecture

Frameworks & Drivers Layer:

  • Outermost layer containing frameworks and tools
  • Acts as glue code connecting the application to external world

Clean Architecture

Frameworks & Drivers Layer:

  • Contains:
    • Web Frameworks: Express, Spring, Django, etc.
    • Database Systems: MySQL, MongoDB, PostgreSQL
    • UI Frameworks: React, Angular, Vue
    • External Services: Payment gateways, email services

Clean Architecture

Frameworks & Drivers Layer:

  • Characteristics:
    • Highly volatile and changeable
    • Contains configuration code
    • Minimal business logic
    • Easily replaceable

Clean Architecture

Frameworks & Drivers Layer:

  • Example Components:
    • Web server configuration
    • Database connection setup
    • ORM configurations
    • UI components
    • External API configurations
    • File system operations

Clean Architecture

Benefits:

  • Independent of frameworks
  • Testable business logic
  • Independent of UI
  • Independent of database
  • Independent of external agencies

Clean Architecture

Implementation Example

Clean Architecture

Relation to OOP and SOLID:

  • OOP principles like encapsulation and abstraction support the goals of Clean Architecture
  • Single responsibility, Dependency inversion contributes to design of Clean Architecture

How to design domain model for an enterprise application?

Domain-Driven Design (DDD)

Definition: A software design approach focusing on modeling software to match a domain according to input from domain experts.

Domain-Driven Design (DDD)

Key Concepts:

  1. Ubiquitous Language
  2. Bounded Contexts
  3. Domain Model
  4. Building Blocks
    • Entities: Objects with identity and lifecycle
    • Value Objects: Immutable objects without identity
    • Aggregates: Cluster of associated objects treated as a unit
    • Services: Operations that don't belong to any entity
    • Example: Link

Ubiquitous Language in DDD

Definition:

  • A common, rigorous language between developers and domain experts
  • Shared vocabulary that is used in code, documentation, and conversation
  • Evolves as the team's understanding of the domain grows

Ubiquitous Language in DDD

Characteristics:

  • Precision: Terms have specific, agreed-upon meanings
  • Consistency: Same terms used everywhere in the bounded context
  • Evolution: Language grows and changes with the project
  • Documentation: Captured in code, tests, and documentation

Ubiquitous Language in DDD

 

Implementation:

  • Use domain terms in class names (e.g., OrderConfirmation not ProcessResult)
  • Model methods after business processes (e.g., confirmOrder() not updateStatus())
  • Name variables using domain terminology
  • Document using business language
  • Avoid technical terms in domain logic

Ubiquitous Language in DDD

Benefits:

  • Reduces translation between technical and business concepts
  • Improves communication with domain experts
  • Makes code self-documenting
  • Ensures consistent understanding across team
  • Helps identify domain concepts early

Domain Model in DDD

Definition:

  • A conceptual model of the domain that incorporates both behavior and data
  • The heart of the business software
  • A structured vision of the domain
  • Distillation of shared knowledge

Domain Model in DDD

 

Characteristics:

  • Rich in behavior (not anemic)
  • Encapsulates complex business rules
  • Reflects domain expert's mental model
  • Independent of technical concerns
  • Uses ubiquitous language

Domain Model in DDD

Implementation Guidelines:

  • Keep business rules in the domain model
  • Use value objects for concepts without identity
  • Create rich behavior instead of anemic models
  • Enforce invariants within the model
  • Use domain events for side effects

Domain Model in DDD

Benefits:

  • Captures complex business rules accurately
  • Provides single source of truth for domain logic
  • Makes business rules explicit and testable
  • Reduces bugs in business logic
  • Improves maintainability
  • Facilitates communication with domain experts

Domain Model in DDD

Domain Model in DDD

Domain Model in DDD

Bounded Contexts in DDD

Definition:

  • Explicit boundary within which a domain model exists
  • Defines where specific terms and concepts of Ubiquitous Language apply
  • Separates different parts of a large system

Bounded Contexts in DDD

Characteristics:

  • Each context has its own Ubiquitous Language
  • Same term can mean different things in different contexts
  • Clear boundaries between different parts of the system
  • Independent implementation within each context

Bounded Contexts in DDD

Implementation Strategies:

  • Separate modules or services per context
  • Different database schemas
  • Independent deployment units
  • Context-specific data models
  • Clear interface contracts between contexts

Bounded Contexts in DDD

Benefits

  • Enables different modeling approaches per context
  • Reduces complexity by dividing system
  • Prevents model pollution
  • Clarifies team boundaries
  • Supports microservices architecture

Bounded Contexts in DDD

Clean architecture  anti-patterns

  • Mixing layers
  • Wrong dependencies
  • Framework coupling
  • Business logic leaks
  • Poor boundary control
  • Example: Link

Conclusion

  • OOP promotes structured, maintainable code, and design patterns provide solutions for common design problems.
  • Importance of Clean Architecture and DDD: Combining clean architecture and DDD can create maintainable and testable systems.

Common Pitfalls to Avoid

  • Wrong Abstraction: A wrong abstraction is worse than code duplication
    • Duplicate code is better than the wrong abstraction
    • Wait until you see the pattern emerge from duplication
    • Don't force patterns where they don't fit
  • Over-Engineering: Start simple, add complexity only when needed
    • Don't add flexibility that you don't need yet
    • YAGNI (You Aren't Gonna Need It)

Exercise: Clean Architecture

Design a library management system using Clean Architecture principles. Requirements:

  • Implement core entities (Book, Member, Loan)
  • Create use cases for borrowing/returning books
  • Add interface adapters for web and console interfaces
  • Implement persistence using different databases

References

  • https://refactoring.guru/refactoring
  • https://github.com/iluwatar/java-design-patterns
  • https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html
  • https://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215
  • https://github.com/eliostvs/clean-architecture-delivery-example/tree/master

Q&A

Any Questions?

Object-Oriented Programming and Design Patterns

By Minh Hoàng Nguyễn

Object-Oriented Programming and Design Patterns

  • 41