@deftai/directive-content 0.55.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/deft/SKILL.md +6 -0
- package/.agents/skills/deft-directive-article-review/SKILL.md +11 -0
- package/.agents/skills/deft-directive-build/SKILL.md +10 -0
- package/.agents/skills/deft-directive-cost/SKILL.md +12 -0
- package/.agents/skills/deft-directive-debug/SKILL.md +13 -0
- package/.agents/skills/deft-directive-gh-arch/SKILL.md +11 -0
- package/.agents/skills/deft-directive-gh-slice/SKILL.md +10 -0
- package/.agents/skills/deft-directive-glossary/SKILL.md +10 -0
- package/.agents/skills/deft-directive-interview/SKILL.md +9 -0
- package/.agents/skills/deft-directive-pre-pr/SKILL.md +9 -0
- package/.agents/skills/deft-directive-refinement/SKILL.md +10 -0
- package/.agents/skills/deft-directive-release/SKILL.md +12 -0
- package/.agents/skills/deft-directive-review-cycle/SKILL.md +10 -0
- package/.agents/skills/deft-directive-setup/SKILL.md +10 -0
- package/.agents/skills/deft-directive-swarm/SKILL.md +10 -0
- package/.agents/skills/deft-directive-sync/SKILL.md +9 -0
- package/.agents/skills/deft-directive-triage/SKILL.md +9 -0
- package/.agents/skills/deft-directive-write-skill/SKILL.md +9 -0
- package/LICENSE.md +22 -0
- package/QUICK-START.md +167 -0
- package/UPGRADING.md +517 -0
- package/coding/build-output.md +28 -0
- package/coding/coding.md +235 -0
- package/coding/debugging.md +110 -0
- package/coding/holzmann.md +96 -0
- package/coding/hygiene.md +127 -0
- package/coding/security.md +158 -0
- package/coding/testing.md +162 -0
- package/coding/toolchain.md +44 -0
- package/commands.md +300 -0
- package/context/context.md +57 -0
- package/context/deterministic-split.md +67 -0
- package/context/examples.md +26 -0
- package/context/fractal-summaries.md +69 -0
- package/context/long-horizon.md +46 -0
- package/context/spec-deltas.md +177 -0
- package/context/tool-design.md +34 -0
- package/context/working-memory.md +62 -0
- package/contracts/boundary-maps.md +65 -0
- package/contracts/deterministic-questions.md +59 -0
- package/contracts/hierarchy.md +77 -0
- package/conventions/content-manifest.json +399 -0
- package/conventions/machine-generated-banner.md +130 -0
- package/conventions/references.md +120 -0
- package/conventions/rule-ownership.json +382 -0
- package/conventions/task-caching.md +43 -0
- package/conventions/vbrief-filenames.md +70 -0
- package/deployments/README.md +37 -0
- package/deployments/agentuity/README.md +138 -0
- package/deployments/agentuity/via-cli.md +380 -0
- package/deployments/agentuity/via-cloud.md +425 -0
- package/deployments/agentuity/via-github-actions.md +664 -0
- package/deployments/agentuity/via-gravity-network.md +606 -0
- package/deployments/agentuity/via-vpc.md +607 -0
- package/deployments/aws/README.md +38 -0
- package/deployments/aws/via-app-runner.md +612 -0
- package/deployments/aws/via-ecs-fargate.md +561 -0
- package/deployments/aws/via-elastic-beanstalk.md +628 -0
- package/deployments/aws/via-lambda.md +649 -0
- package/deployments/azure/README.md +37 -0
- package/deployments/azure/via-aks.md +390 -0
- package/deployments/azure/via-app-service.md +564 -0
- package/deployments/azure/via-container-apps.md +599 -0
- package/deployments/azure/via-functions.md +552 -0
- package/deployments/cloud-gov/README.md +63 -0
- package/deployments/cloud-gov/agents/compliance-docs.md +154 -0
- package/deployments/cloud-gov/agents.md +39 -0
- package/deployments/cloud-gov/cicd.md +64 -0
- package/deployments/cloud-gov/deployment.md +150 -0
- package/deployments/cloud-gov/logging.md +43 -0
- package/deployments/cloud-gov/manifest.md +121 -0
- package/deployments/cloud-gov/overview.md +58 -0
- package/deployments/cloud-gov/security.md +46 -0
- package/deployments/cloud-gov/services.md +72 -0
- package/deployments/cloud-gov/upstream/README.md +18 -0
- package/deployments/cloudflare/README.md +33 -0
- package/deployments/cloudflare/via-dashboard.md +83 -0
- package/deployments/cloudflare/via-git.md +90 -0
- package/deployments/cloudflare/via-github-actions.md +185 -0
- package/deployments/cloudflare/via-terraform.md +157 -0
- package/deployments/cloudflare/via-wrangler.md +165 -0
- package/deployments/fly-io/README.md +37 -0
- package/deployments/fly-io/via-dockerfile.md +648 -0
- package/deployments/fly-io/via-flyctl.md +653 -0
- package/deployments/fly-io/via-github-actions.md +695 -0
- package/deployments/fly-io/via-multi-region.md +598 -0
- package/deployments/google/README.md +34 -0
- package/deployments/google/via-app-engine.md +42 -0
- package/deployments/google/via-cloud-functions.md +23 -0
- package/deployments/google/via-cloud-run.md +330 -0
- package/deployments/google/via-gke.md +23 -0
- package/deployments/netlify/README.md +99 -0
- package/deployments/netlify/via-cli.md +17 -0
- package/deployments/netlify/via-functions.md +19 -0
- package/deployments/netlify/via-git.md +25 -0
- package/deployments/vercel/README.md +90 -0
- package/deployments/vercel/via-api.md +16 -0
- package/deployments/vercel/via-cli.md +17 -0
- package/deployments/vercel/via-git.md +24 -0
- package/docs/BROWNFIELD.md +179 -0
- package/docs/getting-started.md +137 -0
- package/docs/good-agents-md.md +137 -0
- package/events/README.md +89 -0
- package/events/event-record.schema.json +26 -0
- package/events/registry.json +166 -0
- package/events/registry.schema.json +71 -0
- package/glossary.md +145 -0
- package/incidents/README.md +81 -0
- package/incidents/_template.md +38 -0
- package/interfaces/cli.md +104 -0
- package/interfaces/rest.md +212 -0
- package/interfaces/tui.md +242 -0
- package/interfaces/web.md +123 -0
- package/languages/6502-DASM.md +132 -0
- package/languages/c.md +235 -0
- package/languages/commands.md +23 -0
- package/languages/cpp.md +132 -0
- package/languages/csharp.md +259 -0
- package/languages/dart.md +183 -0
- package/languages/delphi.md +218 -0
- package/languages/elixir.md +208 -0
- package/languages/go.md +78 -0
- package/languages/java.md +278 -0
- package/languages/javascript.md +163 -0
- package/languages/julia.md +175 -0
- package/languages/kotlin.md +193 -0
- package/languages/markdown.md +168 -0
- package/languages/mermaid.md +146 -0
- package/languages/officejs.md +392 -0
- package/languages/python.md +209 -0
- package/languages/r.md +163 -0
- package/languages/rust.md +216 -0
- package/languages/sql.md +216 -0
- package/languages/swift.md +153 -0
- package/languages/typescript.md +132 -0
- package/languages/vba.md +279 -0
- package/languages/vhdl.md +180 -0
- package/languages/visual-basic.md +151 -0
- package/languages/zig.md +196 -0
- package/meta/SOUL.md +27 -0
- package/meta/code-field.md +44 -0
- package/meta/morals.md +40 -0
- package/meta/philosophy.md +39 -0
- package/meta/project.md +49 -0
- package/meta/ralph.md +223 -0
- package/meta/security.md +80 -0
- package/meta/versioning.md +326 -0
- package/package.json +22 -0
- package/packs/lessons/lessons-pack-0.1.json +553 -0
- package/packs/patterns/patterns-pack-0.1.json +57 -0
- package/packs/rules/rules-pack-0.1.json +4767 -0
- package/packs/skills/skills-pack-0.1.json +262 -0
- package/packs/strategies/strategies-pack-0.1.json +167 -0
- package/packs/swarm-spec/swarm-spec-pack-0.1.json +17 -0
- package/patterns/executor-layer-credentials.md +227 -0
- package/patterns/llm-app.md +156 -0
- package/patterns/multi-agent.md +278 -0
- package/patterns/prompt-assembly-layer-ordering.md +154 -0
- package/patterns/role-as-overlay.md +179 -0
- package/platforms/2600.md +137 -0
- package/platforms/unity.md +329 -0
- package/references/composer-skill-porting.md +152 -0
- package/references/cost-models.md +163 -0
- package/references/ip-risk.md +246 -0
- package/references/plain-english-ux.md +275 -0
- package/resilience/context-pruning.md +67 -0
- package/resilience/continue-here.md +62 -0
- package/scm/changelog.md +276 -0
- package/scm/git.md +139 -0
- package/scm/github.md +265 -0
- package/secrets/.gitkeep +0 -0
- package/skills/deft-build/SKILL.md +20 -0
- package/skills/deft-directive-article-review/SKILL.md +156 -0
- package/skills/deft-directive-build/SKILL.md +302 -0
- package/skills/deft-directive-cost/SKILL.md +201 -0
- package/skills/deft-directive-debug/SKILL.md +140 -0
- package/skills/deft-directive-decompose/SKILL.md +96 -0
- package/skills/deft-directive-gh-arch/SKILL.md +160 -0
- package/skills/deft-directive-gh-slice/SKILL.md +199 -0
- package/skills/deft-directive-glossary/SKILL.md +118 -0
- package/skills/deft-directive-interview/SKILL.md +528 -0
- package/skills/deft-directive-pre-pr/SKILL.md +131 -0
- package/skills/deft-directive-probe/SKILL.md +127 -0
- package/skills/deft-directive-refinement/SKILL.md +403 -0
- package/skills/deft-directive-release/SKILL.md +266 -0
- package/skills/deft-directive-review-cycle/SKILL.md +401 -0
- package/skills/deft-directive-setup/SKILL.md +717 -0
- package/skills/deft-directive-swarm/SKILL.md +989 -0
- package/skills/deft-directive-sync/SKILL.md +288 -0
- package/skills/deft-directive-triage/SKILL.md +137 -0
- package/skills/deft-directive-write-skill/SKILL.md +169 -0
- package/skills/deft-interview/SKILL.md +16 -0
- package/skills/deft-pre-pr/SKILL.md +16 -0
- package/skills/deft-review-cycle/SKILL.md +16 -0
- package/skills/deft-roadmap-refresh/SKILL.md +16 -0
- package/skills/deft-setup/SKILL.md +20 -0
- package/skills/deft-swarm/SKILL.md +16 -0
- package/skills/deft-sync/SKILL.md +16 -0
- package/strategies/README.md +83 -0
- package/strategies/artifact-guards.md +85 -0
- package/strategies/bdd.md +115 -0
- package/strategies/brownfield.md +7 -0
- package/strategies/discuss.md +129 -0
- package/strategies/emit-hints.md +69 -0
- package/strategies/enterprise.md +193 -0
- package/strategies/interview.md +551 -0
- package/strategies/map.md +179 -0
- package/strategies/probe.md +151 -0
- package/strategies/rapid.md +155 -0
- package/strategies/research.md +155 -0
- package/strategies/roadmap.md +9 -0
- package/strategies/speckit.md +437 -0
- package/strategies/v0-20-contract.md +134 -0
- package/strategies/yolo.md +169 -0
- package/swarm/swarm.md +300 -0
- package/templates/COST-ESTIMATE.md +114 -0
- package/templates/PULL_REQUEST_TEMPLATE.md +35 -0
- package/templates/agent-prompt-preamble.md +409 -0
- package/templates/agents-entry.md +211 -0
- package/templates/agents-entry.placeholders.md +75 -0
- package/templates/embed.go +20 -0
- package/templates/embed_test.go +36 -0
- package/templates/make-spec-example.md +9 -0
- package/templates/make-spec.md +246 -0
- package/templates/project.md.template +52 -0
- package/templates/specification.md +1 -0
- package/templates/swarm-greptile-poller-prompt.md +556 -0
- package/templates/user.md.template +31 -0
- package/tools/RWLDL.md +80 -0
- package/tools/greptile.md +141 -0
- package/tools/installer.md +23 -0
- package/tools/taskfile-migration.md +32 -0
- package/tools/taskfile.md +185 -0
- package/tools/telemetry.md +285 -0
- package/vbrief/schemas/cache-meta.schema.json +137 -0
- package/vbrief/schemas/candidates.schema.json +130 -0
- package/vbrief/schemas/codebase-map.schema.json +213 -0
- package/vbrief/schemas/lessons-pack.schema.json +134 -0
- package/vbrief/schemas/patterns-pack.schema.json +84 -0
- package/vbrief/schemas/rules-pack.schema.json +105 -0
- package/vbrief/schemas/skills-pack.schema.json +94 -0
- package/vbrief/schemas/slices.schema.json +87 -0
- package/vbrief/schemas/strategies-pack.schema.json +89 -0
- package/vbrief/schemas/swarm-spec-pack.schema.json +84 -0
- package/vbrief/schemas/vbrief-core.schema.json +1022 -0
- package/vbrief/vbrief.md +684 -0
- package/verification/integration.md +76 -0
- package/verification/plan-checking.md +85 -0
- package/verification/uat.md +60 -0
- package/verification/verification.md +117 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# Elixir Standards
|
|
2
|
+
|
|
3
|
+
Legend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.
|
|
4
|
+
|
|
5
|
+
**⚠️ See also**: [main.md](../../main.md) | [PROJECT.md](../../PROJECT.md)
|
|
6
|
+
|
|
7
|
+
**Stack**: Elixir 1.16+ / OTP 26+; Build: Mix; Testing: ExUnit; Lint: Credo; Format: `mix format`; Docs: ExDoc; Types: Dialyxir
|
|
8
|
+
|
|
9
|
+
## Standards
|
|
10
|
+
|
|
11
|
+
### Documentation
|
|
12
|
+
- ! `@doc` and `@moduledoc` on all public modules and functions
|
|
13
|
+
- ! `@spec` typespecs on all public functions
|
|
14
|
+
- ! Include `## Examples` with `iex>` doctest blocks for public API
|
|
15
|
+
- ~ Use `@doc false` to explicitly hide internal public functions
|
|
16
|
+
- ~ Cross-reference with `{:link, module}` or backtick syntax
|
|
17
|
+
|
|
18
|
+
### Testing
|
|
19
|
+
See [testing.md](../coding/testing.md).
|
|
20
|
+
|
|
21
|
+
- ! Use ExUnit (`test`, `describe`, `assert`, `refute`)
|
|
22
|
+
- ! Place tests in `test/` mirroring `lib/` structure; files: `*_test.exs`
|
|
23
|
+
- ! Test happy paths, error cases, and edge cases
|
|
24
|
+
- ~ Use doctests (`doctest Module`) for example-based testing
|
|
25
|
+
- ~ Use `Mox` for mocking via behaviours (not concrete implementations)
|
|
26
|
+
- ~ Use property-based testing via `StreamData`
|
|
27
|
+
|
|
28
|
+
### Coverage
|
|
29
|
+
- ! ≥80% coverage (measured via `mix test --cover` or excoveralls)
|
|
30
|
+
- ! Count lib/**
|
|
31
|
+
- ! Exclude generated code, migrations, Phoenix boilerplate
|
|
32
|
+
|
|
33
|
+
### Style
|
|
34
|
+
- ! Run `mix format` on all code (project `.formatter.exs` checked in)
|
|
35
|
+
- ! Use Credo for static analysis (`mix credo --strict`)
|
|
36
|
+
- ! 2-space indentation
|
|
37
|
+
- ! Line length ≤98 characters (Elixir formatter default)
|
|
38
|
+
- ! Follow [Elixir Style Guide](https://github.com/christopheradams/elixir_style_guide)
|
|
39
|
+
|
|
40
|
+
### Naming Conventions
|
|
41
|
+
- ! `snake_case` for functions, variables, atoms, and file names
|
|
42
|
+
- ! `PascalCase` (CamelCase) for module names: `MyApp.UserService`
|
|
43
|
+
- ! `snake_case` for module file paths matching module name: `my_app/user_service.ex`
|
|
44
|
+
- ! Predicate functions end with `?`: `valid?`, `empty?`, `admin?`
|
|
45
|
+
- ! Dangerous/raising functions end with `!`: `fetch!`, `decode!`
|
|
46
|
+
- ! `SCREAMING_SNAKE_CASE` for module attributes used as constants (convention, not enforced)
|
|
47
|
+
- ⊗ Atoms with spaces or special characters unless protocol requires it
|
|
48
|
+
|
|
49
|
+
### Pattern Matching
|
|
50
|
+
- ! Use pattern matching for control flow (function heads, `case`, `with`)
|
|
51
|
+
- ! Prefer multi-clause functions over `if`/`cond` for type/shape dispatch
|
|
52
|
+
- ! Use `with` for chaining fallible operations with clear pattern matching
|
|
53
|
+
- ! Destructure in function arguments when possible
|
|
54
|
+
- ⊗ Nested `case` statements >2 levels deep — refactor into functions
|
|
55
|
+
- ≉ `if`/`else` when pattern matching is clearer
|
|
56
|
+
|
|
57
|
+
### Data & Immutability
|
|
58
|
+
- ! All data is immutable — embrace transformation pipelines
|
|
59
|
+
- ! Use structs (`%MyStruct{}`) for domain entities with enforced keys
|
|
60
|
+
- ! Use `@enforce_keys` for required struct fields
|
|
61
|
+
- ! Use maps for unstructured/dynamic data; keyword lists for options
|
|
62
|
+
- ~ Use Ecto embedded schemas for validated data structures
|
|
63
|
+
- ⊗ Atoms from user input (`String.to_atom/1`) — atom table is not garbage collected
|
|
64
|
+
|
|
65
|
+
### Pipe Operator
|
|
66
|
+
- ! Use `|>` for data transformation chains (≥2 steps)
|
|
67
|
+
- ! First argument flows through the pipe; design functions pipe-friendly
|
|
68
|
+
- ! One transformation per line in pipe chains
|
|
69
|
+
- ≉ Pipe chains >10 steps — extract named intermediate functions
|
|
70
|
+
- ≉ Pipes with anonymous functions — extract to named functions
|
|
71
|
+
|
|
72
|
+
### OTP & Concurrency
|
|
73
|
+
- ! Use OTP behaviours: `GenServer`, `Supervisor`, `Agent`, `Task`
|
|
74
|
+
- ! Supervision trees for all long-running processes
|
|
75
|
+
- ! Use `Task.async` / `Task.await` for concurrent one-off work
|
|
76
|
+
- ! Trap exits explicitly when needed; document why
|
|
77
|
+
- ! Design processes for "let it crash" — supervisors restart
|
|
78
|
+
- ⊗ Spawning bare processes without supervision in production
|
|
79
|
+
- ⊗ Shared mutable state outside of OTP processes
|
|
80
|
+
- ~ Use `Registry` for dynamic process naming
|
|
81
|
+
- ~ Use `GenStage` / `Broadway` for back-pressure and data pipelines
|
|
82
|
+
|
|
83
|
+
### Error Handling
|
|
84
|
+
- ! Use `{:ok, value}` / `{:error, reason}` tuples for expected failures
|
|
85
|
+
- ! Use `!` function variants that raise for unexpected/unrecoverable errors
|
|
86
|
+
- ! Use `with` for composing multiple `{:ok, _}` / `{:error, _}` chains
|
|
87
|
+
- ! Let processes crash on unexpected errors; supervisors handle recovery
|
|
88
|
+
- ⊗ Catching broad exceptions (`rescue Exception`) in normal flow
|
|
89
|
+
- ⊗ Returning bare `:error` without a reason
|
|
90
|
+
|
|
91
|
+
### Behaviours & Protocols
|
|
92
|
+
- ! Define `@callback` specs in behaviour modules
|
|
93
|
+
- ! Use behaviours for dependency injection / mocking boundaries
|
|
94
|
+
- ! Use protocols for polymorphic dispatch on data types
|
|
95
|
+
- ~ Use `defimpl` in the data type's module or in the protocol module (be consistent)
|
|
96
|
+
|
|
97
|
+
### Dependencies
|
|
98
|
+
- ! Manage via Mix (`mix.exs` deps); specify version constraints
|
|
99
|
+
- ! Use `mix.lock` committed for applications
|
|
100
|
+
- ! Minimize dependencies; prefer standard library and OTP
|
|
101
|
+
- ~ Run `mix hex.audit` for security advisories
|
|
102
|
+
- ~ Use `mix deps.audit` for outdated dependencies
|
|
103
|
+
|
|
104
|
+
### Phoenix (Web)
|
|
105
|
+
- ~ Follow Phoenix conventions: contexts for business logic, schemas for data
|
|
106
|
+
- ! Validate all inputs via Ecto changesets
|
|
107
|
+
- ! Use parameterized queries (Ecto handles this by default)
|
|
108
|
+
- ~ Use LiveView for real-time UI; channels for custom WebSocket protocols
|
|
109
|
+
- ⊗ Business logic in controllers — delegate to context modules
|
|
110
|
+
|
|
111
|
+
### Security
|
|
112
|
+
- ⊗ Hardcode secrets or credentials in source
|
|
113
|
+
- ! Use `Application.get_env` or `System.get_env` for secrets (runtime config)
|
|
114
|
+
- ! Validate all external inputs
|
|
115
|
+
- ⊗ `String.to_atom/1` on user input (denial-of-service vector)
|
|
116
|
+
- ~ Use `Plug.CSRFProtection` for web applications
|
|
117
|
+
|
|
118
|
+
### Telemetry
|
|
119
|
+
- ! Use `:telemetry` for instrumentation (Erlang standard)
|
|
120
|
+
- ~ Use `telemetry_metrics` + `telemetry_poller` for metrics collection
|
|
121
|
+
- ~ Use `Logger` with structured metadata
|
|
122
|
+
- ? OpenTelemetry via `opentelemetry_api` + `opentelemetry_exporter`
|
|
123
|
+
|
|
124
|
+
## Commands
|
|
125
|
+
|
|
126
|
+
See [commands.md](./commands.md).
|
|
127
|
+
|
|
128
|
+
## Patterns
|
|
129
|
+
|
|
130
|
+
### Pattern Matching & Pipelines
|
|
131
|
+
```elixir
|
|
132
|
+
defmodule MyApp.Parser do
|
|
133
|
+
@spec parse_value(String.t(), atom()) :: {:ok, term()} | {:error, atom()}
|
|
134
|
+
def parse_value(raw, :integer) do
|
|
135
|
+
case Integer.parse(raw) do
|
|
136
|
+
{val, ""} -> {:ok, val}
|
|
137
|
+
_ -> {:error, :invalid_integer}
|
|
138
|
+
end
|
|
139
|
+
end
|
|
140
|
+
def parse_value("true", :boolean), do: {:ok, true}
|
|
141
|
+
def parse_value("false", :boolean), do: {:ok, false}
|
|
142
|
+
def parse_value(_, :boolean), do: {:error, :invalid_boolean}
|
|
143
|
+
def parse_value(raw, :string) when is_binary(raw), do: {:ok, raw}
|
|
144
|
+
def parse_value(_, _), do: {:error, :unsupported_type}
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# with pipeline for composed operations
|
|
148
|
+
def create_user(params) do
|
|
149
|
+
with {:ok, v} <- validate_params(params),
|
|
150
|
+
{:ok, user} <- Repo.insert(User.changeset(%User{}, v)),
|
|
151
|
+
{:ok, _} <- Mailer.send_welcome(user) do
|
|
152
|
+
{:ok, user}
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### GenServer
|
|
158
|
+
```elixir
|
|
159
|
+
defmodule MyApp.Counter do
|
|
160
|
+
use GenServer
|
|
161
|
+
def start_link(opts \\ []), do: GenServer.start_link(__MODULE__, Keyword.get(opts, :initial, 0), name: __MODULE__)
|
|
162
|
+
def increment, do: GenServer.call(__MODULE__, :increment)
|
|
163
|
+
def value, do: GenServer.call(__MODULE__, :value)
|
|
164
|
+
@impl true
|
|
165
|
+
def init(initial), do: {:ok, initial}
|
|
166
|
+
@impl true
|
|
167
|
+
def handle_call(:increment, _from, n), do: {:reply, n + 1, n + 1}
|
|
168
|
+
def handle_call(:value, _from, n), do: {:reply, n, n}
|
|
169
|
+
end
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Testing (ExUnit)
|
|
173
|
+
```elixir
|
|
174
|
+
defmodule MyApp.ParserTest do
|
|
175
|
+
use ExUnit.Case, async: true
|
|
176
|
+
doctest MyApp.Parser
|
|
177
|
+
|
|
178
|
+
describe "parse_value/2" do
|
|
179
|
+
test "parses integer" do assert {:ok, 42} = MyApp.Parser.parse_value("42", :integer) end
|
|
180
|
+
test "rejects invalid" do assert {:error, _} = MyApp.Parser.parse_value("abc", :integer) end
|
|
181
|
+
test "parses booleans" do
|
|
182
|
+
assert {:ok, true} = MyApp.Parser.parse_value("true", :boolean)
|
|
183
|
+
assert {:error, _} = MyApp.Parser.parse_value("yes", :boolean)
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Anti-Patterns
|
|
190
|
+
|
|
191
|
+
Items marked ⊗ in Standards above are not repeated here.
|
|
192
|
+
|
|
193
|
+
- ≉ **`if`/`else` over pattern matching**: Use multi-clause functions or `case`
|
|
194
|
+
- ≉ **Nested `case` >2 deep**: Refactor into named functions
|
|
195
|
+
- ≉ **Anonymous functions in pipes**: Extract to named functions
|
|
196
|
+
- ≉ **Long `with` chains (>5 clauses)**: Break into smaller functions
|
|
197
|
+
|
|
198
|
+
## Compliance Checklist
|
|
199
|
+
|
|
200
|
+
- ! `@doc`, `@moduledoc`, `@spec` on all public API
|
|
201
|
+
- ! See [testing.md](../coding/testing.md) for testing requirements
|
|
202
|
+
- ! ExUnit + doctests; ≥80% coverage
|
|
203
|
+
- ! `mix format` + Credo (strict) + Dialyxir enforced
|
|
204
|
+
- ! Pattern matching and pipes for control flow; OTP for concurrency
|
|
205
|
+
- ! `{:ok, _}` / `{:error, reason}` tuples; `!` variants for raising
|
|
206
|
+
- ! Supervision trees for all production processes
|
|
207
|
+
- ⊗ Bare `spawn`, `String.to_atom/1` on input, broad `rescue`, logic in controllers
|
|
208
|
+
- ! Run `task check` before commit
|
package/languages/go.md
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Go Standards
|
|
2
|
+
|
|
3
|
+
Legend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.
|
|
4
|
+
|
|
5
|
+
**⚠️ See also**: [main.md](../../main.md) | [PROJECT.md](../../PROJECT.md) | [telemetry.md](../tools/telemetry.md)
|
|
6
|
+
|
|
7
|
+
## Standards
|
|
8
|
+
|
|
9
|
+
### Documentation
|
|
10
|
+
- ! Follow [go.dev/doc/comment](https://go.dev/doc/comment)
|
|
11
|
+
- ! All exported symbols have doc comments (complete sentences)
|
|
12
|
+
|
|
13
|
+
### Testing
|
|
14
|
+
See [testing.md](../coding/testing.md).
|
|
15
|
+
|
|
16
|
+
- ! Use Testify (assert/require)
|
|
17
|
+
- Files: `*_test.go`, functions: `TestFuncName(t *testing.T)`
|
|
18
|
+
|
|
19
|
+
### Coverage
|
|
20
|
+
- ! ≥85% coverage
|
|
21
|
+
- ! Count internal/\* + pkg/\*
|
|
22
|
+
- ! Exclude entry points, utilities, generated code
|
|
23
|
+
|
|
24
|
+
### Telemetry
|
|
25
|
+
- See [telemetry.md](../tools/telemetry.md)
|
|
26
|
+
- ~ Structured logging (zerolog) for production
|
|
27
|
+
- ~ Sentry.io for error tracking
|
|
28
|
+
- ? OpenTelemetry for distributed tracing
|
|
29
|
+
|
|
30
|
+
## Commands
|
|
31
|
+
|
|
32
|
+
See [commands.md](./commands.md).
|
|
33
|
+
|
|
34
|
+
## 🔧 Patterns
|
|
35
|
+
|
|
36
|
+
**Table-Driven Tests**:
|
|
37
|
+
|
|
38
|
+
```go
|
|
39
|
+
tests := []struct{name string; input, want Type; wantErr bool}{
|
|
40
|
+
{"case1", input1, want1, false},
|
|
41
|
+
{"error", input2, want2, true},
|
|
42
|
+
}
|
|
43
|
+
for _, tt := range tests {
|
|
44
|
+
t.Run(tt.name, func(t *testing.T) {
|
|
45
|
+
got, err := Fn(tt.input)
|
|
46
|
+
if tt.wantErr { assert.Error(t, err); return }
|
|
47
|
+
assert.NoError(t, err)
|
|
48
|
+
assert.Equal(t, tt.want, got)
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**HTTP**: `w := httptest.NewRecorder(); req, _ := http.NewRequest("GET", "/path", nil); handler.ServeHTTP(w, req); assert.Equal(t, http.StatusOK, w.Code)`
|
|
54
|
+
|
|
55
|
+
**Interface**: Define consumer-side, mock with function fields
|
|
56
|
+
|
|
57
|
+
## Hygiene
|
|
58
|
+
|
|
59
|
+
**Types:**
|
|
60
|
+
- ⊗ `any` (empty interface) where a concrete type or typed interface is knowable; use generics or explicit interfaces
|
|
61
|
+
|
|
62
|
+
**Error handling:**
|
|
63
|
+
- ⊗ Ignore errors with `_` — every error MUST be checked or explicitly propagated with a reason
|
|
64
|
+
- ⊗ Empty `recover` blocks that swallow panics silently
|
|
65
|
+
|
|
66
|
+
**Dead code:**
|
|
67
|
+
- ~ Run `staticcheck` (detects unused code, unreachable branches) and `deadcode` (golang.org/x/tools/cmd/deadcode) before releases
|
|
68
|
+
- ⊗ Unexported functions that are never called anywhere in the package
|
|
69
|
+
|
|
70
|
+
**Circular dependencies:**
|
|
71
|
+
- The Go compiler rejects import cycles — treat them as build failures, not warnings
|
|
72
|
+
- ! Resolve by extracting shared types to a lower-level package; do not re-order imports
|
|
73
|
+
|
|
74
|
+
## Compliance Checklist
|
|
75
|
+
|
|
76
|
+
- ! Follow go.dev/doc/comment for all exported symbols
|
|
77
|
+
- ! See [testing.md](../coding/testing.md) for testing requirements
|
|
78
|
+
- ! Run `task check` before commit
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
# Java Standards
|
|
2
|
+
|
|
3
|
+
Legend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.
|
|
4
|
+
|
|
5
|
+
**⚠️ See also**: [main.md](../../main.md) | [PROJECT.md](../../PROJECT.md) | [telemetry.md](../tools/telemetry.md)
|
|
6
|
+
|
|
7
|
+
**Stack**: Java 21+ (LTS), Maven/Gradle; Web: Spring Boot 3+; Testing: JUnit 5 + Mockito + AssertJ; Analysis: Checkstyle, SpotBugs, Error Prone
|
|
8
|
+
|
|
9
|
+
## Standards
|
|
10
|
+
|
|
11
|
+
### Documentation
|
|
12
|
+
- ! Javadoc on all public classes, interfaces, methods, and constants
|
|
13
|
+
- ! Document `@param`, `@return`, `@throws` for public/protected methods
|
|
14
|
+
- ~ Use `@since` tags when adding public API to existing libraries
|
|
15
|
+
- ~ Use `{@code}` and `{@link}` for inline references
|
|
16
|
+
|
|
17
|
+
### Testing
|
|
18
|
+
See [testing.md](../coding/testing.md).
|
|
19
|
+
|
|
20
|
+
- ! Use JUnit 5 (`@Test`, `@ParameterizedTest`, `@Nested`)
|
|
21
|
+
- ! Use Mockito for mocking; AssertJ for fluent assertions
|
|
22
|
+
- ≉ Use JUnit 4 for new code (maintain existing suites only)
|
|
23
|
+
- Files: `*Test.java` or `*Tests.java` in `src/test/java`
|
|
24
|
+
|
|
25
|
+
### Coverage
|
|
26
|
+
- ! ≥85% coverage
|
|
27
|
+
- ! Count src/main/\*
|
|
28
|
+
- ! Exclude entry points, generated code, framework config
|
|
29
|
+
|
|
30
|
+
### Style
|
|
31
|
+
- ! Follow [Google Java Style Guide](https://google.github.io/styleguide/javaguide.html)
|
|
32
|
+
- ! Use Checkstyle (project `checkstyle.xml` required)
|
|
33
|
+
- ! Use SpotBugs or Error Prone for static analysis
|
|
34
|
+
- ! Column limit: 100 characters
|
|
35
|
+
- ! 2 or 4 space indentation (pick one, enforce via formatter)
|
|
36
|
+
|
|
37
|
+
### Naming Conventions
|
|
38
|
+
- ! `PascalCase` for classes, interfaces, enums, records, annotations
|
|
39
|
+
- ! `camelCase` for methods, fields, local variables, parameters
|
|
40
|
+
- ! `UPPER_SNAKE_CASE` for `static final` constants
|
|
41
|
+
- ! Package names all lowercase: `com.example.myapp.service`
|
|
42
|
+
- ! Test classes named `{ClassName}Test`: `UserServiceTest`
|
|
43
|
+
- ~ Interfaces without `I` prefix; use nouns/adjectives: `Repository`, `Serializable`
|
|
44
|
+
- ⊗ Hungarian notation or type prefixes
|
|
45
|
+
|
|
46
|
+
### Modern Language Features (Java 21+)
|
|
47
|
+
- ! Use `record` for immutable data carriers (DTOs, value objects)
|
|
48
|
+
- ! Use `sealed` classes/interfaces for restricted type hierarchies
|
|
49
|
+
- ! Use pattern matching in `switch` and `instanceof`
|
|
50
|
+
- ! Use text blocks (`"""`) for multi-line strings (SQL, JSON, etc.)
|
|
51
|
+
- ~ Use `var` for local variables when type is obvious from context
|
|
52
|
+
- ~ Use virtual threads (`Executors.newVirtualThreadPerTaskExecutor()`) for I/O-bound concurrency
|
|
53
|
+
- ≉ Use `var` when it obscures the type or reduces readability
|
|
54
|
+
|
|
55
|
+
### Types & Null Safety
|
|
56
|
+
- ! Use `Optional<T>` for return types that may be absent; ⊗ return `null` from public methods
|
|
57
|
+
- ! Use `@Nullable`/`@NonNull` annotations (JSpecify or JSR 305) on API boundaries
|
|
58
|
+
- ⊗ Use raw generic types (`List` instead of `List<String>`)
|
|
59
|
+
- ⊗ Use `Object` where a specific type or generic is appropriate
|
|
60
|
+
- ~ Prefer immutable collections (`List.of()`, `Map.of()`, `Set.of()`, `Collections.unmodifiable*`)
|
|
61
|
+
- ~ Use `enum` for fixed sets of constants; ⊗ string/int constants for enumerable values
|
|
62
|
+
|
|
63
|
+
### Records & Sealed Types
|
|
64
|
+
- ! Use `record` instead of manual POJO/DTO boilerplate
|
|
65
|
+
- ! Use `sealed` for closed hierarchies (event types, result types, AST nodes)
|
|
66
|
+
- ~ Use compact constructors in records for validation
|
|
67
|
+
- ⊗ Add mutable state to records (they are immutable by design)
|
|
68
|
+
|
|
69
|
+
### Resource Management
|
|
70
|
+
- ! Use try-with-resources for all `AutoCloseable` resources
|
|
71
|
+
- ⊗ Manually call `.close()` in a `finally` block (use try-with-resources instead)
|
|
72
|
+
- ! Close streams, connections, readers/writers on all code paths
|
|
73
|
+
- ~ Use `Cleaner` or `PhantomReference` for native resource cleanup (not `finalize()`)
|
|
74
|
+
- ⊗ Override `finalize()` — deprecated and removed in Java 18+
|
|
75
|
+
|
|
76
|
+
### Error Handling
|
|
77
|
+
- ! Use checked exceptions for recoverable errors; unchecked for programming bugs
|
|
78
|
+
- ! Catch the most specific exception type, not `Exception` or `Throwable`
|
|
79
|
+
- ! Include context in exception messages (what failed, relevant IDs/values)
|
|
80
|
+
- ⊗ Swallow exceptions (empty catch blocks)
|
|
81
|
+
- ⊗ Use exceptions for flow control
|
|
82
|
+
- ~ Create domain-specific exception hierarchies extending `RuntimeException`
|
|
83
|
+
- ~ Use `Optional` instead of throwing for "not found" scenarios in query methods
|
|
84
|
+
- ~ Log exceptions at the boundary where they are handled, not where they are caught and rethrown
|
|
85
|
+
|
|
86
|
+
### Collections & Streams
|
|
87
|
+
- ! Prefer `List.of()`, `Map.of()`, `Set.of()` for immutable collections
|
|
88
|
+
- ! Use Streams for transformation pipelines; ⊗ for simple iterations with side effects
|
|
89
|
+
- ~ Prefer `Stream.toList()` (Java 16+) over `Collectors.toList()` for unmodifiable results
|
|
90
|
+
- ≉ Modify collections during iteration; use `Iterator.remove()` or build a new collection
|
|
91
|
+
- ⊗ Use `Vector`, `Hashtable`, `Stack` — use `ArrayList`, `HashMap`, `ArrayDeque` instead
|
|
92
|
+
|
|
93
|
+
### Concurrency
|
|
94
|
+
- ! Use virtual threads (Java 21+) for I/O-bound workloads
|
|
95
|
+
- ! Use `ReentrantLock` over `synchronized` when using virtual threads (avoids carrier thread pinning)
|
|
96
|
+
- ! Use `ExecutorService` with try-with-resources; ⊗ create raw `Thread` instances
|
|
97
|
+
- ~ Use `CompletableFuture` for async composition when virtual threads are not appropriate
|
|
98
|
+
- ~ Use `ConcurrentHashMap`, `CopyOnWriteArrayList` for concurrent data structures
|
|
99
|
+
- ⊗ Use `Thread.stop()`, `Thread.suspend()`, `Thread.resume()` — all deprecated/removed
|
|
100
|
+
- ≉ Use `ThreadLocal` heavily with virtual threads (high memory overhead at scale)
|
|
101
|
+
|
|
102
|
+
### Dependency Injection
|
|
103
|
+
- ! Use constructor injection; ⊗ field injection (untestable, hides dependencies)
|
|
104
|
+
- ! Keep constructors focused — inject interfaces, not implementations
|
|
105
|
+
- ~ Use `@Qualifier` or custom annotations to disambiguate beans
|
|
106
|
+
- ≉ Use `@Autowired` on fields; prefer `final` fields with constructor injection
|
|
107
|
+
|
|
108
|
+
### Database
|
|
109
|
+
- ! Use parameterized queries / prepared statements; ⊗ string concatenation for SQL
|
|
110
|
+
- ! Use connection pooling (HikariCP)
|
|
111
|
+
- ~ Use Spring Data JPA or jOOQ; ≉ raw JDBC for application code
|
|
112
|
+
- ~ Wrap multi-step operations in explicit `@Transactional` boundaries
|
|
113
|
+
- ⊗ Use `Statement` with user-supplied input (SQL injection risk)
|
|
114
|
+
|
|
115
|
+
### Telemetry
|
|
116
|
+
- See [telemetry.md](../tools/telemetry.md)
|
|
117
|
+
- ~ Structured logging (SLF4J + Logback/Log4j2) for production
|
|
118
|
+
- ~ Sentry.io for error tracking
|
|
119
|
+
- ~ Micrometer for metrics
|
|
120
|
+
- ? OpenTelemetry Java for distributed tracing
|
|
121
|
+
|
|
122
|
+
### Safety
|
|
123
|
+
- ⊗ Hardcode secrets, keys, or credentials in source
|
|
124
|
+
- ! Validate all external input (user, file, network)
|
|
125
|
+
- ! Use `SecurityManager`-independent security practices (removed in Java 24)
|
|
126
|
+
- ~ Keep dependencies up to date; scan with OWASP Dependency-Check or Snyk
|
|
127
|
+
|
|
128
|
+
## Commands
|
|
129
|
+
|
|
130
|
+
See [commands.md](./commands.md).
|
|
131
|
+
|
|
132
|
+
## Patterns
|
|
133
|
+
|
|
134
|
+
### Testing (JUnit 5 + AssertJ + Mockito)
|
|
135
|
+
```java
|
|
136
|
+
class CalculatorTest {
|
|
137
|
+
private Calculator sut;
|
|
138
|
+
@BeforeEach void setUp() { sut = new Calculator(); }
|
|
139
|
+
|
|
140
|
+
@Test void addPositiveNumbers() { assertThat(sut.add(2, 3)).isEqualTo(5); }
|
|
141
|
+
|
|
142
|
+
@ParameterizedTest @CsvSource({"0,1,1", "-1,1,0", "100,200,300"})
|
|
143
|
+
void addParameterized(int a, int b, int expected) {
|
|
144
|
+
assertThat(sut.add(a, b)).isEqualTo(expected);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
@Nested class WhenDividingByZero {
|
|
148
|
+
@Test void throwsArithmeticException() {
|
|
149
|
+
assertThatThrownBy(() -> sut.divide(10, 0))
|
|
150
|
+
.isInstanceOf(ArithmeticException.class);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
@ExtendWith(MockitoExtension.class)
|
|
156
|
+
class UserServiceTest {
|
|
157
|
+
@Mock UserRepository userRepository;
|
|
158
|
+
@InjectMocks UserService userService;
|
|
159
|
+
|
|
160
|
+
@Test void findById_existingUser_returnsUser() {
|
|
161
|
+
var expected = new User(1L, "alice");
|
|
162
|
+
when(userRepository.findById(1L)).thenReturn(Optional.of(expected));
|
|
163
|
+
assertThat(userService.findById(1L)).isPresent().contains(expected);
|
|
164
|
+
verify(userRepository).findById(1L);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Records, Sealed Types & Pattern Matching
|
|
170
|
+
```java
|
|
171
|
+
public record UserDto(long id, String name, String email) {
|
|
172
|
+
public UserDto {
|
|
173
|
+
if (name == null || name.isBlank()) throw new IllegalArgumentException("name required");
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
public sealed interface Result<T> permits Success, Failure {
|
|
178
|
+
record Success<T>(T value) implements Result<T> {}
|
|
179
|
+
record Failure<T>(String error, Exception cause) implements Result<T> {}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
String describe(Result<?> r) { return switch (r) {
|
|
183
|
+
case Result.Success<?> s -> "OK: " + s.value();
|
|
184
|
+
case Result.Failure<?> f -> "Error: " + f.error();
|
|
185
|
+
}; }
|
|
186
|
+
|
|
187
|
+
// instanceof pattern matching
|
|
188
|
+
if (shape instanceof Circle c) return Math.PI * c.radius() * c.radius();
|
|
189
|
+
|
|
190
|
+
// switch pattern matching (Java 21+)
|
|
191
|
+
return switch (obj) {
|
|
192
|
+
case Integer i when i < 0 -> "Negative: " + i;
|
|
193
|
+
case Integer i -> "Integer: " + i;
|
|
194
|
+
case String s -> "String: " + s.toUpperCase();
|
|
195
|
+
case null -> "null";
|
|
196
|
+
default -> "Unknown: " + obj;
|
|
197
|
+
};
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Virtual Threads & Resources
|
|
201
|
+
```java
|
|
202
|
+
try (var executor = Executors.newVirtualThreadPerTaskExecutor()) {
|
|
203
|
+
var futures = urls.stream().map(url -> executor.submit(() -> fetchUrl(url))).toList();
|
|
204
|
+
for (var f : futures) process(f.get());
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// ReentrantLock (not synchronized) with virtual threads
|
|
208
|
+
private final ReentrantLock lock = new ReentrantLock();
|
|
209
|
+
void safeUpdate() { lock.lock(); try { /* critical */ } finally { lock.unlock(); } }
|
|
210
|
+
|
|
211
|
+
// try-with-resources
|
|
212
|
+
try (var conn = ds.getConnection();
|
|
213
|
+
var stmt = conn.prepareStatement("SELECT * FROM users WHERE id = ?")) {
|
|
214
|
+
stmt.setLong(1, userId);
|
|
215
|
+
try (var rs = stmt.executeQuery()) { if (rs.next()) return Optional.of(mapUser(rs)); }
|
|
216
|
+
}
|
|
217
|
+
return Optional.empty();
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Build Configuration
|
|
221
|
+
|
|
222
|
+
**Key requirements** (Maven or Gradle):
|
|
223
|
+
- ! Java 21+ toolchain, UTF-8 encoding
|
|
224
|
+
- ! Test deps: `junit-jupiter`, `assertj-core`, `mockito-junit-jupiter`
|
|
225
|
+
- ! JaCoCo with `minimum = 0.85` line coverage
|
|
226
|
+
- ! SpotBugs plugin for static analysis
|
|
227
|
+
|
|
228
|
+
**Gradle** (`build.gradle.kts`):
|
|
229
|
+
```kotlin
|
|
230
|
+
plugins { java; jacoco; id("com.github.spotbugs") version "6.0.0" }
|
|
231
|
+
java { toolchain { languageVersion = JavaLanguageVersion.of(21) } }
|
|
232
|
+
dependencies {
|
|
233
|
+
testImplementation("org.junit.jupiter:junit-jupiter:5.11.0")
|
|
234
|
+
testImplementation("org.assertj:assertj-core:3.26.0")
|
|
235
|
+
testImplementation("org.mockito:mockito-junit-jupiter:5.14.0")
|
|
236
|
+
}
|
|
237
|
+
tasks.test { useJUnitPlatform() }
|
|
238
|
+
tasks.jacocoTestCoverageVerification {
|
|
239
|
+
violationRules { rule { limit { minimum = "0.85".toBigDecimal() } } }
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Anti-Patterns
|
|
244
|
+
|
|
245
|
+
Items marked ⊗ in Standards above are not repeated here.
|
|
246
|
+
|
|
247
|
+
- ≉ **Checked exceptions for everything**: Reserve for truly recoverable conditions
|
|
248
|
+
- ≉ **God classes**: Keep <500 lines; extract service/strategy/helper
|
|
249
|
+
- ≉ **`Collectors.toList()`**: Prefer `Stream.toList()` (Java 16+)
|
|
250
|
+
|
|
251
|
+
## Hygiene
|
|
252
|
+
|
|
253
|
+
**Types:**
|
|
254
|
+
- ⊗ Raw types (`List`, `Map`, `Optional`) without type parameters — always parameterize
|
|
255
|
+
- ⊗ `Object` as parameter or return type where a concrete type or bounded wildcard is knowable
|
|
256
|
+
- ⊗ `@SuppressWarnings("unchecked")` without an inline comment proving the cast is safe
|
|
257
|
+
|
|
258
|
+
**Error handling:**
|
|
259
|
+
- ⊗ Empty `catch (Exception e) {}` — handle, log with context, or re-throw as a typed exception
|
|
260
|
+
- ⊗ `e.printStackTrace()` as the sole handler — use structured logging and propagate or wrap
|
|
261
|
+
- ⊗ Returning `null` from public methods to signal failure — use `Optional<T>` or throw
|
|
262
|
+
|
|
263
|
+
**Dead code:**
|
|
264
|
+
- ~ SpotBugs (in build config) detects `DLS_DEAD_LOCAL_STORE` and unreachable code
|
|
265
|
+
- ~ PMD rules `UnusedPrivateMethod` and `UnusedPrivateField` catch dead private symbols
|
|
266
|
+
- ~ Run `gradle dependencies --configuration runtimeClasspath` to audit unused dependencies
|
|
267
|
+
|
|
268
|
+
## Compliance Checklist
|
|
269
|
+
|
|
270
|
+
- ! Javadoc on all public APIs
|
|
271
|
+
- ! See [testing.md](../coding/testing.md) for testing requirements
|
|
272
|
+
- ! Use JUnit 5 + AssertJ + Mockito
|
|
273
|
+
- ! Use records for data carriers; sealed types for closed hierarchies
|
|
274
|
+
- ! Use virtual threads for I/O-bound concurrency (Java 21+)
|
|
275
|
+
- ! Try-with-resources for all `AutoCloseable`; ⊗ manual `.close()`
|
|
276
|
+
- ⊗ Return `null` from public methods; raw types; field injection
|
|
277
|
+
- ⊗ `synchronized` with virtual threads
|
|
278
|
+
- ! Run `task check` before commit
|