- Commented out 'View RF Links' button in network map node detail panel - Commented out RF Link health legend (Good/Degraded/Critical) from map legend - Backend code (topology.ex) left intact per instructions - No RF tab found on device show page (nothing to hide there) - All tests pass, compiles clean with --warnings-as-errors Reviewed-on: graham/towerops-web#46
3 KiB
3 KiB
Elixir Code Standards Policy
Effective: 2026-03-15 Owner: Engineering
Purpose
All Elixir code in TowerOps must be idiomatic, readable, and maintainable. This policy ensures consistency across the codebase and reduces cognitive load for contributors.
Standards
Pattern Matching Over Conditionals
- Use pattern matching in function heads instead of
if/casewhen branching on structure. - Prefer multi-clause functions over nested conditionals.
# Good
def process(%{status: :active} = device), do: ...
def process(%{status: :inactive} = device), do: ...
# Avoid
def process(device) do
if device.status == :active do
...
else
...
end
end
The Pipe Operator
- Use
|>for data transformation chains (3+ steps). - Never start a pipe with a raw value — assign or wrap it.
- Each step in a pipe should take the piped value as its first argument.
With Clauses
- Use
withfor sequences of dependent operations that may fail. - Always include an
elseclause that handles expected error shapes. - Keep
withchains under 5 clauses; extract helpers if longer.
Naming
- Modules:
PascalCase, mirroring directory structure. - Functions:
snake_case, verb-first (fetch_device/1,parse_response/1). - Private helpers: prefix with intent, not
do_(e.g.,build_querynotdo_query). - Boolean functions: end with
?(e.g.,active?/1).
Contexts (Phoenix)
- Business logic lives in context modules (
Towerops.Devices,Towerops.Alerts). - LiveViews and controllers call contexts — never Repo directly.
- Contexts return
{:ok, result}or{:error, reason}tuples. - Keep context functions focused; one public function per use case.
Error Handling
- Use tagged tuples (
{:ok, _}/{:error, _}) for expected failures. - Let unexpected failures crash — the supervisor will restart.
- Never rescue broadly (
rescue e ->) without re-raising or logging. - Use
Ecto.Multifor operations that must be atomic.
Documentation
- All public functions must have
@docand@spec. - Modules must have
@moduledocdescribing purpose and responsibilities. - Internal/private functions: document with comments only when non-obvious.
Testing
- Every public context function must have tests.
- Use
ExUnit.CaseTemplateand factories for setup. - Async tests (
async: true) unless they touch shared state (database). - Name tests descriptively:
"fetch_device/1 returns error when device not found".
Formatting
- Run
mix formatbefore every commit. CI will reject unformatted code. - Use
.formatter.exssettings; do not override line length (98 chars).
Dependencies
- Minimize external dependencies. Prefer stdlib and OTP.
- Every new dependency requires a brief justification in the PR description.
- Pin versions explicitly in
mix.exs.
Enforcement
- CI runs
mix format --check-formatted,mix credo --strict, andmix dialyzer. - Code review required for all merges to
main. - Violations block merge.