Files
mux/CONTRIBUTING.md
Ankit Patial 26bb9bf5ee feat: improve resource routing API and add comprehensive quality standards
BREAKING CHANGES:
- Renamed HandleGET -> MemberGET for member-level routes
- Renamed HandlePOST -> MemberPOST for member-level routes
- Renamed HandlePUT -> MemberPUT for member-level routes
- Renamed HandlePATCH -> MemberPATCH for member-level routes
- Renamed HandleDELETE -> MemberDELETE for member-level routes

New Features:
- Added collection-level route methods: GET, POST, PUT, PATCH, DELETE
- Clear distinction between collection (/pattern/action) and member (/pattern/{id}/action) routes
- Comprehensive documentation (README, CONTRIBUTING, QUICKSTART, DOCS)
- Development tooling (Makefile, check.sh script)
- AI coding assistant guidelines (.cursorrules)
- GitHub Actions CI/CD pipeline
- golangci-lint configuration

Code Quality:
- Optimized struct field alignment for better memory usage
- All code passes go vet, staticcheck, and fieldalignment
- All tests pass with race detector
- Go 1.25+ requirement enforced

Documentation:
- Complete README rewrite with examples
- CONTRIBUTING.md with development guidelines
- QUICKSTART.md for new users
- CHANGELOG.md with version history
- SUMMARY.md documenting all changes
- DOCS.md as documentation index
2025-11-15 14:05:11 +05:30

8.6 KiB

Contributing to Mux

Thank you for your interest in contributing to Mux! This document provides guidelines and standards for contributing to this project.

Code of Conduct

Be respectful, constructive, and collaborative. We're all here to build better software together.

Requirements

Go Version

This project requires Go 1.25 or higher. We leverage the latest Go features and improvements, so please ensure your development environment meets this requirement.

go version  # Should show go1.25 or higher

Development Tools

Before contributing, ensure you have the following tools installed:

# Install staticcheck
go install honnef.co/go/tools/cmd/staticcheck@latest

# Install fieldalignment (part of go vet)
# This is included with Go 1.25+

Code Quality Standards

All code contributions MUST pass the following checks before being submitted:

1. go vet

Ensure your code passes go vet which catches common mistakes:

go vet ./...

What it checks:

  • Suspicious constructs
  • Printf-like function calls with incorrect arguments
  • Unreachable code
  • Common mistakes in error handling
  • And many other potential issues

2. fieldalignment

Ensure struct fields are optimally ordered to minimize memory usage:

go vet -vettool=$(which fieldalignment) ./...

Or use fieldalignment directly:

fieldalignment -fix ./...  # Automatically fix alignment issues

Why it matters:

  • Reduces memory footprint
  • Improves cache locality
  • Better performance in memory-constrained environments

Example:

// Bad - wastes memory due to padding
type BadStruct struct {
    a bool   // 1 byte + 7 bytes padding
    b int64  // 8 bytes
    c bool   // 1 byte + 7 bytes padding
}

// Good - optimally aligned
type GoodStruct struct {
    b int64  // 8 bytes
    a bool   // 1 byte
    c bool   // 1 byte + 6 bytes padding
}

3. staticcheck

Run staticcheck to catch bugs and ensure code quality:

staticcheck ./...

What it checks:

  • Unused code
  • Inefficient code patterns
  • Deprecated API usage
  • Common bugs and mistakes
  • Style and consistency issues
  • Performance problems
  • Security vulnerabilities

Pre-Submission Checklist

Before submitting a pull request, run all checks:

# Run all checks
go vet ./...
staticcheck ./...
go test ./...

Create a simple script check.sh in your local environment:

#!/bin/bash
set -e

echo "Running go vet..."
go vet ./...

echo "Running staticcheck..."
staticcheck ./...

echo "Running tests..."
go test -race -v ./...

echo "Checking field alignment..."
go vet -vettool=$(which fieldalignment) ./...

echo "All checks passed! ✅"

Development Workflow

1. Fork and Clone

git clone https://github.com/YOUR_USERNAME/mux.git
cd mux

2. Create a Branch

git checkout -b feature/your-feature-name

3. Make Your Changes

  • Write clear, idiomatic Go code
  • Follow Go conventions and best practices
  • Keep functions small and focused
  • Add comments for exported functions and complex logic
  • Update documentation if needed

4. Write Tests

All new features and bug fixes should include tests:

func TestNewFeature(t *testing.T) {
    // Arrange
    m := mux.New()
    
    // Act
    m.GET("/test", testHandler)
    
    // Assert
    req := httptest.NewRequest(http.MethodGet, "/test", nil)
    rec := httptest.NewRecorder()
    m.ServeHTTP(rec, req)
    
    if rec.Code != http.StatusOK {
        t.Errorf("expected status 200, got %d", rec.Code)
    }
}

5. Run Quality Checks

go vet ./...
staticcheck ./...
go test -race ./...

6. Commit Your Changes

Write clear, descriptive commit messages:

git commit -m "feat: add support for custom error handlers"
git commit -m "fix: resolve race condition in middleware chain"
git commit -m "docs: update README with new examples"

Commit message prefixes:

  • feat: - New feature
  • fix: - Bug fix
  • docs: - Documentation changes
  • test: - Test additions or modifications
  • refactor: - Code refactoring
  • perf: - Performance improvements
  • chore: - Maintenance tasks

7. Push and Create Pull Request

git push origin feature/your-feature-name

Then create a pull request on GitHub with:

  • Clear description of changes
  • Link to related issues (if any)
  • Screenshots/examples if applicable

Code Style Guidelines

General Principles

  1. Simplicity over cleverness - Write clear, maintainable code
  2. Use standard library - Avoid external dependencies unless absolutely necessary
  3. Zero allocation paths - Optimize hot paths to minimize allocations
  4. Fail fast - Use panics for programmer errors, errors for runtime issues
  5. Document public APIs - All exported functions, types, and methods should have comments

Naming Conventions

  • Use short, descriptive names for local variables
  • Use full words for exported identifiers
  • Follow Go naming conventions (MixedCaps, not snake_case)
  • Avoid stuttering (e.g., mux.MuxRoutermux.Router)

Error Handling

// Good - clear error handling
func processRequest(w http.ResponseWriter, r *http.Request) {
    data, err := fetchData(r.Context())
    if err != nil {
        http.Error(w, "Failed to fetch data", http.StatusInternalServerError)
        return
    }
    // process data...
}

// Avoid - ignoring errors
func processRequest(w http.ResponseWriter, r *http.Request) {
    data, _ := fetchData(r.Context()) // Don't do this
    // process data...
}

Comments

// Good - explains why, not what
// Use buffered channel to prevent goroutine leaks when context is cancelled
// before the worker finishes processing.
ch := make(chan result, 1)

// Avoid - states the obvious
// Create a channel
ch := make(chan result, 1)

Testing Guidelines

Test Structure

Use the Arrange-Act-Assert pattern:

func TestRouteRegistration(t *testing.T) {
    // Arrange
    m := mux.New()
    handler := func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("test"))
    }
    
    // Act
    m.GET("/test", handler)
    routes := m.RouteList()
    
    // Assert
    if len(routes) != 1 {
        t.Errorf("expected 1 route, got %d", len(routes))
    }
}

Table-Driven Tests

For testing multiple scenarios:

func TestPathParameters(t *testing.T) {
    tests := []struct {
        name     string
        pattern  string
        path     string
        expected string
    }{
        {"simple param", "/users/{id}", "/users/123", "123"},
        {"multiple params", "/posts/{year}/{month}", "/posts/2024/01", "2024"},
    }
    
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            // test implementation
        })
    }
}

Test Coverage

Aim for high test coverage, especially for:

  • Public APIs
  • Edge cases
  • Error conditions
  • Concurrent access patterns
# Check coverage
go test -cover ./...

# Generate detailed coverage report
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.out

Performance Considerations

Benchmarking

Include benchmarks for performance-critical code:

func BenchmarkMiddlewareChain(b *testing.B) {
    m := mux.New()
    m.Use(middleware1, middleware2, middleware3)
    m.GET("/test", testHandler)
    
    req := httptest.NewRequest(http.MethodGet, "/test", nil)
    rec := httptest.NewRecorder()
    
    b.ResetTimer()
    for i := 0; i < b.N; i++ {
        m.ServeHTTP(rec, req)
    }
}

Run benchmarks:

go test -bench=. -benchmem ./...

Allocation Analysis

Identify and minimize allocations:

go test -bench=. -benchmem -memprofile=mem.out ./...
go tool pprof mem.out

Documentation

Code Documentation

  • All exported functions, types, and methods must have comments
  • Comments should start with the name of the thing being described
  • Use complete sentences with proper punctuation
// New creates and returns a new Mux router instance with an empty route table
// and no middleware configured.
func New() *Mux {
    return &Mux{
        mux:    http.NewServeMux(),
        routes: new(RouteList),
    }
}

README Updates

If your change affects usage:

  • Update relevant sections in README.md
  • Add examples if introducing new features
  • Update the table of contents if adding new sections

Questions or Issues?

  • Open an issue for bugs or feature requests
  • Start a discussion for questions or ideas
  • Check existing issues and PRs before creating new ones

License

By contributing to Mux, you agree that your contributions will be licensed under the MIT License.


Thank you for contributing to Mux! Your efforts help make this project better for everyone. 🙏