Software Architecture: Classroom Bootcamp

An eight-hour classroom bootcamp on software architecture, taught on a large system that records why it is built the way it is: Smarter’s thirty-one Architecture Decision Records, on topics from the choice of Django and Kubernetes to caching, task queues and API versioning. The course is organized around the principles that working architects share as a vocabulary, above all The Twelve-Factor App, and alongside it infrastructure as code, horizontal scalability, zero trust, extensibility and explicit data models. Smarter adopts each of these, in code that students can open and read, and ADR 004 makes the twelve factors binding on every pull request. Students diagram the system, check its decisions and principles against the code, argue the alternatives, and write ADRs of their own. See Course Formats and Grading for the standard bootcamp day, the grading scale and the course policies, and Software Architecture for an overview of the subject.

At a Glance

Students

Experienced developers moving toward technical leadership, and advanced computer science students.

Deployment

A clone of the repository is enough. A running Smarter (Quick Start or from source) helps students confirm what they read.

Cost

Free.

Learning Objectives

By the end of the bootcamp, students can:

  1. Explain what architecture is: the decisions that are expensive to change, and the quality attributes that drive them.

  2. Describe a large system at several levels with the C4 model.

  3. Explain each of the twelve factors, and judge from the code whether a system follows it.

  4. Recognize infrastructure as code, horizontal scalability, zero trust, extensibility and explicit data models in a real codebase, and say what each costs.

  5. Trace a request through the classic web patterns, Model-View-Controller, Django’s Model-View-Template and the LAMP stack, and say where a modern system departs from them.

  6. Read an Architecture Decision Record, find the code that implements it, and judge whether they still agree.

  7. Analyze the trade-offs of a decision, including the alternatives that were not chosen, and record a decision of their own as an ADR.

Technical Prerequisites

  • Required: at least two years of programming, or equivalent coursework, in any language.

  • Required: reading Python well enough to follow a module, and Git for browsing history.

  • Required: web application fundamentals: HTTP, databases, background jobs and caching.

  • Helpful: Docker and Kubernetes concepts, Django, and a diagramming tool (draw.io, Structurizr, Mermaid or PlantUML).

Schedule

The file references in the lectures are listed in full under Principles in the Source Code.

Block

Min

Content

1

45

Lecture 1: What architecture is. Decisions that are hard to reverse, quality attributes (scalability, security, maintainability, cost), trade-offs, and the role of the architect. Principles as a shared vocabulary: the twelve factors, infrastructure as code, horizontal scalability, zero trust, extensibility and data models. A first look at Smarter: browser, CLI, API, workers, database, cache, model providers and Kubernetes.

2

45

Lab 1: Draw it. In pairs, draw Smarter’s C4 context and container diagrams, from the code, the Compose file and the docs. Produces Assignment 1.

3

45

Lecture 2: Architecture Decision Records. Why record decisions, Nygard’s format, and a guided reading of ADR 001 on Django, ADR 004 on the twelve-factor app (an ADR that adopts a whole methodology), ADR 005 on manifests and ADR 024 on the broker model.

4

45

Lab 2: Does the code agree? Each student takes one ADR, finds the code that implements it, and judges whether the code still matches the decision. Produces Assignment 2.

5

45

Lecture 3: The twelve-factor app. Heroku’s methodology, factor by factor, each shown in Smarter’s code: one codebase with a settings module per environment; config in the environment, validated by a Pydantic Settings class; MariaDB, Redis, S3 and SMTP as attached resources; a multi-stage Dockerfile and separate build, release and deploy workflows; stateless processes with sessions in the cache; port binding with uvicorn; web, worker, infrastructure worker and beat as separate process types; health and readiness probes; one image from laptop to production; logs to standard output; and admin work as manage.py commands and a Kubernetes Job. Smarter’s own twelve-factor guide is read critically: a claim is only as good as the code behind it.

6

45

Lecture 4: Styles, patterns and extensibility. A pattern review: Model-View-Controller and the separation it makes between data, presentation and input; Django’s Model-View-Template, traced through the Secret model, its URLconf, views and templates; and the LAMP stack, set beside Smarter’s Debian, uvicorn, MariaDB and Python. Then monolith, modular monolith (one Django app per resource family) and microservices; layered architecture; ports and adapters, in the infrastructure service layer that hides AWS behind infrastructure.dns, .certificates, .kubernetes and .email and swaps in an in-memory provider for tests; the broker model and its registry of kinds; extension points for new plugin types and new LLM providers. Data models: Django models for storage, Pydantic models for manifests and contracts (ADR 031), and the ownership base class that makes every resource belong to an account.

7

45

Lab 3: Twelve-factor audit. Each pair audits four of the twelve factors against the code, with file and line references, and the class assembles a scorecard for the whole system. Produces Assignment 3.

8

45

Lecture 5: Architecture for the cloud and for AI. Infrastructure as code: Terraform for the AWS foundation, a Helm chart for the platform, and Smarter itself as a declarative system that turns YAML manifests into DNS records, certificates and Kubernetes ingresses. Horizontal scalability: stateless pods, Horizontal Pod Autoscalers, a shared Redis cache (ADR 018) and Celery queues (ADR 030). Zero trust: every API call authenticated, every query filtered by owner, secrets encrypted at rest, network policies between pods, server-side request forgery blocked, and the model itself treated as untrusted, with guardrails on its input and output. Where Smarter stops short of full zero trust, and why.

9

45

Lab 4: Argue the opposite. Teams take one ADR or principle and argue for the alternative: what would Smarter look like without it, and what would that have cost? A short debate follows, and each team drafts the losing side as an ADR. Ungraded.

10

45

Lecture 6: Evolving architecture. Technical debt, migrations, API versioning (ADR 023), feature flags (ADR 022), fitness functions in CI (tests, coverage and pre-commit hooks), the audit journal as a record of change, and how architecture changes when coding agents write much of the code and the conventions live in CLAUDE.md and skills/.

11

30

Capstone kickoff. Students choose a capstone and its scope.

Principles in the Source Code

Every lecture, lab and assignment in this course rests on the files below. Every reference is to the main branch of github.com/smarter-sh/smarter, so that students can open each one during class. Python paths are under smarter/smarter/.

The Twelve Factors

Factor

How Smarter follows it

Where to look

  1. Codebase

One repository, deployed as local, alpha, beta, next and production. Each environment is a settings module that inherits from base.py, not a branch or a fork. The Helm chart lives in the same repository.

settings/, helm/charts/smarter

  1. Dependencies

Pinned Python requirements per purpose, an npm workspace for the React apps, and a Docker image that installs them into an isolated virtual environment. ADR 015.

smarter/requirements/, package.json, Dockerfile

  1. Config

Every setting is read from the environment, then validated and typed by a Pydantic Settings class. Placeholders such as SET-ME-PLEASE count as missing. ADR 007.

common/conf/settings.py, common/conf/env.py, .env.example

  1. Backing services

MariaDB, Redis, S3 and SMTP are attached by URL and credentials. File storage switches between S3 and the local file system by configuration alone. Email is reached through the infrastructure service layer.

settings/base.py (DATABASES, CACHES, STORAGES), docker-compose.yml

  1. Build, release, run

A multi-stage Dockerfile builds one image. Separate GitHub Actions workflows build it, release the Helm chart and deploy it, and semantic-release versions it. ADR 014, ADR 020.

.github/workflows/, release.config.js, Makefile

  1. Processes

Web processes keep no state between requests: sessions are stored in the Redis cache (SESSION_ENGINE), and uploaded files in S3.

settings/base.py (SESSION_ENGINE, STORAGES)

  1. Port binding

The app serves itself with uvicorn on a configured port. Nothing is injected into a separate web server.

deployment-app.yaml, asgi.py

  1. Concurrency

Four process types (web, worker, infrastructure worker, beat), each its own Kubernetes Deployment, and the web and worker types scaled out by autoscalers. Infrastructure tasks have their own Celery queue. ADR 009.

helm templates (deployment-*.yaml, hpa-*.yaml), workers/celery.py

  1. Disposability

Liveness and readiness probes on /healthz/ and /readiness/, and a graceful shutdown timeout on uvicorn, let Kubernetes replace pods freely.

urls/console.py, deployment-app.yaml

  1. Dev/prod parity

The same image, the same MariaDB and Redis, and the same Celery workers run under Docker Compose and under Kubernetes. Tests replace the cloud with an in-memory provider: a deliberate break in parity, worth discussing.

docker-compose.yml, infrastructure/providers/memory.py

  1. Logs

Logs go to standard output as a stream. Verbose logging is switched on per subsystem with feature flags, not by editing code. ADR 011.

lib/logging/, settings/base.py (LOGGING)

  1. Admin processes

Setup and maintenance run as manage.py commands in the same image, locally or as a Kubernetes Job. ADR 010.

initialize_platform.py, job-init.yaml

Beyond the Twelve Factors

Principle

How Smarter follows it

Where to look

Infrastructure as code

Terraform and Terragrunt create the AWS foundation, and a Helm chart, validated by a JSON schema, deploys the platform. Smarter is itself declarative: a YAML manifest states what should exist, and deploying an LLMClient creates its DNS record, certificate and Kubernetes ingress from a template. ADR 005, Cloud Infrastructure.

smarter-infrastructure, values.schema.json, llmclient/k8s/ingress.yaml.tpl, llmclient/tasks/deploy_default_api.py

Horizontal scalability

Stateless web pods behind Horizontal Pod Autoscalers, shared state in Redis and MariaDB, and slow work moved to Celery workers that scale on their own. ADR 018, ADR 030.

hpa-app.yaml, hpa-worker.yaml, lib/cache/

Zero trust

No request is trusted for where it comes from. API keys are hashed and checked on every call, querysets are filtered by owner, secrets are encrypted with Fernet, middleware blocks probing and brute force, pods talk only where the network policies of smarter-infrastructure allow, and plugin HTTP calls refuse private addresses. The model’s output is untrusted too: guardrails check both the prompt and the reply. ADR 016, Smarter Guardrail.

lib/drf/token_authentication.py, secret/models.py, lib/django/middleware/, plugin/plugin/safe_http.py, guardrail/services/pipeline.py

Extensibility

New resource kinds register a broker. New plugin types subclass PluginBase. New LLM providers that speak the OpenAI protocol are added with a Provider manifest, not code. New clouds implement the CloudProvider interface. ADR 024, How-To: Adding an LLM Provider to Smarter.

api/v1/cli/brokers.py, plugin/plugin/base.py, infrastructure/providers/base.py

Ports and adapters

All DNS, certificate, Kubernetes and email work goes through one facade, and the provider behind it is chosen by configuration. The application never calls the AWS SDK directly.

infrastructure/services/__init__.py, infrastructure/providers/

Data models and contracts

Two kinds of model with two jobs: Django models for what is stored, and Pydantic models for what crosses a boundary (manifests, settings, API contracts). An abstract base adds ownership and permission-aware querysets to every resource. ADR 017, ADR 031.

account/models/metadata_with_ownership.py, lib/manifest/, plugin/manifest/models/

Multi-tenancy

Every resource belongs to an account and a user, and every query is scoped by them. Account Management.

account/models/

Auditability

Every command sent through the API or CLI (apply, describe, delete, deploy and the rest) is written to a journal with its request, response and user. Smarter Journal.

lib/journal/models.py

API first

The CLI and the web console are clients of the same versioned REST API. ADR 006, ADR 023.

api/v1/

Feature flags

Behavior and diagnostics are switched at run time with Django Waffle, without a deployment. ADR 022.

lib/django/waffle/switches.py

Classic Patterns

Pattern

How Smarter follows it

Where to look

Model-View-Controller

Trygve Reenskaug’s pattern from Smalltalk at Xerox PARC (1979), later the shape of almost every server-side web framework: a model holds the data and its rules, a view presents it, and a controller turns input into changes to the model. In Smarter’s web console the pattern is split across the network. Django sends a page shell, a React app in the browser renders the view and handles the user’s actions, and JSON API views act on the models. ADR 019 still limits React to the Workbench; the packages show how far the code has moved since.

react/packages/smarter-secret-list/src/, secret/views/listview/

Model-View-Template

Django’s own version of MVC, which its FAQ calls MTV. The Django view does the controller’s job, the template does the view’s job, and the URLconf with the framework’s request handling is the remaining controller. One resource family shows all three: the Secret model, the URL patterns that route to its views, and the templates they render. ADR 001, ADR 025.

secret/models.py, secret/urls.py, secret/views/detailview.py, templates/react/secret-list.html

LAMP

Linux, Apache, MySQL and PHP (or Perl or Python): the open-source web stack named in 1998, on which much of the early web ran. Smarter is a descendant. The image is built on Debian Linux; MariaDB, the fork of MySQL by MySQL’s original author, is reached through Django’s MySQL backend; Python replaces PHP; and uvicorn, behind a Kubernetes ingress, replaces Apache. What LAMP did not have shows what changed since: Redis, Celery workers, containers, autoscaling and a React front end.

Dockerfile, docker-compose.yml, settings/base.py (DATABASES), llmclient/k8s/ingress.yaml.tpl

Graded Assignments

Assignment 1: C4 Diagrams

Students draw Smarter’s C4 context and container diagrams, with every container’s technology and responsibility, and the main relationships.

Turn in: the two diagrams (source and image) and a half-page key.

Criterion

Pts

Exemplary

Developing

Accuracy

8

Every container and external system correct, confirmed in code or config.

Missing or invented parts.

C4 notation

4

Correct levels, with technology and responsibility on each box.

Mixed levels.

Relationships

5

Labeled with purpose and protocol.

Unlabeled arrows.

Clarity

3

Readable at a glance.

Cluttered.

Assignment 2: ADR Verification

Students check one ADR against the code: where it is implemented, whether the code follows it, and where it has drifted.

Turn in: a two-page report with code references.

Criterion

Pts

Exemplary

Developing

Understanding

5

The decision and its reasons summarized accurately.

Misread.

Evidence

7

Specific files and functions cited.

General statements.

Judgment

6

Clear verdict on conformance and drift, with reasons.

No verdict.

Recommendation

2

Update the code, or update the ADR.

None.

Assignment 3: Twelve-Factor Audit

Pairs audit four of the twelve factors against the code. For each factor they state what the factor requires, find where Smarter meets it or falls short, and give a verdict: follows, partly follows, or does not follow. At least one verdict must test a claim in Smarter’s own twelve-factor guide against the code. The instructor assigns factors so that the class covers all twelve, and the pairs’ findings are combined into a scorecard for the whole system.

Turn in: a one-page table (factor, evidence with file and line references, verdict) and a half page on the most important gap found.

Criterion

Pts

Exemplary

Developing

Understanding

5

Each factor’s requirement stated accurately, in the pair’s own words.

Copied or misstated.

Evidence

7

Files, settings and manifests cited for every verdict.

Verdicts without references.

Judgment

5

Verdicts that distinguish the letter of a factor from its intent, including the guide’s claims.

Accepts the documentation at face value.

Gap analysis

3

The most important gap, its risk and a remedy.

None.

Capstone Projects

Students choose one. Capstones are due one week after the bootcamp.

Capstone A: An Architecture Review of Smarter

Learning objective. Carry out an architecture review of a real system against stated quality attributes and established principles, and make evidence-based recommendations.

Students choose two quality attributes (for example scalability and security) and review Smarter against them, using the ADRs, the code and the deployment configuration. They complete the class’s twelve-factor scorecard, and assess one of the principles in Beyond the Twelve Factors (for example how far Smarter goes toward zero trust). They identify risks and sensitivity points, and recommend changes.

What students turn in:

  • An architecture review document (five to seven pages) with C4 diagrams.

  • Quality attribute scenarios (“when X happens, the system should Y within Z”).

  • A complete twelve-factor scorecard, with code references.

  • A ranked list of risks, and at least one recommendation written as a draft ADR.

How it is graded (100 points):

Criterion

Pts

Exemplary

Developing

Scenarios

15

Specific, measurable quality attribute scenarios.

Vague goals.

Analysis

25

Traces each scenario through the architecture, with evidence.

Opinions.

Principles

15

Scorecard and principle assessment backed by code, not by the documentation alone.

Restates the documentation.

Risks

15

Ranked, with likelihood and impact.

Unranked.

Recommendations

15

Realistic, with a draft ADR.

Generic.

Writing and diagrams

15

Clear and accurate.

Unclear.

Capstone B: An Architecture for a New Feature

Learning objective. Design a significant feature that fits an existing architecture and its principles, and record the decisions it requires.

Students design a feature Smarter does not have, for example per-team model routing rules, a scheduled report resource, or multi-region deployment. They place it in the existing architecture, show that it keeps to the twelve factors and to Smarter’s other principles (stateless processes, the infrastructure facade, owned resources, a declarative manifest), identify the decisions it needs, and write ADRs for the two most important.

What students turn in:

  • A design document with C4 container and component diagrams.

  • Two ADRs in the format of ADR.

  • A list of the existing ADRs and principles the design depends on, and how it respects them.

How it is graded (100 points):

Criterion

Pts

Exemplary

Developing

Fit

25

Uses existing patterns (brokers, manifests, tasks, the infrastructure facade) where they apply, and keeps to the twelve factors.

Ignores the existing architecture.

Design

20

Complete, with responsibilities and interfaces.

Sketchy.

ADRs

25

Real decisions, alternatives and consequences.

Descriptions, not decisions.

Dependencies on existing ADRs and principles

15

Correctly identified and respected.

Not considered.

Diagrams and writing

15

Clear.

Unclear.

Further Study