We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
The 18-Pillar Doctrine: Building Self-Enforcing Software Quality
How Prismatic Platform enforces quality through 18 complementary pillars covering architecture, testing, security, performance, and documentation -- all validated automatically at every commit.
Tomas Korcak (korczis)
Prismatic Platform
Quality in software is either enforced or aspirational. Aspirational quality erodes under deadline pressure. Enforced quality compounds. This post describes how Prismatic Platform achieves consistent quality across 94 umbrella applications through 18 complementary enforcement pillars.
The Problem with Manual Quality
Most engineering teams rely on code review and tribal knowledge to maintain quality. This breaks down at scale:
The solution is to encode quality rules as automated checks that run at every commit.
The 18 Pillars
Prismatic's doctrine is organized into 18 pillars, each targeting a specific quality dimension:
|--------|------|--------|-------------|
The pillars divide into three enforcement tiers:
2. CI enforcement (17 pillars) -- validates the full doctrine in continuous integration
3. Advisory -- tracks metrics without blocking
How Pre-Commit Enforcement Works
Every git commit triggers a series of validation checks:
# ZERO: Scan for banned patterns
grep -rn "String.to_atom" staged_files # Blocks atom table exhaustion
# SEAL: Scan for hardcoded secrets
grep -rn "api_key.=.\"sk-" staged_files # Blocks credential leaks
# PERF: Scan for performance anti-patterns
grep -rn "length(.)==.0" staged_files # Blocks O(n) emptiness checks
# TACH: Verify test file existence
# For every changed lib/.ex, ensure test/_test.exs exists
# DOCS: Verify documentation
# Changed modules must have @moduledoc and @doc
# DEPS: Verify dependency hygiene
# No overrides without justification comments
# RDME: Verify README existence
# Every umbrella app must have README.md
These checks run in under 2 seconds and catch the most common violations before they reach the repository.
ZERO: Runtime Safety
The ZERO pillar prevents three categories of runtime crashes:
Atom table exhaustion: Erlang's atom table is finite (1,048,576 atoms by default). Converting untrusted strings to atoms with String.to_atom/1 can exhaust this table, crashing the entire VM.
# Banned
String.to_atom(user_input)
# Required
String.to_existing_atom(user_input)
Silent error swallowing: Bare rescue blocks hide the root cause of failures, making debugging impossible.
# Banned
rescue _ -> :error
# Required -- catch specific exceptions
rescue e in [Ecto.NoResultsError] ->
Logger.warning("Record not found: #{inspect(e)}")
{:error, :not_found}
Unsafe deserialization: binary_to_term/1 without the :safe option can create atoms from untrusted data.
# Banned
:erlang.binary_to_term(data)
# Required
:erlang.binary_to_term(data, [:safe])
PERF: Performance Gates
The PERF pillar catches three anti-patterns that cause production performance issues:
O(n) emptiness checks: length/1 traverses the entire list to count elements. Checking length(list) == 0 is O(n) when list == [] is O(1).
Unbounded queries: Repo.all(query) without a limit clause can return millions of rows, consuming all available memory.
N+1 queries: Iterating over a collection and making a database query for each element generates N+1 queries instead of a single batch query.
TACH: Testing Doctrine
The TACH pillar ensures that every module has corresponding test coverage:
lib/.ex file must have a test/_test.exs file@tag :integration@tag :e2eThe pre-commit hook blocks commits that add or modify library code without corresponding test files.
SEAL: Security Enforcement
The SEAL pillar prevents three classes of security vulnerabilities:
Code.eval_string/1 with untrusted inputReal-World Impact
Since deploying the 18-pillar doctrine, Prismatic has achieved:
The doctrine is not about perfection -- it is about preventing the classes of defects that cause production incidents. Each pillar was added in response to a real incident or a category of bugs that consumed engineering time.
Building Your Own Doctrine
The approach generalizes to any codebase:
2. Encode rules as automated checks -- grep patterns, AST analysis, or custom mix tasks
3. Start with pre-commit blocking -- fast checks that catch violations before they enter the repository
4. Add CI enforcement -- slower, more comprehensive checks that run in the pipeline
5. Track metrics over time -- measure the reduction in defect categories
The key insight is that quality enforcement must be automated and non-bypassable. Any check that can be skipped with --no-verify will be skipped under pressure.
Conclusion
Eighteen pillars may sound like overkill. In practice, each pillar targets a specific failure mode that we encountered in production or during development. The overhead is minimal -- pre-commit checks run in under 2 seconds -- while the protection is comprehensive.
Quality is a system property, not an individual discipline. The 18-pillar doctrine makes quality a property of the development process itself, not something that depends on any individual's vigilance.
Explore the full doctrine at [Architecture Documentation](/architecture/) or try the [Quality Gates command](/developers/) to validate your own code against the doctrine.