mirror of
https://git.numenor-labs.us/dsfx.git
synced 2025-04-29 08:10:34 +00:00
update the style
This commit is contained in:
parent
d75d432818
commit
9ba822d4df
@ -1,8 +1,10 @@
|
|||||||
package assert
|
package assert
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
// Assert panics if the given truth value is false, with the given message.
|
// Assert panics if the given truth value is false, with the given message.
|
||||||
func Assert(truth bool, msg string) {
|
func Assert(truth bool, msg string) {
|
||||||
if !truth {
|
if !truth {
|
||||||
panic(msg)
|
panic(fmt.Sprintf("Assertion Failed: %s", msg))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
189
tigerstyle.md
189
tigerstyle.md
@ -1,156 +1,127 @@
|
|||||||
# TigerStyle for Go – Inspired by the Original TigerStyle
|
# 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._
|
Adopted from the original [Tiger Style](https://github.com/tigerbeetle/tigerbeetle/blob/main/docs/TIGER_STYLE.md)
|
||||||
|
for **zig**, created by tigerbeetle.
|
||||||
|
|
||||||
|
## The Essence of Our Go Style
|
||||||
|
|
||||||
|
> “There are three things extremely hard: steel, a diamond, and to know one's self.” — Benjamin Franklin
|
||||||
|
|
||||||
|
Our Go style is not merely about formatting code—it’s our design philosophy. It blends engineering excellence with artful clarity to ensure that our systems are safe, high-performance, and enjoyable to develop and maintain.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1. The Core Principles
|
## Why Have Style?
|
||||||
|
|
||||||
Our goal is to write Go code that is:
|
In our view, design is as much about how the system works as what it looks like. Our style makes each decision explicit, ensuring that safety, performance, and developer experience remain paramount.
|
||||||
|
|
||||||
- **Safe:** No surprises. Every error is caught and handled.
|
- **Safety** first,
|
||||||
- **High-Performance:** Bottlenecks are identified and efficiently addressed.
|
- **Performance** next,
|
||||||
- **Easy to Maintain:** Code is clear, well-organized, and thoroughly documented.
|
- and then **developer experience**.
|
||||||
|
|
||||||
|
Good style does more than improve readability; it enforces the design decisions that prevent technical debt from creeping in.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2. Why Strict Style Matters
|
## On Simplicity, Elegance, and Technical Debt
|
||||||
|
|
||||||
Adhering to strict rules ensures:
|
- **Simplicity** is our ultimate goal—but it is never a free pass. Achieving simplicity is the result of thoughtful design and disciplined iteration.
|
||||||
|
- A “zero technical debt” policy applies: we design and implement things right the first time. This saves each of us from the cost of firefighting production issues later.
|
||||||
- **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
|
## Safety
|
||||||
|
|
||||||
- **Simple Designs First:** Strive for solutions that solve multiple issues simultaneously.
|
Even in Go, safety is non‐negotiable. We frequently embed explicit checks and assertions to ensure our code behaves as expected. Consider this sample assertion helper:
|
||||||
- **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.
|
```go
|
||||||
|
// Assert panics with a message if the condition is not met.
|
||||||
|
// Not idiomatic Go, but used here to enforce critical invariants.
|
||||||
|
func Assert(condition bool, msg string) {
|
||||||
|
if !condition {
|
||||||
|
panic(fmt.Sprintf("Assertion failed: %s", msg))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Key safety guidelines:
|
||||||
|
|
||||||
|
- Use **simple, explicit control flow** (avoid unnecessary recursion and hidden complex abstractions).
|
||||||
|
- **Limit loops and queues**: every loop should have an explicit upper bound to avoid infinite cycles.
|
||||||
|
- Favor fixed-size types (e.g., use `uint32` or `int32` where appropriate) instead of architecture-dependent sizes.
|
||||||
|
- Use assertions liberally—both to check expected states _before_ and _after_ important operations. Aim for at least two assertions per function.
|
||||||
|
- All memory usage should be planned up-front. Although Go provides garbage collection, design your modules with a fixed resource strategy in mind for predictability.
|
||||||
|
- Keep function bodies short. In Go, we suggest striving for functions to be easily digestible (roughly keeping functions around 70 lines or less) by breaking out helper functions where it makes sense.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 4. Zero Technical Debt Policy
|
## Performance
|
||||||
|
|
||||||
- **Fail Early:** Address potential issues during development—not after deployment.
|
Performance starts in the design phase—even before profiling code.
|
||||||
- **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.
|
- **Back-of-the-envelope sketches:** Before implementation, roughly gauge resource (network, disk, memory, CPU) usage.
|
||||||
|
- Identify the slowest resource (network → disk → memory → CPU) and optimize that first.
|
||||||
|
- Use batching to reduce overhead and context switching. For example, aggregate database writes rather than doing them one at a time.
|
||||||
|
- Separate the control plane from the data plane. For “hot loops” or performance‐critical code, create small, stateless helper functions accepting primitive types. This helps both the compiler and human reviewers spot redundant computations.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 5. Safety: Rules and Assertions
|
## Developer Experience
|
||||||
|
|
||||||
Safety comes first. Our practices include:
|
Our goal is to make our code easy to read, maintain, and extend.
|
||||||
|
|
||||||
- **Control Flow and Limits:**
|
### Naming Conventions
|
||||||
|
|
||||||
- Use clear, linear control structures. No clever hacks that compromise readability.
|
- **Go idioms:** For exported functions, use `CamelCase` (e.g., `ReadSector`), and for local functions and variables, use `camelCase`.
|
||||||
- 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.
|
- Avoid abbreviations unless they are well-known acronyms (for example, use `HTTPStatus` rather than `httpStatus`).
|
||||||
|
- Include units and qualifiers in variable names at the end, so names like `latencyMsMax` (where “Ms” stands for milliseconds) are both clear and neatly aligned with related variables.
|
||||||
|
- When a function delegates work to helpers, consider prefixing the helper name with the parent function (e.g., `readSectorCallback`) to provide context.
|
||||||
|
- Place important constructs (like `main`) or critical types near the top of files for clarity.
|
||||||
|
|
||||||
- **Assertions and Error Handling:**
|
### Comments and Commit Messages
|
||||||
|
|
||||||
- Every function **must validate its inputs and expected outputs**.
|
- Write clear and complete comments. Comments should be full sentences with proper punctuation.
|
||||||
- Use explicit error checks (`if err != nil { … }`) to handle all non-fatal errors.
|
- Document why a decision was made, not just what the code does. Commit messages should convey context and rationale.
|
||||||
- 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
|
## Handling Errors
|
||||||
|
|
||||||
- **Identify Bottlenecks:** Optimize in order: Network > Disk > Memory > CPU.
|
Errors must always be handled explicitly:
|
||||||
- **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.
|
- In Go, this means checking returned errors immediately. Do not ignore them.
|
||||||
- **Explicit Critical Paths:** Code that is performance-critical must be isolated, clearly documented, and benchmarked. No “magic” will hide inefficient loops or algorithms.
|
- Test error paths thoroughly, including non-fatal errors, to mitigate the risk of catastrophic failures found in distributed systems.
|
||||||
|
- Use assertions where appropriate to ensure that numbers or states remain within expected ranges.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7. Developer Experience: Consistency and Clarity
|
## Avoiding Off-By-One Errors
|
||||||
|
|
||||||
### Naming and Organization
|
Misunderstandings between zero-based indexes and one-based counts can be problematic:
|
||||||
|
|
||||||
- **Naming Conventions:**
|
- Clearly differentiate between an index, a count, and a size. For example, increment an index when calculating a count.
|
||||||
|
- Use helper functions for mathematical operations—consider naming them in a way that demonstrates intent (like `divExact`, `divFloor`, or `divCeil`).
|
||||||
- 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
|
## Formatting and Dependencies
|
||||||
|
|
||||||
### Dependencies
|
- Run `go fmt` on all code. We also recommend using linters (such as `golangci-lint`) for consistency.
|
||||||
|
- Set a limit on line lengths (suggested maximum of 100 columns) to ensure clear visibility of code segments.
|
||||||
- **Minimal External Dependencies:**
|
- Aim for a “zero dependencies” mindset where possible. Rely on Go’s standard library to reduce external risk and simplify builds.
|
||||||
- Rely heavily on Go’s 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
|
## Tooling
|
||||||
|
|
||||||
- **Continuous Improvement:**
|
- Choose tools that streamline development. When writing scripts or utilities, consider writing them in Go.
|
||||||
|
- A standardized toolchain reduces personal variations and ensures consistency across the team.
|
||||||
- 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_
|
## Final Thoughts
|
||||||
|
|
||||||
_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._
|
In our adapted TigerStyle for Go, every detail—from strict assertions to deliberate naming and error handling—is designed to create robust, clear, and high-performance software. Remember: even though some of these practices (like assertions) aren’t common in Go, we include them as an essential part of our commitment to safety and clarity.
|
||||||
|
|
||||||
|
> "You don’t really suppose, do you, that all your adventures and escapes were managed by mere luck?"
|
||||||
|
> Keep iterating, keep improving, and let your code be both a precise tool and a piece of art.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user