Get Down with ALA, a Zero-Coupled Architecture
My motivation is to dabble with ALA myself and to express it in a compact form for functional programming (later OO) and provide tooling and templates, to help others to try and evaluate it as a distinct architectural choice. I'm not saying it's a good or the best way, just a way that intrigues me, and is compatible with some other software principles I find useful or appealing.
Exploring ALA yourself — a web app, a design, a tool, an analysis, or just thoughts? Add it to Awesome ALA, a community list where anyone can share links to their own explorations.
This is a single-topic site. It explores code architecture ideas from John Spray's Abstraction Layered Architecture (ALA), an online book (with C# code examples in his GitHub), as applied to real programming languages and applications, mixed with some of my own preferences and directions of curiosity. It starts with the Elixir programming language and Phoenix LiveView web apps.
Spray's argument, briefly: software degrades into a big ball of mud because of coupling, where modules come to depend on their peers and on things more specific than themselves, and no amount of layering-by-containment removes it. ALA's target is specifically design-time coupling, the dependencies written into the source, where one module's code names and relies on another. It drives those to zero between peers, permitting a dependency only downward, from a concrete piece to a more abstract, more stable one, so in that sense the code is strictly zero-coupled. What it does not forbid is run-time coupling: while the program runs, abstractions still exchange data and events, but only through wires connected in a higher layer, so two peers interact without either one's source knowing the other exists. Zero-coupled at design time, fully connected at run time. Spray claims this buys what object-oriented, layered, hexagonal, and clean-architecture approaches aim at but reach less completely: abstractions that are reusable, replaceable, and testable in isolation; code you can understand a piece at a time; changes that stay local; and a top layer that reads like the requirements. Those claims are his. Testing how far they hold in Elixir is the point of this site.
Introduction to ALA
- A first look at ALA, through a thermometer
What Abstraction Layered Architecture actually asks of your code, shown on a tiny example, distilled to four rules, then run through the linter.
- The coffee maker: an ALA model that nests cleanly inside LiveView
Robert Martin's Mark IV coffee maker, reworked in Abstraction Layered Architecture and dropped into a Phoenix LiveView, where the pure model needed no changes to fit the framework.
Building from Scratch with ALA
- The ALA Checklist: eleven rules, applied by hand
The full ALA Checklist, eleven rules that make Spray's constraints checkable, walked one at a time against the thermometer example.
- ala_lint: putting the ALA Checklist in CI
A static-analysis linter that scores an Elixir codebase against the ALA Checklist, reports each violation with a file and line, and can encode your code into the checklist notation for a human to finish.
- A field guide: which technique solves which checklist rule
Across twenty-odd LiveView variants I tried a lot of techniques. This maps each item of the ALA Checklist to the concrete moves that satisfy it, so you can shop by rule instead of adopting a whole variant.
Some ALA Reference Web App Designs
- V36, the vernacular core: ALA that reads like ordinary Phoenix
A LiveView design that any Phoenix developer understands after one example, yet holds zero feature-to-feature coupling by discipline rather than machinery.
- V38, lint-guided evolution: making a conventional app ALA
Instead of designing an ALA architecture up front, start from an ordinary Phoenix app and let the ALA Checklist and ala_lint guide it there, one small change at a time.
- V30, committed codegen: make the diagram the source of truth
A LiveView variant where the page's wiring diagram is a data file, the glue is generated and committed, and CI fails the build if the two ever drift apart.
- V35, composed inputs: making one coupling impossible instead of lint-able
How a LiveView variant closes the sneakiest peer dependency in a multi-feature page, a feature reaching into another feature's state, and turns it into a mechanical check.