Code Conventions

Code Conventions

Why We Have Conventions

Code conventions aren’t about being pedantic—they’re about making collaboration easier. When everyone follows the same patterns, you can jump into any SEAD Club project and immediately understand how it’s organized, how commits are structured, and what the code is doing.

Think of conventions like traffic rules: they work because everyone agrees to follow them. Your code might work fine without these conventions, but working with others requires consistency.

The goal: Write code that’s easy to read, review, and maintain by anyone in the club, not just you.


Understanding Priority Levels

Note: The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document follow RFC 2119 standards.

  • MUST = Required, no exceptions
  • SHOULD = Strongly recommended
  • MAY = Optional, use your judgment

When creating or working on issues, use these priority levels:

  • Low – Small improvements, nice-to-haves, polish (e.g., “Update button hover color”)
  • Normal – Standard features and bug fixes (most issues fall here)
  • High – Important features or bugs that significantly impact users
  • Blocker – Critical issues that prevent other work from happening (e.g., “Build is broken,” “Can’t deploy”)

Estimation Guidelines

Estimate how long an issue will take:

  • Hours – 1-8 hours of work
  • Days – 1-7 days of work
  • Weeks – 1-2 weeks of work

If something will take longer than 2 weeks, break it into smaller issues. Large issues are hard to estimate, review, and track. Smaller issues give you a sense of progress and make it easier to parallelize work.


Repository Setup

Merge Strategy

  • Repositories MUST allow either merge commits or rebase merging
  • Repositories MUST NOT allow squash merging

Why? We want to preserve commit history for context and learning. Squash merging destroys the history of how a feature was built, which makes it harder to understand decisions later.

Branch Protection

  • The main branch MUST be named main
  • The main branch MUST be protected (require PR reviews, no direct commits)
  • The main branch MUST NOT be force-pushed (force pushing rewrites history and breaks things for everyone)

Translation: Don’t commit directly to main. Always work on a branch and open a PR.


Branch Naming

When creating a new branch, follow this pattern:

<type>/#<issue-number>/optional-description

Types come from Conventional Commits:

  • feat – New feature
  • fix – Bug fix
  • docs – Documentation changes
  • refactor – Code restructuring without changing behavior
  • test – Adding or updating tests
  • chore – Maintenance tasks (dependencies, config, etc.)

Examples:

feat/#42/user-authentication
fix/#89/mobile-navbar-overflow
docs/#12/update-api-guide
refactor/#156/database-connection
test/#203/add-login-tests
chore/#78/update-dependencies

Why the issue number? It makes it easy to connect the branch to its GitHub issue for context.


Commit Messages

Follow Conventional Commits v1.0.0 standard.

Format

<type>(#<issue-number>): <short description>

[optional longer description]

[optional footer with "Fixes #X" or "Closes #X"]

Examples

Good commits:

feat(#42): add JWT authentication for user login

fix(#89): resolve navbar overflow on mobile screens

docs(#12): update API endpoint documentation

refactor(#156): switch to connection pooling for database

test(#203): add unit tests for login validation

Bad commits:

updated stuff
fixed bug
changes
asdfasdf
WIP

Guidelines

  • Include the issue number in the scope (the part in parentheses)
  • Keep the summary under 50 characters when possible
  • Use present tense (“add feature” not “added feature”)
  • Explain what and why, not how (the code shows how)
  • Sign off your commits (SHOULD, not required): git commit -s

For larger changes, add more detail in the body:

refactor(#156): switch to connection pooling for database

The previous approach created a new connection for each request,
which caused performance issues under load. Connection pooling
reuses connections and limits the total number open.

Tested with 1000 concurrent requests - response time improved
from 500ms to 80ms average.

Issue Guidelines

Issues are how we track work. Well-written issues save time and prevent confusion.

Required Information

If an issue is not in the Backlog column, it MUST have:

  • ✅ Clear title
  • ✅ Description explaining the problem or feature
  • ✅ Priority label (Low, Normal, High, Blocker)
  • ✅ Estimate (Hours, Days, Weeks)
  • ✅ At least one type label (bug, enhancement, documentation, etc.)

Writing Good Issues

Issue body SHOULD NOT be blank. Give enough context that someone else could work on it.

For bugs:

**What's broken:** Login button doesn't respond on Safari

**Steps to reproduce:**
1. Open site in Safari 17.x
2. Navigate to /login
3. Enter credentials
4. Click "Login"

**Expected:** User logs in
**Actual:** Nothing happens, no error

**Priority:** High (blocks users on Safari)
**Estimate:** Hours

For features:

**What we need:** Password reset functionality

**Why:** Users currently have to email us to reset passwords, 
creating support burden and frustrating users

**Approach:**
- Add "Forgot Password" link on login page
- Send reset email with time-limited token
- Create password reset form
- Token expires after 1 hour

**Priority:** Normal
**Estimate:** Days

Pull Request Guidelines

PR Title

PR titles MUST follow Conventional Commits:

feat(#42): add user authentication
fix(#89): resolve mobile navbar bug
docs(#12): improve setup instructions

PR Description

PR body MUST NOT be blank. Include:

## What This Does
Brief explanation of the changes

## Why This Matters
Why we're making this change

## How to Test
1. Step one
2. Step two
3. Expected result

## Related Issues
Closes #42
Related to #38

Linking

Every PR MUST be:

  • Linked to a project board (so we can track progress)
  • Linked to its issue (Closes #X in the description)

Code Formatting

Language-Specific Formatting

Every repository MUST have formatting defined in a config file:

  • JavaScript/TypeScript: .prettierrc or eslint.config.js
  • Python: pyproject.toml or .flake8
  • Rust: rustfmt.toml
  • Other languages: equivalent config file

Indentation: Use 4 spaces for indentation (not tabs, not 2 spaces)

Setting Up Formatters

The repository’s README MUST explain how to set up linters and formatters locally. If there are tricky setup steps, document them clearly.

Example setup section:

## Development Setup

1. Install dependencies: `npm install`
2. Set up pre-commit hooks: `npm run prepare`
3. Recommended VS Code extensions:
   - ESLint
   - Prettier
4. Format on save should work automatically

Writing Quality Code

These are principles that lead to better, more maintainable code:

Naming

Use descriptive names for variables, functions, and classes:

❌ Bad:

function calc(a, b) {
  return a * b * 0.15;
}

✅ Good:

function calculateSalesTax(price, quantity) {
  const TAX_RATE = 0.15;
  return price * quantity * TAX_RATE;
}

Names should reveal intent. If you need a comment to explain what a variable does, the name isn’t descriptive enough.

Comments

Avoid comments when code can be self-explanatory. Comments should explain why, not what.

❌ Bad:

// Loop through users
for (let i = 0; i < users.length; i++) {
  // Check if user is active
  if (users[i].active) {
    // Send email
    sendEmail(users[i]);
  }
}

✅ Good:

const activeUsers = users.filter(user => user.active);
activeUsers.forEach(user => sendEmail(user));

When to comment:

  • Complex algorithms that aren’t immediately obvious
  • Business logic reasons (“We do X because of Y requirement”)
  • TODOs with context: // TODO(#123): Refactor this when we migrate to new API
  • Workarounds: // HACK: iOS Safari doesn't support X, using Y instead

KISS Principle

Keep It Simple, Stupid.

The simplest solution that works is usually the best. Don’t over-engineer or add complexity “just in case.” Solve today’s problem today, not imaginary future problems.

DRY Principle

Don’t Repeat Yourself.

If you’re copying and pasting code more than twice (the “rule of three”), extract it into a function or component.

❌ Bad:

const user1Tax = user1.income * 0.15;
const user2Tax = user2.income * 0.15;
const user3Tax = user3.income * 0.15;

✅ Good:

function calculateTax(income) {
  return income * 0.15;
}

const user1Tax = calculateTax(user1.income);
const user2Tax = calculateTax(user2.income);
const user3Tax = calculateTax(user3.income);

Use Existing Libraries

Don’t reinvent the wheel. Before writing something from scratch, search for existing solutions.

Need to parse dates? Use date-fns or dayjs.
Need to make HTTP requests? Use fetch or axios.
Need form validation? Use an existing library.

We don’t need another JSON parsing library or date formatter. Learn to evaluate and use existing tools.

Exception: If it’s a learning exercise or the library is way overkill for your needs, it’s fine to implement it yourself. Just be honest about why.


Testing

Projects SHOULD have tests. At minimum, unit tests are required and MUST cover as much functionality as possible.

What to Test

Focus on:

  • Critical functionality (authentication, payments, data processing)
  • Business logic and algorithms
  • Bug fixes (write a test that would have caught the bug)
  • Edge cases and error handling

You don’t need 100% coverage, but test the important stuff.

Testing Examples

// Good test: Clear, specific, tests one thing
test('calculateTax returns correct amount for standard income', () => {
  expect(calculateTax(1000)).toBe(150);
});

test('calculateTax handles zero income', () => {
  expect(calculateTax(0)).toBe(0);
});

test('calculateTax throws error for negative income', () => {
  expect(() => calculateTax(-100)).toThrow();
});

Documentation

Good documentation is not optional.

Every project MUST have:

  • README with setup and usage instructions
  • Inline comments for complex or non-obvious code
  • API documentation if the project exposes an API
  • Architecture docs for larger projects

Every function, class, and module SHOULD have clear documentation:

/**
 * Calculates sales tax for a given price and quantity.
 * 
 * @param {number} price - Price per unit
 * @param {number} quantity - Number of units
 * @returns {number} Total tax amount
 * @throws {Error} If price or quantity is negative
 */
function calculateSalesTax(price, quantity) {
  if (price < 0 || quantity < 0) {
    throw new Error('Price and quantity must be non-negative');
  }
  const TAX_RATE = 0.15;
  return price * quantity * TAX_RATE;
}

Versioning

We follow Semantic Versioning (SemVer) for all projects:

  • MAJOR version when you make incompatible API changes
  • MINOR version when you add functionality in a backward-compatible manner
  • PATCH version when you make backward-compatible bug fixes

Example: v2.3.1 means major version 2, minor version 3, patch version 1.


Code Ownership

Know what you’re responsible for.

In team projects, different people own different parts of the codebase. This doesn’t mean others can’t contribute, but it means someone is responsible for maintaining that area, reviewing PRs, and making architectural decisions.

Document ownership in the project’s README or a CODEOWNERS file.


CI/CD Practices

Automate everything you can.

Projects SHOULD set up:

  • Automated testing – Run tests on every PR
  • Linting and formatting checks – Reject PRs with formatting issues
  • Deployment pipelines – Automate deployment to staging/production
  • Dependency updates – Use Dependabot or similar tools

Manual processes are error-prone. If you’re doing something repeatedly, automate it.


Accessibility and Internationalization

If your project has a user interface:

Accessibility (a11y):

  • Use semantic HTML
  • Include alt text for images
  • Ensure keyboard navigation works
  • Test with screen readers when possible
  • Maintain sufficient color contrast

Internationalization (i18n) and Localization (l10n):

  • Don’t hardcode text in code
  • Use translation files or libraries
  • Support different date/time/number formats
  • Consider RTL (right-to-left) languages if applicable

These aren’t afterthoughts—build them in from the start when relevant.


Community Contributions

For projects that accept external contributions:

  • Follow our Code of Conduct
  • Check the Contributing Guide
  • Label beginner-friendly issues with “good first issue”
  • Be welcoming and patient with new contributors
  • Review PRs promptly and constructively

Final Thoughts

These conventions exist to help you, not slow you down. If something doesn’t make sense for your project, discuss it with your team. The goal is better collaboration, not blind rule-following.

When in doubt, ask. It’s better to ask for clarification than to guess and do it wrong.

Conventions evolve. If you think something here should change, open an issue or bring it up at a club meeting. We improve these based on real experience.

Happy coding!