The Problem with Architecture Advice

Most architecture tools tell you what you already know. Linters catch style. Type checkers catch types. Complexity metrics give you a number without telling you what it means. What they don't catch is the kind of structural rot that makes a codebase unmaintainable over months and years.

And when you go looking for advice, you get dogmas. "Never use booleans in function signatures." "Always write tests." "Single responsibility, always." Nobody tells you when these rules start strangling the system. Nobody shows you the real failure cases.

ArchDogma is my attempt at something different. It's a static analysis tool for Python that catches architectural anti-patterns — not style, not formatting, but structure. And it tries to be honest about what it actually knows.

What It Does

Install it:

pip install archdogma

Run it on a Python file or directory:

archdogma probe mymodule/
archdogma probe src/api.py

It analyzes your Python code with AST-based detectors and flags architectural issues with severity levels: critical, high, medium, low. Output is clean JSON — pipe it into whatever you want.

The 11 Detectors in v0.1.0

These are the patterns ArchDogma catches today. Not aspirational — actually implemented, actually tested.

null-return

Functions that return None mixed with real values. The caller has to null-check everywhere, or it crashes. Severity: high.

if-on-parameter

Functions that branch on a boolean parameter. This is a sign that you have two functions masquerading as one. The classic: def process(data, dry_run=False) — split it. Severity: medium.

magic-numbers

Numeric literals in logic that aren't 0 or 1. if retries > 3 — why 3? What changes when the system scales? Magic numbers are undocumented assumptions. Severity: medium.

dynamic-magic

Dynamic attribute creation at runtime via setattr, __dict__, or vars(). Makes the object model impossible to reason about statically. Severity: high.

function-complexity

Functions that do too many things: high cyclomatic complexity, too many parameters, too many lines. Each is a separate threshold with its own severity.

class-complexity

Classes with too many public methods. Usually a sign of a class that accumulated responsibilities over time rather than being designed with one clear purpose.

file-complexity

Files that span too many concerns: too many classes, too many top-level functions, too many imports. A useful proxy for "this file is doing too much."

circular-import

Circular import chains between modules. These cause subtle runtime errors and make the dependency graph impossible to understand.

module-docstring

Missing module-level docstrings. Low severity, but forces you to articulate what a module is actually for. If you can't write one sentence — it's a smell.

broad-except

except Exception: or bare except: blocks. You're catching things you didn't intend to catch, hiding bugs, and making debugging impossible. Severity: high.

mutable-default-arg

def foo(items=[]) is a Python classic that bites everyone eventually. The default is shared across all calls. Use None and initialize inside. Severity: high.

Why 281 Tests

Every detector has its own test suite. Each test proves one specific case: the pattern fires when it should, doesn't fire when it shouldn't. No magic coverage numbers — just scenarios that correspond to real code structures.

The test count matters because detectors break silently. A regex or AST traversal that worked for one code pattern can miss another. 281 tests means we've explored the space of inputs enough to trust the output.

It's also honest about what it can't do. ArchDogma doesn't analyze runtime behavior. It doesn't understand semantics. It catches structural patterns that tend to correlate with problems — it can't prove causation.

The Catalog of Dogmas

The other part of ArchDogma is the dogma catalog. Each architectural anti-pattern detected by the tool links to a catalog entry with:

  • What the pattern is
  • Under what conditions it actually causes problems
  • Real failure cases with links to post-mortems
  • Counter-dogmas — when the conventional wisdom is wrong

The rule: no link, no claim. If we can't find a real-world case where the dogma failed, we mark it [NEED POSTMORTEMS] and don't pretend we know more than we do. Three dogmas are fully filled with sources: microservices-for-everything, TDD-as-law, DRY/premature-abstractions. The rest are drafts.

This is the part that makes ArchDogma different from other linters. Most tools tell you "this is bad." ArchDogma tries to tell you why, and under what conditions it might actually be fine.

How to Use It

Basic probe of a file or directory:

archdogma probe src/

Output issues filtered by severity:

archdogma probe src/ --min-severity high

JSON output for CI integration:

archdogma probe src/ --format json | jq '.issues[] | select(.severity == "critical")'

Browse the dogma catalog:

archdogma catalog
archdogma catalog --tag null-return

What's Next

v0.1.1 will add two more Tier 1 detectors: god-class (classes with too many responsibilities measured by method count + coupling) and deep-inheritance (inheritance chains that go more than 2-3 levels deep). These require ClassDef walker extensions to the AST analyzer that aren't in v0.1.0.

After that: repo-level analysis (import graphs, dependency cycles across packages), and better catalog coverage with more post-mortems. Eventually — integration with the Function Probe so the tool can say "this pattern appears in functions that also have X and Y, which historically correlates with production incidents."

But that's the roadmap. v0.1.0 is on PyPI, works, and is honest about what it catches.

Links