ЁЯПл The SchoolтА║ЁЯПЫя╕П Software ArchitectureтА║ЁЯЧ║я╕П рдзрдбрд╛ 10 тАФ C4 model: рдХреЕрдореНрдкрд╕рдЪрд╛ рдирдХрд╛рд╢рд╛, рдЗрдорд╛рд░рддреАрдЪрд╛ рдЖрд░рд╛рдЦрдбрд╛, рдордЬрд▓реНрдпрд╛рдЪрд╛ рдирдХрд╛рд╢рд╛ тАФ code рдордзреВрди рдХрд╛рдврд▓реЗрд▓реЗ
ЁЯЦ╝я╕П See the drawing + lab ЁЯПа Course home ЁЯМ┐ Branch on GitHub тЬПя╕П View source
ЁЯЦ╝я╕П рдЖрдХреГрддреА рдЖрдгрд┐ labThe drawing + lab рдкреВрд░реНрдг рдкрд╛рдирд╛рд╡рд░ рдЙрдШрдбрд╛ тЖЧOpen full page тЖЧ

ЁЯЧ║я╕П рдзрдбрд╛ 10 тАФ C4 model: рдХреЕрдореНрдкрд╕рдЪрд╛ рдирдХрд╛рд╢рд╛, рдЗрдорд╛рд░рддреАрдЪрд╛ рдЖрд░рд╛рдЦрдбрд╛, рдордЬрд▓реНрдпрд╛рдЪрд╛ рдирдХрд╛рд╢рд╛ тАФ code рдордзреВрди рдХрд╛рдврд▓реЗрд▓реЗ

ЁЯУН рддреБрдореНрд╣реА рдЗрдереЗ рдЖрд╣рд╛рдд: 12 рдкреИрдХреА рдзрдбрд╛ 10 ┬╖ рдорд╛рдЧрдЪрд╛: lesson-09-fitness-functions ┬╖ рдкреБрдврдЪрд╛: lesson-11-adrs


ЁЯУж рдпрд╛ рдмреНрд░рдБрдЪрдордзреНрдпреЗ рдХрд╛рдп рдЖрд╣реЗ

рдзрдбреЗ 01тАУ09, рдЖрдгрд┐ рдЦрд░реЗ рд╕рд╛рдВрдЧрдгрд╛рд░реЗ documentation. C4 model рдПрдЦрд╛рджреА system рдЪрд╛рд░ zoom levels рд╡рд░ рдХрд╛рдврддреЗ тАФ Context, Containers, Components, Code тАФ рдЬрд╕рд╛ рдХреЕрдореНрдкрд╕рдЪрд╛ рдирдХрд╛рд╢рд╛, рдЗрдорд╛рд░рддреАрдЪрд╛ рдЖрд░рд╛рдЦрдбрд╛, рдордЬрд▓реНрдпрд╛рдЪрд╛ рдирдХрд╛рд╢рд╛ рдЖрдгрд┐ рдПрдХрд╛ рдЦреЛрд▓реАрдЪреА рдорд╛рдВрдбрдгреА. Lab рдПрдХ text C4 model рддрдпрд╛рд░ рдХрд░рддреЗ (Structurizr DSL) рдЬреНрдпрд╛рдЪреЗ component arrows imports рдордзреВрди рдпреЗрддрд╛рдд, рдЖрдгрд┐ drift рд╢реЛрдзрдгреНрдпрд╛рд╕рд╛рдареА рддреЗ рд╣рд╛рддрд╛рдиреЗ рдХрд╛рдврд▓реЗрд▓реНрдпрд╛ wiki diagram рд╢реА рддреБрд▓рдирд╛ рдХрд░рддреЗ. c4_dsl() рдЖрдгрд┐ doc_drift() arch/analyze.py рдордзреНрдпреЗ, c4() arch/demo.py рдордзреНрдпреЗ.

ЁЯзТ 5 рд╡рд░реНрд╖рд╛рдВрдЪреНрдпрд╛ рдореБрд▓рд╛рд▓рд╛ рд╕рдордЬрд╛рд╡рд▓реНрдпрд╛рд╕рд╛рд░рдЦреЗ

рдРрд╢реНрд╡рд░реНрдпрд╛ рдирд╛рд╡рд╛рдЪреА рдирд╡реАрди рд╢рд┐рдХреНрд╖рд┐рдХрд╛ рд╢рд╛рд│реЗрдд рдпреЗрддреЗ. ЁЯзн рддрд┐рд▓рд╛ рд╢рд╛рд│рд╛ рдХрд╢реА рджрд╛рдЦрд╡рд╛рд▓?

рддреБрдореНрд╣реА рдХрдзреАрдЪ рдмрд╛рдХрд╛рдВрдЪреНрдпрд╛ рдорд╛рдВрдбрдгреАрдкрд╛рд╕реВрди рд╕реБрд░реБрд╡рд╛рдд рдХрд░рдгрд╛рд░ рдирд╛рд╣реА. рдЖрдгрд┐ рдЖрдгрдЦреА рдПрдХ рдЧреЛрд╖реНрдЯ: рднрд┐рдВрддреАрд╡рд░рдЪрд╛ рдирдХрд╛рд╢рд╛ рдЬреБрдирд╛ рдЕрд╕реЗрд▓, рддрд░ рддреЛ рдирдХрд╛рд╢рд╛рдЪ рдирд╕рдгреНрдпрд╛рдкреЗрдХреНрд╖рд╛ рд╡рд╛рдИрдЯ тАФ рдРрд╢реНрд╡рд░реНрдпрд╛ рд╕рд░рд│ рднрд┐рдВрддреАрд╡рд░ рдЖрджрд│реЗрд▓. рдореНрд╣рдгреВрди рдХрддрд░рд┐рдирд╛ рдкреНрд░рддреНрдпреЗрдХ рдмрджрд▓рд╛рдирдВрддрд░ рддреЛ рдирдХрд╛рд╢рд╛ рдЗрдорд╛рд░рддреАрддреВрдирдЪ рдЫрд╛рдкрддреЗ.

ЁЯЧ║я╕П рдЖрдХреГрддреА

flowchart TB
    subgraph L1["1 ┬╖ Context (the campus map)"]
      parent["ЁЯСк Parent"] --> school["ЁЯПл School app"]
      staff["ЁЯзСтАНЁЯТ╝ Office staff"] --> school
      school --> mail["тЬЙя╕П Email service (external)"]
    end
    subgraph L2["2 ┬╖ Containers (the building plan)"]
      webapp["Web app (Python)"] --> db[("Database")]
    end
    subgraph L3["3 ┬╖ Components (the floor plan, from the imports)"]
      web["web"] -->|"3"| app["app"]
      app -->|"6"| domain["domain"]
      infra["infra"] -->|"3"| domain
      domain -.->|"1 ┬╖ not on the wiki"| web
    end
    L1 --> L2 --> L3

ЁЯЧ║я╕П рдХрд╛рдврд▓реЗрд▓реА рдЖрдХреГрддреА + рдПрдХ lab: https://school-edh.pages.dev/software-architecture/lesson-diagrams.html#l10

тЭУ рдХрд╛рдп

ЁЯдФ рдХрд╛

рдХрд╛рд░рдг рдмрд╣реБрддреЗрдХ architecture diagrams levels рдорд┐рд╕рд│рддрд╛рдд (class рд╢реЗрдЬрд╛рд░реА database, рддреНрдпрд╛рд╢реЗрдЬрд╛рд░реА рд╡реНрдпрдХреНрддреА), рдЕрд╕реЗ boxes рд╡рд╛рдкрд░рддрд╛рдд рдЬреНрдпрд╛рдВрдирд╛ рдХреЛрдгреАрдЪ рдирд╛рд╡ рджреЗрдК рд╢рдХрдд рдирд╛рд╣реА, рдЖрдгрд┐ рдХрд╛рдврд▓реНрдпрд╛рдирдВрддрд░рдЪреНрдпрд╛ рдЖрдард╡рдбреНрдпрд╛рддрдЪ рдЬреБрдиреЗ рд╣реЛрддрд╛рдд. C4 рдкрд╣рд┐рд▓реНрдпрд╛ рджреЛрди рдЕрдбрдЪрдгреА рдард░рд▓реЗрд▓реНрдпрд╛ zoom levels рдЖрдгрд┐ рдЫреЛрдЯреНрдпрд╛ рд╢рдмреНрджрд╕рдВрдЧреНрд░рд╣рд╛рдиреЗ рд╕реЛрдбрд╡рддреЗ. Component level code рдордзреВрди рддрдпрд╛рд░ рдХрд░рдгреЗ тАФ рдХрд┐рдВрд╡рд╛ CI рдордзреНрдпреЗ рддрдкрд╛рд╕рдгреЗ тАФ рддрд┐рд╕рд░реА рд╕реЛрдбрд╡рддреЗ.

ЁЯФз рдХрд╕реЗ (рдпрд╛ repo рдордзреНрдпреЗ)

arch/analyze.py рдордзрд▓реЗ c4_dsl(g) рдПрдХ Structurizr DSL workspace рд▓рд┐рд╣рд┐рддреЗ: рд▓реЛрдХ, email system, containers рдЖрдгрд┐ рддреНрдпрд╛рдВрдЪреЗ technology рд╣рд╛рддрд╛рдиреЗ рд▓рд┐рд╣рд┐рд▓реЗрд▓реЗ рдЖрд╣реЗрдд (scanner рд▓рд╛ рддреЗ рдХрд│реВ рд╢рдХрдд рдирд╛рд╣реАрдд); components рдореНрд╣рдгрдЬреЗ рдордЬрд▓реЗ рдЖрдгрд┐ component relationships imports рдордзреВрди рдореЛрдЬрд▓реЗ рдЬрд╛рддрд╛рдд (app -> domain "imports (6)"). DOCUMENTED рдордзреНрдпреЗ wiki рдЪрд┐рддреНрд░рд╛рд╡рд░рдЪреЗ arrows рдЖрд╣реЗрдд. doc_drift(g) code рдордзреНрдпреЗ рдЖрд╣реЗрдд рдкрдг рдЪрд┐рддреНрд░рд╛рд╡рд░ рдирд╛рд╣реАрдд рдЕрд╕реЗ arrows, рдЖрдгрд┐ рдЪрд┐рддреНрд░рд╛рд╡рд░ рдЖрд╣реЗрдд рдкрдг code рдордзреНрдпреЗ рдирд╛рд╣реАрдд рдЕрд╕реЗ arrows рдкрд░рдд рдХрд░рддреЗ.

ЁЯзк рдХрд░реВрди рдкрд╛рд╣рд╛

python3 arch/demo.py c4
python3 - <<'EOF'
import sys; sys.path.insert(0, "arch"); from analyze import scan, c4_dsl, doc_drift, DOCUMENTED
g = scan().imports
print(c4_dsl(g))
print("wiki says:", DOCUMENTED)
print("in the code, not on the drawing:", doc_drift(g)[0])
EOF

тЬЕ рддрдкрд╛рд╕рд╛ тАФ рддреБрдореНрд╣рд╛рд▓рд╛ рдХрд╛рдп рджрд┐рд╕рд╛рдпрд▓рд╛ рд╣рд╡реЗ

c4 рд╣реЗ рдЫрд╛рдкрддреЗ:

тФАтФА a C4 model as text (Structurizr DSL), 31 lines тАФ the component arrows come from the code:
   app -> domain "imports (6)"
   app -> infra "imports (1)"
   domain -> infra "imports (1)"
   domain -> web "imports (1)"
   infra -> domain "imports (3)"
   web -> app "imports (3)"
   the wiki drawing is out of date: 3 arrows in the code are not on it: app тЖТ infra, domain тЖТ infra, domain тЖТ web
   after the fixes: 0 drift ┬╖ generate the drawing from the code, or check it in CI

рддреБрдордЪрд╛ snippet рдкреВрд░реНрдг workspace рдЫрд╛рдкрддреЛ тАФ рддреНрдпрд╛рдЪреА рд╕реБрд░реБрд╡рд╛рдд рдЖрдгрд┐ рд╢реЗрд╡рдЯ рдЕрд╕рд╛ рд╣реЛрддреЛ:

workspace "School app" {
  model {
    parent = person "Parent" "Checks report cards and pays fees"
    staff = person "Office staff" "Enrols students"
    mail = softwareSystem "Email service" "Sends welcome mails" "External"
  views {
    systemContext school { include * }
    container school { include * }
    component webapp { include * }
  }
}
wiki says: {'web': ['app'], 'app': ['domain'], 'infra': ['domain'], 'domain': []}
in the code, not on the drawing: [('app', 'infra'), ('domain', 'infra'), ('domain', 'web')]

ЁЯПБ рддреБрдореНрд╣реА рдЖрддреНрддрд╛рдЪ рдХрд╛рдп рд╕рд┐рджреНрдз рдХреЗрд▓реЗ

Wiki рдЪрд┐рддреНрд░ рд╕реНрд╡рдЪреНрдЫ рджреГрд╢реНрдп рджрд╛рдЦрд╡рддреЗ: web тЖТ app тЖТ domain тЖР infra. Code рдордзреНрдпреЗ рдЖрдгрдЦреА рддреАрди arrows рдЖрд╣реЗрдд тАФ app тЖТ infra, domain тЖТ infra рдЖрдгрд┐ domain тЖТ web тАФ рдпрд╛рдЪ рддреНрдпрд╛ рдорд╛рд░реНрдЧрд┐рдХрд╛ рдЬреНрдпрд╛рдВрдирд╛ рдзрдбреЗ 03тАУ04 рдиреЗ рдЙрд▓реНрд▓рдВрдШрдиреЗ рдореНрд╣рдЯрд▓реЗ. Wiki рд╡рд╛рдЪрдгрд╛рд▒реНрдпрд╛ рдирд╡реАрди рд╢рд┐рдХреНрд╖рд┐рдХреЗрд▓рд╛ domain рд╕реНрд╡рдЪреНрдЫ рдЖрд╣реЗ рдЕрд╕реЗ рд╡рд╛рдЯреЗрд▓. рддрдпрд╛рд░ рдХреЗрд▓реЗрд▓реЗ model drift рд╣реЛрдК рд╢рдХрдд рдирд╛рд╣реА, рдХрд╛рд░рдг рддреЗ imports рдордзреВрди рдкреБрдиреНрд╣рд╛ рдмрдирд╡рд▓реЗ рдЬрд╛рддреЗ; рдЖрдгрд┐ fixes рд▓рд╛рдЧреВ рдЭрд╛рд▓реНрдпрд╛рд╡рд░ рдЪрд┐рддреНрд░ рдЖрдгрд┐ code рдЬреБрд│рддрд╛рдд (0 drift). Arrows рд╡рд░рдЪреЗ рдЖрдХрдбреЗ (6, 3, 3, 1) рдордЬрд▓реНрдпрд╛рдВрдордзрд▓реА рдЦрд░реА рд╡рд░реНрджрд│ рдХреБрдареЗ рдЖрд╣реЗ рд╣реЗ рджреЗрдЦреАрд▓ рджрд╛рдЦрд╡рддрд╛рдд.

тЪая╕П рдиреЗрд╣рдореАрдЪреНрдпрд╛ рдЪреБрдХрд╛

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд

рдЦрд▒реНрдпрд╛ machine рд╡рд░ тАФ DSL Structurizr рдиреЗ render рдХрд░рд╛. Lab рдЪрд╛ output workspace.dsl рдореНрд╣рдгреВрди save рдХрд░рд╛ рдЖрдгрд┐ рдореЛрдлрдд Structurizr Lite image рдЪрд╛рд▓рд╡рд╛, рдЬреА diagrams port 8080 рд╡рд░ рджрд╛рдЦрд╡рддреЗ:

python3 -c 'import sys; sys.path.insert(0, "arch"); from analyze import scan, c4_dsl; print(c4_dsl(scan().imports))' > workspace.dsl
docker run -it --rm -p 8080:8080 -v "$PWD":/usr/local/structurizr structurizr/lite

рд╣рд╛рдЪ system context Mermaid рдордзреНрдпреЗ (рддреНрдпрд╛рдЪреЗ C4 diagrams experimental рдореНрд╣рдгреВрди рдЪрд┐рдиреНрд╣рд╛рдВрдХрд┐рдд рдЖрд╣реЗрдд), рдЬреЛ GitHub Markdown рдордзреНрдпреЗрдЪ render рдХрд░рддреЗ:

C4Context
  title School app тАФ system context
  Person(parent, "Parent", "Checks report cards and pays fees")
  System(school, "School app", "Enrolment, marks, fees, timetable")
  System_Ext(mail, "Email service", "Sends welcome mails")
  Rel(parent, school, "Uses", "HTTPS")
  Rel(school, mail, "Sends mail", "SMTP")

Model repo рдордзреНрдпреЗрдЪ рдареЗрд╡рд╛ (рдЙрджрд╛рд╣рд░рдгрд╛рд░реНрде docs/architecture/workspace.dsl), рдЖрдгрд┐ drift check рдзрдбрд╛ 09 рдЪреНрдпрд╛ pipeline рдордзреНрдпреЗ рдЬреЛрдбрд╛, рдореНрд╣рдгрдЬреЗ рдордЬрд▓реНрдпрд╛рдВрдордзрд▓реА рдирд╡реАрди рдорд╛рд░реНрдЧрд┐рдХрд╛ рдЪрд┐рддреНрд░ (рдХрд┐рдВрд╡рд╛ code) рджреБрд░реБрд╕реНрдд рд╣реЛрдИрдкрд░реНрдпрдВрдд fail рд╣реЛрдИрд▓.

ЁЯПн рдкреНрд░рддреНрдпрдХреНрд╖ рд╡рд╛рдкрд░рд╛рдд рд╣реЗ рдХрд╛ рдорд╣рддреНрддреНрд╡рд╛рдЪреЗ: рддреБрдордЪреНрдпрд╛ рдЯреАрдордордзрд▓реНрдпрд╛ рд╕рд░реНрд╡рд╛рдд рдирд╡реАрди рд╕рджрд╕реНрдпрд╛рд▓рд╛ рддреБрдордЪрд╛ architecture diagram рджрд╛рдЦрд╡рд╛ рдЖрдгрд┐ рддреЛ рдХреЛрдгрддрд╛ level рдЖрд╣реЗ рддреЗ рд╡рд┐рдЪрд╛рд░рд╛. рддреНрдпрд╛рдВрдирд╛ рд╕рд╛рдВрдЧрддрд╛ рдЖрд▓реЗ рдирд╛рд╣реА тАФ рдХрд┐рдВрд╡рд╛ рддреЛ code рд╢реА рдЬреБрд│рддреЛ рдпрд╛рдЪреА рддреБрдореНрд╣рд╛рд▓рд╛рдЪ рдЦрд╛рддреНрд░реА рдирд╕реЗрд▓ тАФ рддрд░ рдпрд╛ рдЖрдард╡рдбреНрдпрд╛рдд рдПрдХ level code рдордзреВрди рддрдпрд╛рд░ рдХрд░рд╛.

тПня╕П рдкреБрдвреЗ

рдЪрд┐рддреНрд░реЗ рдЗрдорд╛рд░рдд рдХрд╛рдп рдЖрд╣реЗ рддреЗ рджрд╛рдЦрд╡рддрд╛рдд. рдЬрд┐рдирд╛ рддрд┐рдереЗрдЪ рдХрд╛ рдЖрд╣реЗ рд╣реЗ рддреА рдХрдзреАрдЪ рд╕рд╛рдВрдЧрдд рдирд╛рд╣реАрдд. Architecture decision records рдЖрдгрд┐ trade-off analysis.

git checkout lesson-11-adrs

ЁЯЧ║я╕П Lesson 10 тАФ The C4 model: campus map, building plan, floor plan тАФ drawn from the code

ЁЯУН You are here: Lesson 10 of 12 ┬╖ Previous: lesson-09-fitness-functions ┬╖ Next: lesson-11-adrs


ЁЯУж What's in this branch

Lessons 01тАУ09, plus documentation that tells the truth. The C4 model draws a system at four zoom levels тАФ Context, Containers, Components, Code тАФ like a campus map, a building plan, a floor plan and a room layout. The lab generates a text C4 model (Structurizr DSL) whose component arrows come from the imports, and compares it with the hand-drawn wiki diagram to find drift. c4_dsl() and doc_drift() in arch/analyze.py, c4() in arch/demo.py.

ЁЯзТ Explain like I'm 5

A new teacher, Aishwarya, joins the school. ЁЯзн How do you show her around?

You would never start with the desk layout. And one more thing: if the floor plan on the wall is old, it is worse than no plan тАФ Aishwarya will walk into a wall. So Katrina prints the floor plan from the building itself, every time it changes.

ЁЯЧ║я╕П Diagram

flowchart TB
    subgraph L1["1 ┬╖ Context (the campus map)"]
      parent["ЁЯСк Parent"] --> school["ЁЯПл School app"]
      staff["ЁЯзСтАНЁЯТ╝ Office staff"] --> school
      school --> mail["тЬЙя╕П Email service (external)"]
    end
    subgraph L2["2 ┬╖ Containers (the building plan)"]
      webapp["Web app (Python)"] --> db[("Database")]
    end
    subgraph L3["3 ┬╖ Components (the floor plan, from the imports)"]
      web["web"] -->|"3"| app["app"]
      app -->|"6"| domain["domain"]
      infra["infra"] -->|"3"| domain
      domain -.->|"1 ┬╖ not on the wiki"| web
    end
    L1 --> L2 --> L3

ЁЯЧ║я╕П Drawn version + a lab: https://school-edh.pages.dev/software-architecture/lesson-diagrams.html#l10

тЭУ What

ЁЯдФ Why

Because most architecture diagrams mix levels (a database next to a class next to a person), use boxes nobody can name, and are out of date the week after they are drawn. C4 fixes the first two with fixed zoom levels and a small vocabulary. Generating the component level from the code тАФ or checking it in CI тАФ fixes the third.

ЁЯФз How (in this repo)

c4_dsl(g) in arch/analyze.py writes a Structurizr DSL workspace: the people, the email system, the containers and their technology are written by hand (a scanner cannot know them); the components are the floors and the component relationships are counted from the imports (app -> domain "imports (6)"). DOCUMENTED holds the arrows on the wiki drawing. doc_drift(g) returns the arrows in the code but not on the drawing, and the arrows on the drawing but not in the code.

ЁЯзк Try it

python3 arch/demo.py c4
python3 - <<'EOF'
import sys; sys.path.insert(0, "arch"); from analyze import scan, c4_dsl, doc_drift, DOCUMENTED
g = scan().imports
print(c4_dsl(g))
print("wiki says:", DOCUMENTED)
print("in the code, not on the drawing:", doc_drift(g)[0])
EOF

тЬЕ Verify тАФ what you should see

c4 prints:

тФАтФА a C4 model as text (Structurizr DSL), 31 lines тАФ the component arrows come from the code:
   app -> domain "imports (6)"
   app -> infra "imports (1)"
   domain -> infra "imports (1)"
   domain -> web "imports (1)"
   infra -> domain "imports (3)"
   web -> app "imports (3)"
   the wiki drawing is out of date: 3 arrows in the code are not on it: app тЖТ infra, domain тЖТ infra, domain тЖТ web
   after the fixes: 0 drift ┬╖ generate the drawing from the code, or check it in CI

Your snippet prints the whole workspace тАФ it starts and ends like this:

workspace "School app" {
  model {
    parent = person "Parent" "Checks report cards and pays fees"
    staff = person "Office staff" "Enrols students"
    mail = softwareSystem "Email service" "Sends welcome mails" "External"
  views {
    systemContext school { include * }
    container school { include * }
    component webapp { include * }
  }
}
wiki says: {'web': ['app'], 'app': ['domain'], 'infra': ['domain'], 'domain': []}
in the code, not on the drawing: [('app', 'infra'), ('domain', 'infra'), ('domain', 'web')]

ЁЯПБ What you just proved

The wiki drawing shows a clean picture: web тЖТ app тЖТ domain тЖР infra. The code has three more arrows тАФ app тЖТ infra, domain тЖТ infra and domain тЖТ web тАФ the very corridors lessons 03тАУ04 called violations. A new teacher reading the wiki would believe the domain is clean. The generated model cannot drift, because it is rebuilt from the imports; and once the fixes are applied, the drawing and the code agree (0 drift). The counts on the arrows (6, 3, 3, 1) also show where the real traffic between floors is.

тЪая╕П Common mistakes

ЁЯПн In production

On a real machine тАФ render the DSL with Structurizr. Save the lab's output as workspace.dsl and run the free Structurizr Lite image, which serves the diagrams on port 8080:

python3 -c 'import sys; sys.path.insert(0, "arch"); from analyze import scan, c4_dsl; print(c4_dsl(scan().imports))' > workspace.dsl
docker run -it --rm -p 8080:8080 -v "$PWD":/usr/local/structurizr structurizr/lite

The same system context in Mermaid (its C4 diagrams are marked experimental), which GitHub renders inside Markdown:

C4Context
  title School app тАФ system context
  Person(parent, "Parent", "Checks report cards and pays fees")
  System(school, "School app", "Enrolment, marks, fees, timetable")
  System_Ext(mail, "Email service", "Sends welcome mails")
  Rel(parent, school, "Uses", "HTTPS")
  Rel(school, mail, "Sends mail", "SMTP")

Keep the model in the repo (for example docs/architecture/workspace.dsl), and add the drift check to the lesson 09 pipeline so a new corridor between floors fails until the drawing (or the code) is fixed.

ЁЯПн Why this matters in production: show your team's newest joiner your architecture diagram and ask which level it is. If they cannot tell тАФ or if you are not sure it matches the code тАФ generate one level from the code this week.

тПня╕П Next

The drawings show what the building is. They never say why the staircase is where it is. Architecture decision records and trade-off analysis.

git checkout lesson-11-adrs
тЖР Previousfitness functionsNext тЖТadrs

This page is the lesson's README from the lesson-10-c4 branch, shown here so the whole School stays on one site. Code files open on GitHub at the same branch.