Files
bible/rules/patterns/module-structure/contract.md
2026-06-12 09:41:46 +03:00

1.6 KiB

Contract: Module Atomicity

Version: 1.0

Principle

Each file has one clear responsibility. A file that does many unrelated things is a liability, not a convenience.

Rules

  • One concept per file. A file should be nameable in a single noun: user_validator.go, session_store.go, invoice_pdf.go. If the name requires "and" or "misc", the file is too broad.
  • Do not append new functionality to an existing file because it is nearby or already open. When a new piece of logic does not belong to the existing concept, create a new file.
  • A file that grows past ~200 lines is a signal to split, not a mandate — but treat it as a prompt to ask whether all the code in it shares a single responsibility.
  • Package-level utils.go, helpers.go, or common.go files are banned. Name the file after what the code actually does.

Anti-patterns

  • Adding a new handler to handlers.go because there is already a handler there.
  • Putting unrelated functions in the same file to avoid creating a new one.
  • A single file containing models, queries, business logic, and HTTP concerns at once.
  • Files named after their location or role in the codebase rather than their concept: api.go, misc.go, util.go, shared.go.

When to split

Split a file when:

  1. You cannot describe all of its functions in one short sentence.
  2. A new function you are adding does not share the domain of the existing ones.
  3. The file has more than one reason to change independently.

Do not wait until a file is "too big." Split at the moment the second responsibility appears.