- Golang code standards are enforced specifically for user or agent-written code, not code that is automatically generated by tooling (example: unit test mocks)
- Receiver functions on structs should prefer
sas the variable name instead of the first letter of the struct type. - Named returns are not allowed; all return variables must be defined in the function.
- Group variable initializations in a
var ( ... )block and hoist them to the top of the function when possible. - Use
anyinstead ofinterface{}. - Prefer rich variables names, for example:
databaseInterfaceinstead ofdiordbi.
- Prefer pure functions: a function's result should depend only on its arguments, and it should not mutate arguments or other state owned by its caller.
- Do not pass in an array or object for a function to fill (an "out parameter"); return the result instead and let the caller combine it, for example:
problems.push(...checkKeys(raw, ['cards', 'docs'], 'config'))rather thancheckKeys(raw, ['cards', 'docs'], 'config', problems). - Mutating a local variable inside a function is fine, as long as the mutation is not visible to the caller until the value is returned.
- Keep side effects (throwing, logging, I/O) in the top-level or entry-point function rather than spreading them across helpers.
- Do not pass in an array or object for a function to fill (an "out parameter"); return the result instead and let the caller combine it, for example:
- Title format: : <Title>
- Always run
just prepare-for-codereviewbefore committing to perform tests and do code generation and license checks.
- If a test file is testing internal (non-exported) logic, the file may be included in the same package as the code being tested.
- If a test file is only testing the external (exported) pieces of code, the file should use the same package as the code being tested with
_testappended.- Example:
auth.gohaspackage api,auth_test.gois only testing exported logic inauth.goand should havepackage api_test
- Example:
- Integration tests should be separated from unit tests, such that if we have an
auth.gofile,auth_test.goshould have unit tests andauth_integration_test.goshould have integration tests. - Integration test files should have an
*integrationbuild tag at the top of the file, underneath the license header: example://go:build integrationor//go:build serial_integrationor//go:build slow_integration - Exception for vertical-slice features under
server/<feature>/: full-stack, production-routed tests that exercise the endpoint end-to-end through the real router and middleware use the<feature>_e2e_test.gosuffix, while layer-level integration tests (e.g. persistence against a real database) keep the*_integration_test.gosuffix. Both use the//go:build integrationbuild tag.
- The user should have run
just prepare-for-codereviewbefore creating a PR. This command runs tests locally, does code generation, adds license headers, and generates OpenAPI docs. - There is no 100% positive way to identify that a user has run
just prepare-for-codereview, but there are some smells to look for which indicate that a user might not have run it:- Code files must have a license header at the top of the file using a code comment block. The file
LICENSE.headerfile has an up-to-date version of the header. - The file located at
cmd/api/src/database/db.gocontains a Database interface type. This interface must be implemented by theMockDatabasestruct incmd/api/src/database/mocks/db.goand is generated bygo.uber.org/mock/mockgen. - If the code adds a new API endpoint, or it changes something about an existing API endpoint (url, models that get marshaled to JSON, query params, etc), there should probably be changes to the OpenAPI yaml files.
- If OpenAPI yaml files have been changed,
openapi.jsonshould also have corresponding changes. - If a PR migrates an endpoint to the
bhce/server/vertical-slice structure (or removes a legacy handler fromcmd/api/src), the author SHOULD update the migration tracker in Notion. Reviewers should verify that the Notion status reflects the PR's scope.
- Code files must have a license header at the top of the file using a code comment block. The file
- Migration files must use goose annotations:
-- +goose Upand-- +goose Down - Migration filenames must follow the pattern:
<timestamp>_<version>_<name>.sql- Timestamp:
YYYYMMDDHHMMSS - Version:
v9,v10, etc. (current major release) - Name: descriptive snake_case name
- Example:
20260514120000_v9_add_feature_flags.sql
- Timestamp:
- Never modify baseline migrations (
00000000000001_init.sqlor00000000000002_init.sql) - Never modify migrations that have already been merged to main. The user should create a new migration instead
- Migration locations:
- BHCE migrations:
cmd/api/src/database/migration/migrations/
- BHCE migrations: