Coding Architecture: SOLID & Clean Design
Coding Architecture: SOLID & Clean Design
Great coding architecture ensures that your codebase is maintainable, testable, and adaptable to change over time.
ποΈ 1. SOLID Principles
The five foundational principles of object-oriented design.
- S: Single Responsibility Principle (SRP): A class should have only one reason to change.
- O: Open/Closed Principle (OCP): Software entities should be open for extension but closed for modification.
- L: Liskov Substitution Principle (LSP): Subclasses should be substitutable for their base classes without breaking the application.
- I: Interface Segregation Principle (ISP): Clients should not be forced to depend on interfaces they do not use.
- D: Dependency Inversion Principle (DIP): Depend on abstractions, not on concretions. High-level modules should not depend on low-level modules.
π 2. Clean Architecture (Hexagonal/Onion)
A layered approach where the Domain (Entities) sits at the center, surrounded by Use Cases, Adapters, and finally External Systems (DB, API, UI).
- The Rule: Dependencies only point inward.
- Benefits: The core business logic is independent of the UI, database, or external frameworks.
π 3. Domain-Driven Design (DDD)
Focus on the core domain and domain logic. It uses a Ubiquitous Language that both technical and non-technical stakeholders understand.
- Aggregate Roots: A cluster of objects treated as a single unit for data changes.
- Value Objects: Objects that are defined by their attributes rather than a unique identity (e.g., Money, Address).
π οΈ 4. Gang of Four (GoF) Patterns: The Complete List
The 23 original patterns are divided into three categories based on their purpose.
Creational Patterns (Object Creation)
| Name | Purpose |
|---|---|
| Factory Method | Define an interface for creating an object, but let subclasses decide which class to instantiate. |
| Abstract Factory | Create families of related objects without specifying their concrete classes. |
| Builder | Construct complex objects step-by-step. |
| Singleton | Ensure a class has only one instance and provides a global access point. |
| Prototype | Copy existing objects without making your code dependent on their classes. |
Structural Patterns (Object Assembly)
| Name | Purpose |
|---|---|
| Adapter | Allow incompatible interfaces to work together (The βBridgeβ between systems). |
| Bridge | Split a large class into two separate hierarchies: Abstraction and Implementation. |
| Composite | Compose objects into tree structures to represent part-whole hierarchies. |
| Decorator | Attach new behaviors to objects by placing them inside wrapper objects. |
| Facade | Provide a simplified interface to a complex library or framework. |
| Flyweight | Share common parts of state between multiple objects to save RAM. |
| Proxy | Provide a substitute or placeholder for another object to control access. |
Behavioral Patterns (Communication)
| Name | Purpose |
|---|---|
| Chain of Responsibility | Pass requests along a chain of handlers. |
| Command | Turn a request into a stand-alone object containing all information about the request. |
| Iterator | Traverse elements of a collection without exposing its underlying representation. |
| Mediator | Restrict direct communications between objects and force them to collaborate via a mediator. |
| Memento | Save and restore the previous state of an object without revealing its implementation. |
| Observer | Define a subscription mechanism to notify multiple objects about events. |
| State | Let an object alter its behavior when its internal state changes. |
| Strategy | Define a family of algorithms and make them interchangeable. |
| Template Method | Define the skeleton of an algorithm in the superclass but let subclasses override steps. |
| Visitor | Separate algorithms from the objects on which they operate. |
| Interpreter | A way to include language elements in a program. |
π‘ Best Practices
- DRY (Donβt Repeat Yourself): Avoid logic duplication across the codebase.
- KISS (Keep It Simple, Stupid): Avoid over-engineering. If a simple solution works, use it.
- YAGNI (You Ainβt Gonna Need It): Donβt add features until they are actually needed.
- TDD (Test-Driven Development): Write tests first to drive the design and ensure reliability.