Coding Standards
Code Style and Conventions
Section titled “Code Style and Conventions”Following consistent coding standards makes the codebase easier to read, maintain, and contribute to.
Go Code Standards
Section titled “Go Code Standards”Code Formatting
Section titled “Code Formatting”Use standard Go formatting tools:
# Format all codegofmt -w .
# Use goimports for import organizationgoimports -w .Required: All Go code must pass gofmt and goimports before committing.
Naming Conventions
Section titled “Naming Conventions”Packages:
- Lowercase, single word when possible
package application,package events- Avoid underscores or mixed caps
Exported Names:
- PascalCase for types, functions, constants
type WebviewWindow struct,func NewApplication()
Unexported Names:
- camelCase for internal types, functions, variables
type windowImpl struct,func createWindow()
Interfaces:
- Name by behavior:
Reader,Writer,Handler - Single-method interfaces: name with
-ersuffix
// Goodtype Closer interface { Close() error}
// Avoidtype CloseInterface interface { Close() error}Error Handling
Section titled “Error Handling”Always check errors:
// Goodresult, err := doSomething()if err != nil { return fmt.Errorf("failed to do something: %w", err)}
// Bad - ignoring errorsresult, _ := doSomething()Use error wrapping:
// Wrap errors to provide contextif err := validate(); err != nil { return fmt.Errorf("validation failed: %w", err)}Create custom error types when needed:
type ValidationError struct { Field string Value string}
func (e *ValidationError) Error() string { return fmt.Sprintf("invalid value %q for field %q", e.Value, e.Field)}Comments and Documentation
Section titled “Comments and Documentation”Package comments:
// Package application provides the core Wails application runtime.//// It handles window management, event dispatching, and service lifecycle.package applicationExported declarations:
// NewApplication creates a new Wails application with the given options.//// The application must be started with Run() or RunWithContext().func NewApplication(opts Options) *Application { // ...}Implementation comments:
// processEvent handles incoming events from the runtime.// It dispatches to registered handlers and manages event lifecycle.func (a *Application) processEvent(event *Event) { // Validate event before processing if event == nil { return }
// Find and invoke handlers // ...}Function and Method Structure
Section titled “Function and Method Structure”Keep functions focused:
// Good - single responsibilityfunc (w *Window) setTitle(title string) { w.title = title w.updateNativeTitle()}
// Bad - doing too muchfunc (w *Window) updateEverything() { w.setTitle(w.title) w.setSize(w.width, w.height) w.setPosition(w.x, w.y) // ... 20 more operations}Use early returns:
// Goodfunc validate(input string) error { if input == "" { return errors.New("empty input") }
if len(input) > 100 { return errors.New("input too long") }
return nil}
// Avoid deep nestingConcurrency
Section titled “Concurrency”Use context for cancellation:
func (a *Application) RunWithContext(ctx context.Context) error { select { case <-ctx.Done(): return ctx.Err() case <-a.done: return nil }}Protect shared state with mutexes:
type SafeCounter struct { mu sync.Mutex count int}
func (c *SafeCounter) Increment() { c.mu.Lock() defer c.mu.Unlock() c.count++}Avoid goroutine leaks:
// Good - goroutine has exit conditionfunc (a *Application) startWorker(ctx context.Context) { go func() { for { select { case <-ctx.Done(): return // Clean exit case work := <-a.workChan: a.process(work) } } }()}Testing
Section titled “Testing”Test file naming:
// Tests: window_test.goTable-driven tests:
func TestValidate(t *testing.T) { tests := []struct { name string input string wantErr bool }{ {"empty input", "", true}, {"valid input", "hello", false}, {"too long", strings.Repeat("a", 101), true}, }
for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { err := validate(tt.input) if (err != nil) != tt.wantErr { t.Errorf("validate() error = %v, wantErr %v", err, tt.wantErr) } }) }}JavaScript/TypeScript Standards
Section titled “JavaScript/TypeScript Standards”Code Formatting
Section titled “Code Formatting”Use Prettier for consistent formatting:
{ "semi": false, "singleQuote": true, "tabWidth": 2, "trailingComma": "es5"}Naming Conventions
Section titled “Naming Conventions”Variables and functions:
- camelCase:
const userName = "John"
Classes and types:
- PascalCase:
class WindowManager
Constants:
- UPPER_SNAKE_CASE:
const MAX_RETRIES = 3
TypeScript
Section titled “TypeScript”Use explicit types:
// Goodfunction greet(name: string): string { return `Hello, ${name}`}
// Avoid implicit anyfunction process(data) { // Bad return data}Define interfaces:
interface WindowOptions { title: string width: number height: number}
function createWindow(options: WindowOptions): void { // ...}Commit Message Format
Section titled “Commit Message Format”Use Conventional Commits:
<type>(<scope>): <subject>
<body>
<footer>Types:
feat: New featurefix: Bug fixdocs: Documentation changesrefactor: Code refactoringtest: Adding or updating testschore: Maintenance tasks
Examples:
feat(window): add SetAlwaysOnTop method
Implement SetAlwaysOnTop for keeping windows above others.Adds platform implementations for macOS, Windows, and Linux.
Closes #123fix(events): prevent event handler memory leak
Event listeners were not being properly cleaned up whenwindows were closed. This adds explicit cleanup in thewindow destructor.Pull Request Guidelines
Section titled “Pull Request Guidelines”Before Submitting
Section titled “Before Submitting”- Code passes
gofmtandgoimports - All tests pass (
go test ./...) - New code has tests
- Documentation updated if needed
- Commit messages follow conventions
- No merge conflicts with
master
PR Description Template
Section titled “PR Description Template”## DescriptionBrief description of what this PR does.
## Type of Change- [ ] Bug fix- [ ] New feature- [ ] Breaking change- [ ] Documentation update
## TestingHow was this tested?
## Checklist- [ ] Tests pass- [ ] Documentation updated- [ ] No breaking changes (or documented)Code Review Process
Section titled “Code Review Process”As a Reviewer
Section titled “As a Reviewer”- Be constructive and respectful
- Focus on code quality, not personal preferences
- Explain why changes are suggested
- Approve once satisfied
As an Author
Section titled “As an Author”- Respond to all comments
- Ask for clarification if needed
- Make requested changes or explain why not
- Be open to feedback
Best Practices
Section titled “Best Practices”Performance
Section titled “Performance”- Avoid premature optimization
- Profile before optimizing
- Use benchmarks for performance-critical code
func BenchmarkProcess(b *testing.B) { for i := 0; i < b.N; i++ { process(testData) }}Security
Section titled “Security”- Validate all user input
- Sanitize data before display
- Use
crypto/randfor random data - Never log sensitive information
Documentation
Section titled “Documentation”- Document exported APIs
- Include examples in documentation
- Update docs when changing APIs
- Keep README files current
Platform-Specific Code
Section titled “Platform-Specific Code”File Naming
Section titled “File Naming”window.go // Common interfacewindow_darwin.go // macOS implementationwindow_windows.go // Windows implementationwindow_linux.go // Linux implementationBuild Tags
Section titled “Build Tags”//go:build darwin
package application
// macOS-specific codeLinting
Section titled “Linting”Run linters before committing:
# golangci-lint (recommended)golangci-lint run
# Individual lintersgo vet ./...staticcheck ./...Questions?
Section titled “Questions?”If you’re unsure about any standards:
- Check existing code for examples
- Ask in Discord
- Open a discussion on GitHub