For opinionated, token-efficient monoliths (e.g., Rails apps) that are moving to agent-first workflows, what specific patterns of file layout, naming, and boundary design most improve agent accessibility and human-verifiable diffs—compared to today’s “good monolith” practices—and how should teams adjust their craft bar and style guides so that these agent-friendly patterns don’t erode long-term maintainability or apprenticeship?

dhh-agent-first-software-craft | Updated at

Answer

Patterns that help, and how to keep them from rotting the codebase or apprenticeship.

  1. Layout and boundaries for agents and diffs
  • Flattened, façade-first domains

    • Prefer app/services/<domain>/<verb>_service.rb, app/queries/<domain>/..., app/forms/... over deep helper/module nesting.
    • Keep 1–2 obvious façades per domain (e.g., Billing::ChargeCustomer, Projects::CreateProject). Instruct agents: call façades, don’t reach into models directly.
  • Scenario-oriented entrypoints

    • Co-locate controller/action + form/command + view/partial under a shallow namespace (app/features/checkouts/... or app/flows/...).
    • Make one file the “flow coordinator” (e.g., Checkouts::Flow), so agent diffs have a natural home instead of scattering logic.
  • Stable boundary directories

    • Treat app/services, app/queries, app/jobs, app/events as contract surfaces.
    • For cross-cutting concerns (billing, auth), use app/boundaries/billing/... with a tiny public API; forbid agent calls outside that.
  • Token-efficient split of concerns

    • Keep files short (e.g., 50–150 lines), single responsibility, no mega-objects.
    • Prefer more small, named methods over long, inlined logic so agents can reason in local windows.
  1. Naming patterns
  • Domain-first names

    • Use domain nouns consistently in folders, classes, methods (Workspace, BillingProfile, InviteToken).
    • Maintain a repo DOMAIN_GLOSSARY.md; instruct agents to align new names with it.
  • Verb clarity at boundaries

    • Use explicit verbs on façades: create_invoice, send_invite, recalculate_totals instead of run, process.
    • For side effects vs queries, keep suffixes consistent: *_query read, *_service write.
  • Path–concept alignment

    • Enforce that file path mirrors namespace and concept (app/services/billing/create_invoice_service.rbBilling::CreateInvoiceService).
    • Style guide: no abbreviations in top-level names; reserve short names for internals.
  1. Diff-shaping patterns
  • One primary diff locus per change

    • Prefer that each behavior change has a single “main” file (flow/command/query) with small edits elsewhere.
    • Review rule: reject PRs where behavior is encoded mostly in callbacks or scattered helpers; ask agent to refactor toward the locus.
  • Guardrail files per domain

    • Keep a tiny “taste sample” file per domain (e.g., billing/_taste_example.rb) that shows ideal style and layering.
    • Seed agents with these examples; reviewers link back when asking for rewrites.
  • Explicit contracts near risky code

    • Keep a short contract comment or DSL at top of key façades (# Contract: inputs, side effects, invariants).
    • Agents update contracts + code; humans verify contract diffs first.
  1. Style-guide adjustments to stay agent-friendly without erosion
  • Make agent rules explicit

    • Add a short “Agent usage” section: which directories agents may edit freely, which require human-led design, and which are read-only.
    • Encode this in the harness (e.g., tool scopes, path allowlists/denylists).
  • Raise the bar on tests and contracts, not on cleverness

    • Require at least one small, focused spec per new façade or flow class.
    • Prefer scenario or request specs over brittle unit tests on internals; easier for agents to extend safely.
  • Normalize refactor-first PRs

    • When agents propose logic in the wrong place, seniors first move structure (e.g., extract a service), then re-run agent to fill in details.
    • Style guide: “if it doesn’t have a flow/command, add one before adding more conditionals.”
  1. Protecting maintainability and apprenticeship
  • Apprenticeship scaffolds

    • Pair juniors on reviewing agent diffs in one domain at a time; have them edit taste/tone, not just rubber-stamp.
    • Use “explain-the-diff” comments as a requirement: author (or junior) must summarize what changed in domain language.
  • Guard against callback creep

    • Ban new model callbacks except in whitelisted files; teach agents to use services/flows instead.
    • Add CI checks for new callbacks or deep ActiveRecord magic in non-boundary files.
  • Periodic domain health passes

    • Once per cycle, sample a few agent-heavy diffs per domain; confirm they still respect façades, naming, and boundaries.
    • If drift shows up, update examples and style guide; don’t just complain in PRs.

Net effect: make Rails-style “good monolith” patterns more explicit, façade-centric, and glossary-backed so agents can produce small, readable diffs. Keep the craft bar anchored in clean boundaries, contracts, and tests, while using style guides and harness rules to prevent agent convenience patterns (callbacks, scattering, anonymous helpers) from eating long-term structure or apprenticeship.