Skip to content
AyoKoding

Overview

This section provides a code-first approach to learning software architecture through heavily annotated examples in Java, Kotlin, C#, and TypeScript.

What You Will Learn

The examples in this section cover patterns, principles, architectural styles, trade-offs, and real-world architectural decisions across three progressive levels:

  • Beginner: Foundational architectural concepts with simple, self-contained examples
  • Intermediate: Composite patterns and common enterprise architecture challenges
  • Advanced: Complex systems, distributed architecture, and nuanced trade-off analysis

How to Use This Section

Each example is self-contained and annotated to explain not just what the code does, but why each architectural decision was made. Start at the level that matches your current understanding and progress through the examples in order. Each OOP example shares the same number as its FP counterpart in the in-fp-by-example sibling tutorial, enabling cross-paradigm comparison.

Paradigm-Fit Legend

Not every architectural pattern fits every paradigm equally. Many examples carry a Paradigm Note banner explaining whether the pattern is FP-native, OOP-native, or paradigm-neutral. The classification follows authoritative sources:

  • NEUTRAL — paradigm-agnostic concept (microservices, distributed tracing, hexagonal architecture). Both tracks teach legitimately.
  • OOP-NATIVE — pattern emerged from OOP (GoF, DDD, PEAA). Norvig (1996, Design Patterns in Dynamic Languages) classified 16 of 23 GoF patterns as absorbed by FP language features; the OOP track shows the canonical class-based form.
  • OOP-NATIVE-BUT-TRANSFERABLE — OOP roots but the concept transfers cleanly to FP. The paradigm note explains the FP encoding.
  • FP-NATIVE — pattern emerged from or expresses most naturally in FP (Railway-Oriented Programming, Free Monads, Reader/State monads, Event Sourcing fold, FRP, Kleisli composition). OOP encodings approximate these via libraries (Rx for FRP, monad-like result types for ROP); see Examples 86–90 for stub pointers to the FP track.
  • Examples 91–93 are OOP-native extras (Active Record, GRASP, Singleton-with-FP-counterexample) — the FP track carries only stubs for these.

Authority basis: Norvig 1996; Seemann (Design patterns across paradigms, 2012; SOLID: the next step is Functional, 2014); Wlaschin (Domain Modeling Made Functional); Hickey (Simple Made Easy); Evans (Domain-Driven Design); Fowler (PEAA).

Where Go Fits (Partial)

Go has interface satisfaction without inheritance — methods on structs, structural typing, no class hierarchies. Rob Pike (Google SPLASH 2012 keynote: "Go at Google: Language Design in the Service of Software Engineering") explicitly rejected type hierarchies: "Type hierarchies result in brittle code... Go therefore encourages composition over inheritance, using simple, often one-method interfaces." That makes Go a partial fit for this OOP track:

  • Translates one-to-one to Go: SOLID (especially ISP — Go interfaces are tiny by convention), composition over inheritance, dependency injection via constructor functions, Adapter pattern (concrete type satisfies a interface), Decorator pattern (embedding), Strategy / Command pattern (function values or interface values).
  • Does NOT translate to Go: LSP (no subtype hierarchies to substitute against), Template Method (no abstract methods + inheritance), GoF "OOP-NATIVE" patterns that hinge on inheritance hierarchies (Visitor with double dispatch, Bridge, Abstract Factory family hierarchies).
  • Honest path: read this track for patterns that translate, then see in-procedural-by-example for patterns where composition + structural typing + explicit data flow are the design force — that track teaches what only Go and Rust teach (no inheritance assumed; ownership / structural typing as primary mechanism).

Structure of Each Example

Every example follows a consistent five-part format:

  1. Brief Explanation — what the pattern or principle addresses and why it matters (2-3 sentences)
  2. Mermaid Diagram — visual representation of component relationships, layers, or data flow (when appropriate)
  3. Heavily Annotated Code — Java (canonical), Kotlin, C#, and TypeScript implementations with // => comments documenting architectural decisions and trade-offs; language tabs appear where the idiom differs meaningfully
  4. Key Takeaway — the core insight to retain from the example (1-2 sentences)
  5. Why It Matters — production relevance and real-world impact (50-100 words)

Examples by Level

Beginner (Examples 1–28)

Intermediate (Examples 29–57)

Advanced (Examples 58–85)

FP-Native Stubs (Examples 86–90)

Numbering parity with the FP track; full treatment lives there.

OOP-Native Extras (Examples 91–93)

Patterns that exist primarily in OOP because they assume mutable state, identity, and class hierarchies as first-class building blocks.

Last updated March 19, 2026

Command Palette

Search for a command to run...