Design Patterns & Software Architecture #

Every engineer who has written code for a while has hit the same moments: looking back at code written six months ago and not understanding it. Or trying to add a small feature that turns out to require changes in ten different places. Or debating a design with teammates where everyone pictures a different solution to the same problem. These issues are not about technical skill — they are about lacking a shared language and framework for talking about code structure. Design patterns and software architecture fill that gap: not as magic recipes, but as vocabulary and a way of thinking that lets you design systems that last.

Goals of This Website #

Many design pattern resources jump straight to implementation code without explaining why a pattern exists and when it is the right fit. The result is that patterns get memorized rather than used as a thinking tool. This website takes a different approach.

Every topic is explored from its root problem: what problem gave rise to this pattern, how the naive solution fails, and why the pattern is the better answer. Implementation is present as proof of concept, not as the main goal.

There are four outcomes we want for every reader:

flowchart LR
    A[Read\\nThis Website] --> B[Understand\\nWhy Patterns Exist]
    B --> C[Recognize\\nWhen a Pattern Fits]
    C --> D[Build a\\nDesign Mental Model]
    D --> E[Design Systems\\nThat Last]

Understand why — Patterns are not trivia. Every pattern was born from real experience dealing with a recurring problem. Understanding the context in which it emerged matters far more than memorizing its name.

Recognize when — The right pattern in the wrong situation is more dangerous than no pattern at all. You need to know when to use a pattern and when not to.

Build a mental model — The most valuable thing about learning design patterns is not the list of patterns you memorize, but how your thinking changes when you face a new design problem.

Design systems that last — Good code is not code that works today; it is code that can still be extended, tested, and understood six months from now.


What Is a Design Pattern? #

A design pattern is a solution template for recurring design problems in software development. The concept was popularized by the book Design Patterns: Elements of Reusable Object-Oriented Software (1994) by the Gang of Four — Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides — which documented 23 patterns drawn from years of experience building real systems.

One thing to understand from the start: a pattern is not a piece of copy-pasteable code. A pattern describes structure, relationships between components, and collaboration flows — something you then implement according to your language and project context.

Pattern vs Framework vs Library #

These three concepts are often mixed up, even though they occupy different positions:

ConceptWhat It IsExamples
Design PatternConceptual solution template for recurring design problemsSingleton, Observer, Strategy
FrameworkApplication skeleton that dictates the execution flow; you fill in its “slots”Spring, Django, Laravel, Go Fiber
LibraryA collection of functions/classes you call as needednet/http, lodash, requests

Frameworks often implement patterns internally. Spring uses Singleton for its beans. Angular uses Observer for reactive data flow. Understanding patterns helps you understand why a framework is designed the way it is — not just how to use it.

The Over-Engineering Risk #

A pattern is a tool, not a goal. One of the most common traps is applying a pattern because it “feels more professional”, not because there is a real problem to solve.

flowchart TD
    M[Facing a Problem] --> A{Does this problem\\nactually exist right now?}
    A -- No --> B[Write simple code\\nRefactor later if needed]
    A -- Yes --> C{Is this a\\nrecurring problem?}
    C -- No --> D[Targeted ad-hoc\\nsolution]
    C -- Yes --> E{Is the pattern's\\ncomplexity worth\\nthe benefit?}
    E -- No --> D
    E -- Yes --> F[Apply the\\nRight Pattern]

“Premature optimization is the root of all evil” applies to patterns too. Apply a pattern when the problem is real — not in anticipation of problems that may never arrive.


Learning Roadmap #

The material on this website is organized into nine major groups, from the most basic foundations to system-level architecture decisions. Each group builds understanding for the next.

flowchart TD
    subgraph Fondasi[Foundations]
        A[1. Introduction\\nto Design Patterns]
    end

    subgraph OOP["Object-Based Patterns"]
        B[2. Creational\\nPatterns]
        C[3. Structural\\nPatterns]
        D[4. Behavioral\\nPatterns]
    end

    subgraph Sistem["System-Level Patterns"]
        E[5. Concurrency\\nPatterns]
        F[6. Data Access &\\nMessaging Patterns]
        G[7. Resource & Lifetime\\nManagement]
    end

    subgraph Modern["Modern Patterns"]
        H[8. Functional &\\nModern Code Patterns]
    end

    subgraph Arsitektur["Software Architecture"]
        I[9. Software\\nArchitecture Patterns]
    end

    Fondasi --> OOP
    OOP --> Sistem
    Sistem --> Modern
    Modern --> Arsitektur

Creational Patterns #

Creational patterns focus on how objects are created — in a controlled, flexible way that does not burden the system’s dependencies. The problems that appear without these patterns: object construction scattered across the codebase, hard to swap when requirements change, and complicated testing due to hard-coded dependencies.

PatternProblem It Solves
SingletonEnsures only one instance exists for a shared resource (config, connection pool)
Factory MethodSeparates object creation from its use so the object type can be swapped
Abstract FactoryGroups the creation of related object families
BuilderSimplifies constructing complex objects with many optional parameters
PrototypeCreates new objects by copying an existing instance

Structural Patterns #

Structural patterns help organize relationships between objects and components. When two incompatible systems must work together, or when you want to add features to an object without modifying its original code, structural patterns provide the answer.

PatternProblem It Solves
AdapterConnects two incompatible interfaces
BridgeSeparates abstraction from implementation so each can evolve independently
CompositeTreats individual objects and collections of objects uniformly
DecoratorAdds behavior to objects dynamically without modifying the original class
FacadeProvides a simple interface on top of a complex subsystem
FlyweightReduces memory usage by sharing identical data across many objects
ProxyControls access to an object for security, caching, or lazy loading

Behavioral Patterns #

Behavioral patterns govern how objects communicate and share responsibility. Many complex logic bugs are rooted in unstructured inter-object communication — behavioral patterns help make it explicit and predictable.

PatternProblem It Solves
StrategySwaps algorithms dynamically without changing client code
ObserverSpreads state changes to many objects in a loosely coupled way
CommandWraps an action as an object to support undo, logging, queuing
Chain of ResponsibilityDistributes requests through a chain of handlers
StateChanges an object’s behavior based on internal state without nested if-else
Template MethodDefines an algorithm skeleton and delegates details to subclasses
MediatorCentralizes communication between objects to reduce coupling
MementoSaves and restores an object’s state without breaking encapsulation
IteratorProvides a standard way to traverse collections without exposing their structure
VisitorAdds operations to an object structure without modifying its classes
InterpreterDefines a grammar for a simple language and executes it

Concurrency Patterns #

Concurrency patterns help manage parallel execution safely and efficiently. This is one of the hardest areas in software engineering — concurrency bugs are non-deterministic, hard to reproduce, and potentially very damaging in production.

PatternProblem It Solves
Thread Pool / Worker PoolControls the amount of parallel execution so resources are not overwhelmed
Producer–ConsumerSeparates data production from consumption with a queue as buffer
Future / PromiseRepresents the result of an async computation that has not finished yet
Async CallbackHandles async operation results without blocking the thread
Fork–JoinSplits a large task into parallel subtasks and merges the results
Read–Write LockOptimizes concurrent access by distinguishing reads from writes
Double-Checked LockingInitializes a singleton lazily and thread-safely
Immutable ObjectPrevents race conditions with objects that cannot be changed
Guarded SuspensionDelays execution until a precondition is met

Software Architecture Patterns #

Architecture patterns operate at a higher level than design patterns — not about how one class interacts with another, but about how the whole system is divided into large components and how those components communicate.

PatternProblem It Solves
Layered ArchitectureSeparates the system into clear layers of responsibility
Clean ArchitectureKeeps business logic independent of frameworks and technologies
Hexagonal ArchitectureDomain at the center with ports and adapters as the boundary
Onion ArchitectureLayered dependencies that all point toward the domain
Domain-Driven DesignModels the system based on business language and needs
Modular MonolithA structured monolith with firm module boundaries
MicroservicesSmall independent services that can be developed and deployed separately
Event-Driven ArchitectureEvents as the primary communication mechanism of the system
CQRSSeparate read and write models for high scale and complexity
Serverless ArchitectureInfrastructure management handed over to the cloud platform
MVC / MVP / MVVMSeparation of concerns for UI-based applications

Who Is This Website For? #

This website is designed for a broad range of readers, but with different depths depending on your background:

flowchart TD
    subgraph Junior["Junior Engineer (1-2 years)"]
        J["Focus: Creational, Structural, Behavioral\\nGoal: Build good design habits from day one"]
    end

    subgraph Mid["Mid-Level Engineer (3-5 years)"]
        M["Focus: Concurrency, Data Access, basic Architecture\\nGoal: Understand trade-offs and when NOT to use a pattern"]
    end

    subgraph Senior["Senior / Tech Lead (5+ years)"]
        S["Focus: Architecture Patterns, DDD, scale trade-offs\\nGoal: Use as a reference when designing large systems"]
    end

    Junior --> Mid --> Senior

Every level can start from whichever section is relevant to the problem at hand — there is no need to go through everything in order.


How to Use This Website #

There are two recommended ways to read, depending on your goal:

Read sequentially if you are new to design patterns or want to build a systematic understanding. Start from the Introduction and follow the order from Creational to Architecture. Each section builds the foundation for the next.

Read by problem if you are experienced and facing a specific design problem. Use the pattern lists above as a reference — identify your problem, find the relevant pattern, and jump straight to that section.

Things to keep in mind while reading:

How to read properly:
  ✓ Read the "why" explanation before the implementation
  ✓ Note when a pattern is NOT the right fit
  ✓ Connect it with problems you have faced before
  ✓ Use it as a reference while designing, not as a checklist

What to avoid:
  ✗ Memorizing pattern names without understanding the context
  ✗ Applying a pattern because it "feels professional"
  ✗ Skipping the anti-pattern sections and when-not-to-use guidance
  ✗ Reading without connecting it to real systems

Relationships Between Patterns #

One of the interesting things about design patterns is that they do not stand alone — many complement each other, and some are frequently used together as natural pairs.

flowchart LR
    subgraph Creational
        Factory[Factory Method]
        Builder
        Singleton
    end

    subgraph Behavioral
        Strategy
        Observer
        Command
    end

    subgraph Structural
        Decorator
        Proxy
        Adapter
    end

    Factory -- "often paired with" --> Strategy
    Observer -- "used together with" --> Command
    Proxy -- "can act as" --> Decorator
    Builder -- "builds objects for" --> Strategy
    Singleton -- "often becomes" --> Factory

Some combinations frequently found in real systems:

CombinationCommon Context
Factory + StrategySelecting and creating the right algorithm implementation at runtime
Observer + CommandEvent systems where every event is an undoable Command
Decorator + ProxyMiddleware chains that add behavior while controlling access
Builder + SingletonA builder creating the single config object instance
Repository + Unit of WorkTransactional, consistent data access

Summary #

  • A design pattern is a solution template for recurring design problems — not ready-made code, but a pattern of structure and collaboration between components.
  • Why before how — understanding the context in which a pattern emerged matters far more than memorizing its implementation.
  • Nine material groups — Creational, Structural, Behavioral, Concurrency, Data Access & Messaging, Resource Management, Functional, and Architecture Patterns — arranged from OOP foundations to system-scale decisions.
  • A pattern is not a goal — over-engineering with an unnecessary pattern is more dangerous than using none at all. Apply it when the problem is real.
  • Pattern vs Framework vs Library — frameworks implement patterns internally; understanding patterns helps you understand why a framework is designed the way it is.
  • Patterns are interrelated — many are used together as natural pairs: Factory + Strategy, Observer + Command, Repository + Unit of Work.
  • Read according to context — go sequentially if you are new to patterns, or jump straight to the section relevant to the problem you are facing.
  • The mental model is the real goal — the most valuable thing is not the list of patterns you memorize, but how your thinking changes when facing new design problems.

Next: Singleton →
About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact