This document outlines the coding standards, conventions, and best practices for contributing to UGEM.
UGEM is built on three core principles:
| Principle | Description |
|---|---|
| 🎯 Determinism | Code must produce predictable, reproducible results |
| 🔒 Safety | Prefer explicit error handling over runtime panics |
| 📖 Clarity | Code is read more than written — optimize for readability |
- ✅ Run
go fmtbefore every commit - ✅ Run
go vetto catch common issues - ✅ Use
golintfor style recommendations - ✅ Keep lines under 100 characters when reasonable
- ✅ Use 2 spaces for indentation (Go standard)
| Element | Convention | Example |
|---|---|---|
| Packages | lowercase, short | runtime, gdl, planning |
| Functions | PascalCase, descriptive | ResolveGoal(), ExecuteAction() |
| Variables | camelCase, meaningful | goalState, eventLog |
| Constants | PascalCase or SCREAMING_SNAKE | MaxRetries, DEFAULT_TIMEOUT |
| Interfaces | PascalCase, ends with -er | Planner, Dispatcher |
| Files | lowercase, snake_case | event_bus.go, types.go |
// ✅ Good: Small, focused, well-named
func (e *Engine) ResolveGoal(goal *Goal) error {
if goal == nil {
return ErrNilGoal
}
return e.planner.CreatePlan(goal)
}
// ❌ Bad: Does too much, unclear purpose
func process(x string) {
// ... 200 lines of code
}Every package must have a doc comment:
// Package runtime provides the core execution engine for UGEM.
// It handles goal resolution, event processing, and action dispatching.
package runtimePublic functions require doc comments:
// ExecuteAction runs the specified action and records the result.
// Returns an error if the action fails or validation fails.
func (d *Dispatcher) ExecuteAction(action *Action) error- Use full sentences for documentation
- Use // comments for implementation notes
- Prefix with TODO: for tracking future work
// CalculateNextState derives the new state from the current state
// and the given event. This is deterministic by design.
func CalculateNextState(state *State, event *Event) (*State, error)| Rule | Example |
|---|---|
| ✅ Return errors explicitly | return nil, ErrNotFound |
| ✅ Wrap errors with context | return nil, fmt.Errorf("parse goal: %w", err) |
| ✅ Use sentinel errors | var ErrGoalNotFound = errors.New("goal not found") |
| ❌ Don't ignore errors | _ = doSomething() |
| ❌ Avoid panic in production | panic("should not happen") |
package gdl
import "errors"
// Sentinel errors for the GDL package
var (
ErrParseFailed = errors.New("parse failed")
ErrTypeNotFound = errors.New("type not found")
ErrInvalidGoal = errors.New("invalid goal")
)- ✅ All public functions must have tests
- ✅ Use table-driven tests for multiple scenarios
- ✅ Name tests descriptively:
Test<Function>_<Scenario>_<Expected> - ✅ Use
t.Helper()for test utilities
func TestGoalEngine_ResolveGoal_Success(t *testing.T) {
// Arrange
engine := NewGoalEngine()
goal := &Goal{ID: "test-1", Condition: "status == PAID"}
// Act
err := engine.ResolveGoal(goal)
// Assert
assert.NoError(t, err)
assert.Equal(t, StateResolved, goal.State)
}
func TestGoalEngine_ResolveGoal_InvalidGoal(t *testing.T) {
tests := []struct {
name string
goal *Goal
wantErr error
}{
{"nil goal", nil, ErrNilGoal},
{"empty id", &Goal{ID: ""}, ErrInvalidGoal},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
engine := NewGoalEngine()
err := engine.ResolveGoal(tt.goal)
assert.ErrorIs(t, err, tt.wantErr)
})
}
}| File | Test File |
|---|---|
runtime/kernel.go |
runtime/kernel_test.go |
gdl/parser.go |
gdl/gdl_test.go |
<type>/<description>
Examples:
├── feat/add-goal-partitioning
├── fix/event-log-corruption
├── docs/readme-updates
├── refactor/scheduler-optimization
├── test/add-e2e-scenarios
Follow Conventional Commits:
<type>(<scope>): <description>
[optional body]
[optional footer]
| Type | Description |
|---|---|
feat |
New feature |
fix |
Bug fix |
docs |
Documentation |
style |
Formatting |
refactor |
Code refactoring |
test |
Tests |
chore |
Maintenance |
feat(gdl): add support for nested type definitions
Fixes #42
Co-authored-by: Jane Doe <jane@example.com>fix(runtime): prevent race condition in event bus
The event bus was not thread-safe when processing concurrent
events. Added mutex protection to the publish method.- Code compiles without errors
- All tests pass (
go test ./...) -
go fmthas been run -
go vetreports no issues - New functions have doc comments
- Edge cases are handled
- No hardcoded secrets or credentials
| Area | Check |
|---|---|
| 🔍 Correctness | Does the code do what it claims? |
| 🧪 Tests | Are tests comprehensive? |
| 📖 Readability | Is the code easy to understand? |
| ⚡ Performance | Any obvious inefficiencies? |
| 🔒 Security | Any security vulnerabilities? |
| 📦 Coupling | Is the change properly scoped? |
ugem/
├── cmd/ # Entry points
├── gdl/ # Goal Definition Language
├── runtime/ # Core execution engine
├── planning/ # Goal planning subsystem
├── distributed/ # Distributed coordination
├── storage/ # Persistence layer
├── http/ # HTTP server
├── grpc/ # gRPC service
├── logging/ # Logging utilities
├── observability/ # Metrics & tracing
├── plugins/ # Plugin system
├── security/ # Security utilities
└── demo/ # Demo applications
- Only add dependencies when necessary
- Prefer standard library over external packages
- Keep dependency list updated:
go mod tidy - Document why each dependency is needed
- ❌ Unlicensed dependencies
- ❌ Dependencies with known security vulnerabilities
- ❌ Heavy frameworks when simple solutions suffice
// ❌ Bad
apiKey := "sk-1234567890abcdef"
// ✅ Good
apiKey := os.Getenv("API_KEY")func NewGoal(id, condition string) (*Goal, error) {
if id == "" {
return nil, ErrEmptyGoalID
}
if condition == "" {
return nil, ErrEmptyCondition
}
return &Goal{ID: id, Condition: condition}, nil
}- ✅ Profile before optimizing
- ✅ Use
sync.Poolfor frequent allocations - ✅ Batch database operations when possible
- ✅ Use buffered channels for high-throughput scenarios
func BenchmarkResolveGoal(b *testing.B) {
engine := NewGoalEngine()
goal := &Goal{ID: "bench-goal", Condition: "status == ACTIVE"}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_ = engine.ResolveGoal(goal)
}
}Remember: Code is read far more often than it is written. Write for the reader.