# 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. ```bash go version # Should show go1.25 or higher ``` ### Development Tools Before contributing, ensure you have the following tools installed: ```bash # 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: ```bash 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: ```bash go vet -vettool=$(which fieldalignment) ./... ``` Or use fieldalignment directly: ```bash fieldalignment -fix ./... # Automatically fix alignment issues ``` **Why it matters:** - Reduces memory footprint - Improves cache locality - Better performance in memory-constrained environments **Example:** ```go // 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: ```bash 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: ```bash # Run all checks go vet ./... staticcheck ./... go test ./... ``` Create a simple script `check.sh` in your local environment: ```bash #!/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 ```bash git clone https://github.com/YOUR_USERNAME/mux.git cd mux ``` ### 2. Create a Branch ```bash 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: ```go 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 ```bash go vet ./... staticcheck ./... go test -race ./... ``` ### 6. Commit Your Changes Write clear, descriptive commit messages: ```bash 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 ```bash 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.MuxRouter` → `mux.Router`) ### Error Handling ```go // 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 ```go // 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: ```go 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: ```go 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 ```bash # 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: ```go 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: ```bash go test -bench=. -benchmem ./... ``` ### Allocation Analysis Identify and minimize allocations: ```bash 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 ```go // 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. 🙏