Documentation
Ensure that code is understandable, maintainable, and easy to onboard by documenting public APIs, business logic, architectural decisions, and non-obvious implementation details.
Clear and consistent documentation strengthens team communication, reduces bugs caused by misunderstandings, and acts as a reliable knowledge base across both frontend and backend codebases.
Document public APIs and components
Any exported utility, hook, class, or React component should include clear documentation about what it does, what parameters it expects, and what it returns. This helps other developers (or future you) use the module without diving into the implementation.
1export function calculateTax(value: number) {
2 // ...
3}
1/**
2 * Calculates tax based on the provided base value.
3 * @param value - The amount before tax.
4 * @returns The calculated tax amount.
5 */
6export function calculateTax(value: number): number {
7 // ...
8}
Write meaningful comments only
Avoid comments that simply repeat what the code already says. Instead, explain why something is done or call out edge cases, assumptions, or non-obvious intent. Comments should add context, not noise.
1// Increment i
2i++;
1// i starts at -1 to ensure the first run skips validation
2i++;
Keep comments up-to-date
Comments must reflect the current behavior of the code. If the implementation changes, outdated comments can cause confusion and bugs. Always revise or remove stale comments when updating code.
Use JSDoc/TSDoc
Use structured comments (JSDoc or TSDoc) to document utility functions, type aliases, interfaces, and class methods. This improves autocomplete, IDE support, and onboarding speed — especially in shared codebase
1function normalizePrice(price: number): number {
2 return Math.round(price * 100) / 100;
3}
1/**
2 * Rounds a price to two decimal places.
3 * @param price - Raw numeric price
4 * @returns Rounded price as number
5 */
6function normalizePrice(price: number): number {
7 return Math.round(price * 100) / 100;
8}
Explain business logic and side effects
If a function contains domain-specific rules or side effects (e.g., time zone logic, payment validation, async updates), add a comment to explain the reasoning. This clarifies intent for teammates and your future self.
1function calculateDiscount(user) {
2 if (user.tier === 'gold') return 0.1;
3 return 0;
4}
1function calculateDiscount(user) {
2 // Gold members always receive a 10% discount — this is a fixed business rule.
3 if (user.tier === 'gold') return 0.1;
4 return 0;
5}
Document environment variables and configs
Clearly list required environment variables (like API keys, ports, secrets) in a .env.example
or README
, along with descriptions and value expectations. For sensitive configs, explain format and fallback logic in code
1.env
2API_KEY=
3DB_URI=
1# API key for external payment provider (Stripe)
2API_KEY=pk_test_...
3
4# Database connection string (MongoDB or PostgreSQL)
5DB_URI=postgres://user:pass@localhost:5432/mydb
Include README in feature or package folders
When a folder contains a distinct module, feature, or package, include a README.md
to explain its purpose, usage, structure, and any design decisions. This is especially helpful in monorepos and domain-based front/backend systems.
1/src/features/user/
2 README.md
3 index.ts
4 controller.ts
5 service.ts
Link to related resources or decisions
If a piece of code is tied to an architectural decision, ticket, or external document (e.g., design spec, API contract), include a short comment with the relevant link. This adds valuable context without bloating the code.
1// some magic formula
2const tax = base * 1.093;
1// Using NY state tax rate (source: https://example.com/tax-policy)
2const tax = base * 1.093;
Document API routes clearly
Every API route should be documented with its method, expected parameters, response shape, and possible errors. You can do this via Swagger/OpenAPI, comments, or decorators (e.g. in NestJS). This makes your backend self-explanatory for frontend devs and third-party consumers.
router.post('/users', createUser);
1/**
2 * POST /users
3 * Creates a new user account.
4 * Body: { email: string, password: string }
5 * Response: 201 Created { id: string }
6 * Errors: 400 Bad Request, 409 Conflict
7 */
8router.post('/users', createUser);
Tip: Prefer Swagger (OpenAPI) decorators or generators in production APIs for consistency and automation.
Use storybook or MDX for UI components
For reusable UI components, write interactive docs using Storybook (or MDX). Document each variant and prop clearly. This acts as living documentation and helps other devs or designers understand usage without reading the code.
1// Button.stories.tsx
2export const Primary = () => <Button variant="primary">Click me</Button>;
1## Button
2
3Use `variant` to switch styles. The component supports all native `button` attributes.
Document domain logic and design decisions
In business-critical or domain-driven code, explain why a rule or structure exists — especially if it’s non-trivial or reflects a strategic decision (e.g., CQRS, DDD, or layered architecture). Use comments, ADRs, or docs/
folders.
1function recalculateBonus() {
2 // domain logic here
3}
1/**
2 * This logic is based on the new 2024 commission policy:
3 * - Agents are scored quarterly
4 * - Bonuses depend on both sales volume and client retention
5 * Full spec: [internal-link]/docs/commission-rules-2024
6 */
7function recalculateBonus() {
8 ...
9}