dsfx/tigerstyle.md

6.3 KiB
Raw Blame History

TigerStyle for Go Inspired by the Original TigerStyle

This guide draws direct inspiration from the original TigerStyle document. Its principles have been adapted to the Go ecosystem, establishing definitive rules for writing safe, high-performance code with an exceptional developer experience.


1. The Core Principles

Our goal is to write Go code that is:

  • Safe: No surprises. Every error is caught and handled.
  • High-Performance: Bottlenecks are identified and efficiently addressed.
  • Easy to Maintain: Code is clear, well-organized, and thoroughly documented.

2. Why Strict Style Matters

Adhering to strict rules ensures:

  • Clarity and Consistency: Every developer on the team can immediately understand the code.
  • Early Error Detection: Explicit checks and assertions catch mistakes before they become costly.
  • Reduced Technical Debt: Investing time in clear design saves time later in production fixes and maintenance.

3. Simplicity and Elegance

  • Simple Designs First: Strive for solutions that solve multiple issues simultaneously.
  • Iterate to Elegance: The first solution is rarely the best. Refactor until your code is as simple as possible without sacrificing clarity.
  • Definitive Boundaries: If something is too complex or too long, it must be split into distinct, manageable components.

4. Zero Technical Debt Policy

  • Fail Early: Address potential issues during development—not after deployment.
  • No Compromise on Quality: Code must fully meet our design standards before it can be merged.
  • Comprehensive Testing: All functions must be covered by tests that include both valid and invalid cases.

5. Safety: Rules and Assertions

Safety comes first. Our practices include:

  • Control Flow and Limits:

    • Use clear, linear control structures. No clever hacks that compromise readability.
    • Every loop, channel, and buffer must have an explicit, hard upper limit. For example, a loop should never exceed a fixed iteration count unless justified.
  • Assertions and Error Handling:

    • Every function must validate its inputs and expected outputs.
    • Use explicit error checks (if err != nil { … }) to handle all non-fatal errors.
    • For invariants that must never be violated, use panic immediately. Such panics are reserved solely for truly unrecoverable conditions.
    • Minimum Assertion Density: Every function must include at least two assertions or validations—one confirming expected conditions and one ensuring the rejection of impossible states.
  • Resource Management:

    • Preallocate slices and buffers in hot paths to avoid runtime allocation surprises.
    • All resources should be allocated once during startup, particularly in performance-sensitive parts of the system.
  • Variable Scoping:

    • Declare variables in the smallest scope possible. Global variables and unnecessarily wide variable scopes are not allowed.
  • Function Size:

    • Hard limit: No function may exceed 70 lines of code. Functions that approach this limit must be refactored immediately into smaller helper functions with well-defined responsibilities.

6. Performance: Measured and Proven

  • Identify Bottlenecks: Optimize in order: Network > Disk > Memory > CPU.
  • Profiling is Mandatory: Use tools like pprof to physically measure performance. No assumptions—optimize based on real data.
  • Batch Operations: Always batch I/O and computational tasks where possible to reduce overhead.
  • Explicit Critical Paths: Code that is performance-critical must be isolated, clearly documented, and benchmarked. No “magic” will hide inefficient loops or algorithms.

7. Developer Experience: Consistency and Clarity

Naming and Organization

  • Naming Conventions:

    • Use CamelCase for exported identifiers and lowerCamelCase for unexported ones.
    • Names must be descriptive and avoid abbreviations unless the abbreviation is well recognized.
  • File and Code Organization:

    • The main function and package initialization must appear at the top of the file.
    • Group related types and functions together. Consistent ordering enhances readability.
  • Commit Messages and Documentation:

    • Every commit must include a clear explanation of what changed and, more importantly, why the change was made.
    • Comments must clarify the rationale behind decisions and describe non-obvious logic.

Error Handling and Modularity

  • Explicit Error Checks:

    • Use the standard Go idiom (if err != nil { … }) without exception.
    • Never ignore errors.
  • Function Design:

    • Functions must be single-purpose and maintain a clear separation of concerns.
    • Avoid overly complicated signatures—simplicity at the point of use is paramount.
  • Testing:

    • Unit tests are mandatory for every function, covering both expected and edge-case scenarios.
    • Tests must also deliberately check for error conditions and validate that assertions are working.

8. Tools, Dependencies, and Workflow

Dependencies

  • Minimal External Dependencies:
    • Rely heavily on Gos standard library. External libraries are permitted only when absolutely necessary and must be scrutinized for maintenance, security, and performance impact.

Tooling

  • Formatting:

    • Code must be formatted with gofmt. No exceptions.
  • Static Analysis:

    • Run go vet, and other static analyzers with every commit. Fix all warnings immediately.
  • Version Control and CI/CD:

    • Use Go modules for dependency management.
    • Integrate linting and testing into the CI pipeline to maintain consistency and catch issues early.

9. Final Mandates

  • Continuous Improvement:

    • This document is the definitive style guide for our Go code. Adherence is not optional.
    • Regular audits, code reviews, and performance benchmarks must be conducted to ensure compliance.
  • No Excuses:

    • If a piece of code violates these rules, it must be refactored immediately.
    • Our style ensures that every line of code is safe, efficient, and maintainable.

End of TigerStyle for Go

We take inspiration from TigerStyle without compromise. Our rules are definitive and non-negotiable—engineered to produce Go code that stands out for its clarity, safety, and performance.