Skip to content

Commit bbcec6c

Browse files
docs(standards): add universal coding practices page and cross-references
Create practices.md (weight 5) consolidating key coding and git workflow practices from the planning repo. Add cross-reference bullets to all 7 language standard Notes sections. Update _index.md with Practices entry in page list and Consistent Page Structure note. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 5d33088 commit bbcec6c

9 files changed

Lines changed: 109 additions & 1 deletion

File tree

content/docs/standards/_index.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ Each Makefile target runs the relevant tools for all languages declared in `.dev
4040

4141
## Per-Language Pages
4242

43+
- [Coding Practices](/docs/standards/practices/) -- principles, error handling, testing, git workflow
4344
- [Python Standards](/docs/standards/python/) -- ruff, bandit, semgrep, pytest, mypy
4445
- [Bash Standards](/docs/standards/bash/) -- shellcheck, shfmt, bats
4546
- [Terraform Standards](/docs/standards/terraform/) -- tflint, terraform fmt, tfsec, checkov, terratest, terraform-docs
@@ -51,7 +52,7 @@ Each Makefile target runs the relevant tools for all languages declared in `.dev
5152

5253
## Consistent Page Structure
5354

54-
Each per-language page follows a consistent structure:
55+
The Coding Practices page covers cross-cutting standards (principles, error handling, testing, git workflow) that apply to all languages. Each per-language page follows a consistent structure:
5556

5657
1. **Tools** -- table of tools with category, name, and purpose
5758
2. **Configuration** -- configuration examples with inline comments

content/docs/standards/ansible.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,3 +106,4 @@ repos:
106106
- **Role directory structure follows Ansible Galaxy conventions:** `tasks/`, `handlers/`, `defaults/`, `vars/`, `templates/`, `files/`, `meta/`.
107107
- **Molecule scenarios should be comprehensive.** At minimum, test converge, idempotence, and verify.
108108
- **All tools are pre-installed in the dev-toolchain container.** Do not install them on the host.
109+
- For cross-cutting coding practices and git workflow standards that apply to all languages, see [Coding Practices](/docs/standards/practices/).

content/docs/standards/bash.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,4 @@ echo "Starting installation" # Do not do this
170170
- **Use shared logging functions** from `lib/log.sh`. No raw `echo` for status messages.
171171
- **Every script supports `--help`** and uses `getopts` for argument parsing.
172172
- **All tools are pre-installed in the dev-toolchain container.** Do not install them on the host.
173+
- For cross-cutting coding practices and git workflow standards that apply to all languages, see [Coding Practices](/docs/standards/practices/).

content/docs/standards/go.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,3 +94,4 @@ repos:
9494
- **Go tools use `./...` patterns.** The `./...` pattern matches all packages in the module. This is the standard Go convention for recursive operations.
9595
- **`go.sum` presence gates security scanning.** If no `go.sum` file exists, govulncheck is skipped because there are no module dependencies to scan.
9696
- **All tools are pre-installed in the dev-toolchain container.** Do not install them on the host.
97+
- For cross-cutting coding practices and git workflow standards that apply to all languages, see [Coding Practices](/docs/standards/practices/).

content/docs/standards/javascript.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,4 @@ repos:
170170
- **npm audit gates on `package-lock.json`.** If no `package-lock.json` exists, npm audit is skipped because there are no locked dependencies to scan.
171171
- **Vitest gates on test file presence.** If no `*.test.*` or `*.spec.*` files exist, vitest is skipped.
172172
- **All tools are pre-installed in the dev-toolchain container.** Do not install them on the host.
173+
- For cross-cutting coding practices and git workflow standards that apply to all languages, see [Coding Practices](/docs/standards/practices/).
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
---
2+
title: "Coding Practices"
3+
linkTitle: "Practices"
4+
weight: 5
5+
description: "Cross-cutting coding and git practices for all DevRail projects."
6+
---
7+
8+
These practices apply to every DevRail project regardless of language. They are enforced by code review, not automated tooling. The per-language pages cover *which tools run*; this page covers *how to write the code those tools check*.
9+
10+
## Principles
11+
12+
| Principle | Rule |
13+
|---|---|
14+
| **DRY** (Don't Repeat Yourself) | Extract repeated logic into shared functions or modules. If the same block appears three or more times, refactor it. |
15+
| **KISS** (Keep It Simple, Stupid) | Choose the simplest solution that meets the requirement. Avoid clever code that requires comments to explain. |
16+
| **YAGNI** (You Aren't Gonna Need It) | Do not build for hypothetical future requirements. Implement what is needed now. |
17+
| **Single Responsibility** | Each function, class, or module does one thing. If a description requires "and", split it. |
18+
| **Separation of Concerns** | Keep business logic, data access, configuration, and presentation in distinct layers. |
19+
| **Fail Fast** | Detect errors as early as possible. Validate inputs at boundaries. Return or raise immediately on invalid state. |
20+
| **Least Surprise** | Code should behave as a reader would expect. Follow language idioms and project conventions. |
21+
| **Idempotency** | Operations must be safe to re-run. The result of running something once must be identical to running it N times. |
22+
23+
## Idempotency
24+
25+
Every script, migration, deployment, and configuration change must be safe to re-run without causing damage or duplication.
26+
27+
### Patterns by Context
28+
29+
| Context | Pattern |
30+
|---|---|
31+
| **Shell scripts** | `command -v tool \|\| install_tool`, `mkdir -p`, guard file writes with existence checks. |
32+
| **Database migrations** | Use a migration framework that tracks applied migrations by ID. Never rely on manual execution order. |
33+
| **Terraform** | Declare desired state, not imperative steps. `terraform apply` is inherently idempotent when state is managed correctly. |
34+
| **Ansible** | Use declarative modules over `command`/`shell`. Set `creates:` or `removes:` on shell tasks. Use `changed_when` to avoid false changes. |
35+
| **CI/CD pipelines** | Pipeline stages must not fail or produce different results when re-triggered. Use `--if-not-exists` flags and check artifact existence before publishing. |
36+
| **Python** | Guard resource creation with existence checks. Use `os.makedirs(path, exist_ok=True)`, catch `FileExistsError`. |
37+
| **Configuration management** | Write config files atomically (write to temp, then rename). Check current state before modifying. Never append without checking for existing entries. |
38+
39+
### Anti-Patterns
40+
41+
- Blindly appending to files (duplicate entries on re-run)
42+
- `INSERT` without `ON CONFLICT` / `IF NOT EXISTS`
43+
- Scripts that assume clean state (empty directory, fresh database)
44+
- Provisioners or setup scripts with no guards
45+
46+
## Error Handling
47+
48+
1. **Validate inputs at system boundaries.** User input, API payloads, environment variables, and file contents must be validated before use. Internal function-to-function calls can trust types and contracts.
49+
2. **No swallowed exceptions.** Every `except`, `catch`, or error branch must either handle the error meaningfully or re-raise/propagate it. Bare `except:` (Python) and empty `catch {}` blocks are prohibited.
50+
3. **Fail with meaningful messages.** Error messages must include what went wrong, what was expected, and (when possible) how to fix it.
51+
4. **Use language-appropriate error patterns.** See the per-language standard for specifics (e.g., `set -euo pipefail` in Bash, specific exception types in Python).
52+
5. **Log errors before propagating.** Use the appropriate logging mechanism so errors are visible in structured output even if the caller catches and handles them.
53+
54+
## Testing
55+
56+
### Test Pyramid
57+
58+
Maintain a healthy ratio: **unit tests > integration tests > end-to-end tests**.
59+
60+
- **Unit tests** -- fast, isolated, test a single function or method. Mock external dependencies.
61+
- **Integration tests** -- verify that components work together (e.g., script + filesystem, module + provider).
62+
- **End-to-end tests** -- validate full workflows. Fewer of these; they are slower and more brittle.
63+
64+
### Test Naming
65+
66+
Use descriptive names: `test_<what>_<condition>_<expected>`.
67+
68+
### Coverage
69+
70+
- Aim for meaningful coverage, not vanity metrics. 80% coverage of critical paths beats 100% coverage padded with trivial assertions.
71+
- **New code must include tests.** PRs that add logic without tests are incomplete.
72+
73+
## Git Workflow
74+
75+
- **Never push directly to `main`.** All changes reach the default branch through a pull/merge request.
76+
- **Branch naming:** `type/short-description` (e.g., `feat/add-ansible-support`, `fix/shellcheck-false-positive`).
77+
- **Conventional commits:** Every commit message follows `type(scope): description`.
78+
- **Minimum 1 approval required** before merging. No self-merge (exception: solo maintainers after CI passes).
79+
- **Never force-push shared branches.** Force push is acceptable on your own feature branches only.
80+
- **Squash-merge feature branches** into `main` for clean, linear history.
81+
- **No secrets in commits.** Enforced by `gitleaks` in pre-commit hooks and `make scan`.
82+
83+
## Code Organization
84+
85+
- **Function length: ~50 lines maximum.** If a function exceeds this, consider splitting it.
86+
- **One primary concern per file.** A file named `auth.py` should contain authentication logic, not unrelated utilities.
87+
- **No circular dependencies.** If A imports B and B imports A, refactor to extract the shared dependency into C.
88+
89+
## Dependencies
90+
91+
- **Lock files are mandatory.** Use the appropriate lock file for each language and commit it to version control.
92+
- **Pin versions.** Allow compatible ranges only in dependency declarations; lock files pin to exact versions.
93+
- **Respond to security advisories promptly.** Run `make security` and `make scan` after dependency updates.
94+
95+
## Notes
96+
97+
- These practices are enforced by code review, not by automated tooling. Automated enforcement is covered by the per-language tool standards.
98+
- When a practice here conflicts with a language-specific standard, the language-specific standard takes precedence.
99+
- These practices are embedded in every project's DEVELOPMENT.md via the DevRail template repos.
100+
- Full reference: [Coding Practices](https://gitlab.mfsoho.linkridge.net/OrgDocs/development-standards/-/blob/main/standards/coding-practices.md) and [Git Workflow](https://gitlab.mfsoho.linkridge.net/OrgDocs/development-standards/-/blob/main/standards/git-workflow.md) in the planning repo.

content/docs/standards/python.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,3 +139,4 @@ These tools run via `make security` and `make test` in CI pipelines:
139139
- **bandit and semgrep are complementary.** Bandit catches Python-specific issues, semgrep applies broader security patterns. Both run as part of `make security`.
140140
- **All tools are pre-installed in the dev-toolchain container.** Do not install them on the host machine.
141141
- **Python CLIs in DevRail repos use Click** for argument parsing (not argparse).
142+
- For cross-cutting coding practices and git workflow standards that apply to all languages, see [Coding Practices](/docs/standards/practices/).

content/docs/standards/ruby.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,3 +157,4 @@ repos:
157157
- **`sorbet` is optional.** Projects can incrementally adopt it by adding `# typed:` sigils to Ruby files. The `sorbet-runtime` gem provides runtime type annotations.
158158
- **All tools are pre-installed in the dev-toolchain container.** Do not install them on the host.
159159
- **Rails rspec in CI:** The dev-toolchain container handles static analysis (rubocop, reek, brakeman, bundler-audit) but Rails integration tests typically need a database service (Postgres, MySQL). In CI, run a separate rspec job with the project's own `ruby` image, Bundler, and a database service. The DevRail `make _test` target handles rspec for simple cases; use a dedicated CI job when your tests require external services.
160+
- For cross-cutting coding practices and git workflow standards that apply to all languages, see [Coding Practices](/docs/standards/practices/).

content/docs/standards/terraform.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,3 +169,4 @@ repos:
169169
- **`terraform-docs` runs as part of `make docs`.** Place `<!-- BEGIN_TF_DOCS -->` / `<!-- END_TF_DOCS -->` markers in your `README.md`.
170170
- **`terratest` tests are written in Go.** The `tests/` directory must contain a `go.mod` file.
171171
- **All tools are pre-installed in the dev-toolchain container.** Do not install them on the host.
172+
- For cross-cutting coding practices and git workflow standards that apply to all languages, see [Coding Practices](/docs/standards/practices/).

0 commit comments

Comments
 (0)