Mindset shift: compiler-enforced design over runtime discipline
Move from Go's simplicity-and-discipline culture to Rust's compiler-guided design loop.
by the end of this lesson you can
- →Uses Result and ? intentionally
- →Keeps the control flow explicit
- →Lets the function signature communicate what can fail
Overview
Go developers are used to keeping code simple and relying on clear conventions at runtime. Rust still values clarity, but it pushes more design decisions into the type system and uses compiler feedback to keep those decisions honest.
In Go, you often
accept a simple design that stays readable and trust code review, tests, and discipline to catch many mistakes.
In Rust, the common pattern is
to encode more guarantees directly in types, ownership rules, and function signatures so mistakes are rejected before the program runs.
why this difference matters
The first transition is cultural. Rust feels slower until you start using the compiler as part of the design process rather than a final syntax check.
Go
cfg, err := loadConfig()
if err != nil {
return err
}
run(cfg)Rust
let cfg = load_config()?;
run(cfg)?;Deeper comparison
Go version
user, err := loadUser(id)
if err != nil {
return err
}
if user.Admin {
log.Println("admin")
}Rust version
let user = load_user(id)?;
if user.admin {
println!("admin");
}Reflect
What becomes easier to trust when the compiler is allowed to reject more vague or underspecified designs?
what a strong answer notices
A strong answer mentions clearer invariants, fewer hidden assumptions, and more explicit failure and ownership boundaries.
Rewrite
Rewrite this Go sketch into a Rust-style flow that makes failure part of the function signature.
Rewrite this Go
cfg, err := loadConfig()
if err != nil {
return err
}
if cfg.Enabled {
startWorker(cfg)
}
return nilwhat good looks like
- Uses Result and ? intentionally
- Keeps the control flow explicit
- Lets the function signature communicate what can fail
Practice
Describe how you would redesign a small Go service helper so it feels natural in Rust.
success criteria
- Names which assumptions should move into types
- Explains what ownership or borrowing would clarify
- Treats compiler feedback as part of the design loop
Common mistakes
- Expecting Rust to feel productive only when it behaves like Go.
- Trying to remove compiler constraints instead of learning from them.
- Treating exactness as overengineering before seeing what bugs it prevents.
takeaways
- ●The first transition is cultural. Rust feels slower until you start using the compiler as part of the design process rather than a final syntax check.
- ●A strong answer mentions clearer invariants, fewer hidden assumptions, and more explicit failure and ownership boundaries.
- ●Names which assumptions should move into types