Files
mux/CONTRIBUTING.md

411 lines
8.6 KiB
Markdown
Raw Permalink Normal View History

# 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. 🙏