m05-type-driven

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Type-Driven Design

Type-Driven Design

Layer 1: Language Mechanics
第一层:语言机制

Core Question

核心问题

How can the type system prevent invalid states?
Before reaching for runtime checks:
  • Can the compiler catch this error?
  • Can invalid states be unrepresentable?
  • Can the type encode the invariant?

类型系统如何防止无效状态?
在使用运行时检查之前:
  • 编译器能否捕获这个错误?
  • 能否让无效状态无法被表示?
  • 类型能否编码不变式?

Error → Design Question

错误→设计问题

PatternDon't Just SayAsk Instead
Primitive obsession"It's just a string"What does this value represent?
Boolean flags"Add an is_valid flag"Can states be types?
Optional everywhere"Check for None"Is absence really possible?
Validation at runtime"Return Err if invalid"Can we validate at construction?

模式不要只说换个问法
原始类型滥用"这只是个字符串"这个值代表什么?
布尔标志过度使用"加个is_valid标志"能否将状态设计为类型?
到处使用可选类型"检查是否为None"真的可能存在缺失的情况吗?
运行时验证"无效时返回Err"能否在构造时就完成验证?

Thinking Prompt

思考提示

Before adding runtime validation:
  1. Can the type encode the constraint?
    • Numeric range → bounded types or newtypes
    • Valid states → type state pattern
    • Semantic meaning → newtype
  2. When is validation possible?
    • At construction → validated newtype
    • At state transition → type state
    • Only at runtime → Result with clear error
  3. Who needs to know the invariant?
    • Compiler → type-level encoding
    • API users → clear type signatures
    • Runtime only → documentation

在添加运行时验证之前:
  1. 类型能否编码约束?
    • 数值范围 → 有界类型或newtype
    • 有效状态 → type state模式
    • 语义含义 → newtype
  2. 何时可以进行验证?
    • 构造时 → 已验证的newtype
    • 状态转换时 → type state
    • 仅能在运行时 → 返回带有明确错误的Result
  3. 谁需要了解这个不变式?
    • 编译器 → 类型层面的编码
    • API使用者 → 清晰的类型签名
    • 仅运行时需要 → 文档说明

Trace Up ↑

向上追溯 ↑

When type design is unclear:
"Need to validate email format"
    ↑ Ask: Is this a domain value object?
    ↑ Check: m09-domain (Email as Value Object)
    ↑ Check: domain-* (validation requirements)
SituationTrace ToQuestion
What types to createm09-domainWhat's the domain model?
State machine designm09-domainWhat are valid transitions?
Marker trait usagem04-zero-costStatic or dynamic dispatch?

当类型设计不明确时:
"需要验证邮箱格式"
    ↑ 提问:这是领域值对象吗?
    ↑ 查看:m09-domain(邮箱作为值对象)
    ↑ 查看:domain-*(验证要求)
场景追溯至问题
需要创建哪些类型m09-domain领域模型是什么?
状态机设计m09-domain有效的状态转换有哪些?
Marker trait的使用m04-zero-cost使用静态还是动态分发?

Trace Down ↓

向下落地 ↓

From design to implementation:
"Need type-safe wrapper for primitives"
    ↓ Newtype: struct UserId(u64);

"Need compile-time state validation"
    ↓ Type State: Connection<Connected>

"Need to track phantom type parameters"
    ↓ PhantomData: PhantomData<T>

"Need capability markers"
    ↓ Marker Trait: trait Validated {}

"Need gradual construction"
    ↓ Builder: Builder::new().field(x).build()

从设计到实现:
"需要为原始类型提供类型安全的包装器"
    ↓ Newtype: struct UserId(u64);

"需要编译时状态验证"
    ↓ Type State: Connection<Connected>

"需要跟踪幽灵类型参数"
    ↓ PhantomData: PhantomData<T>

"需要能力标记"
    ↓ Marker Trait: trait Validated {}

"需要逐步构建"
    ↓ Builder: Builder::new().field(x).build()

Quick Reference

快速参考

PatternPurposeExample
NewtypeType safety
struct UserId(u64);
Type StateState machine
Connection<Connected>
PhantomDataVariance/lifetime
PhantomData<&'a T>
Marker TraitCapability flag
trait Validated {}
BuilderGradual construction
Builder::new().name("x").build()
Sealed TraitPrevent external impl
mod private { pub trait Sealed {} }
模式用途示例
Newtype类型安全
struct UserId(u64);
Type State状态机
Connection<Connected>
PhantomData可变性/生命周期跟踪
PhantomData<&'a T>
Marker Trait能力标记
trait Validated {}
Builder逐步构建
Builder::new().name("x").build()
Sealed Trait防止外部实现
mod private { pub trait Sealed {} }

Pattern Examples

模式示例

Newtype

Newtype模式

rust
struct Email(String);  // Not just any string

impl Email {
    pub fn new(s: &str) -> Result<Self, ValidationError> {
        // Validate once, trust forever
        validate_email(s)?;
        Ok(Self(s.to_string()))
    }
}
rust
struct Email(String);  // 不只是普通字符串

impl Email {
    pub fn new(s: &str) -> Result<Self, ValidationError> {
        // 验证一次,永久信任
        validate_email(s)?;
        Ok(Self(s.to_string()))
    }
}

Type State

Type State模式

rust
struct Connection<State>(TcpStream, PhantomData<State>);

struct Disconnected;
struct Connected;
struct Authenticated;

impl Connection<Disconnected> {
    fn connect(self) -> Connection<Connected> { ... }
}

impl Connection<Connected> {
    fn authenticate(self) -> Connection<Authenticated> { ... }
}

rust
struct Connection<State>(TcpStream, PhantomData<State>);

struct Disconnected;
struct Connected;
struct Authenticated;

impl Connection<Disconnected> {
    fn connect(self) -> Connection<Connected> { ... }
}

impl Connection<Connected> {
    fn authenticate(self) -> Connection<Authenticated> { ... }
}

Decision Guide

决策指南

NeedPattern
Type safety for primitivesNewtype
Compile-time state validationType State
Lifetime/variance markersPhantomData
Capability flagsMarker Trait
Gradual constructionBuilder
Closed set of implsSealed Trait
Zero-sized type markerZST struct

需求模式
原始类型的类型安全Newtype
编译时状态验证Type State
生命周期/可变性标记PhantomData
能力标志Marker Trait
逐步构建Builder
封闭的实现集合Sealed Trait
零大小类型标记ZST struct

Anti-Patterns

反模式

Anti-PatternWhy BadBetter
Boolean flags for statesRuntime errorsType state
String for semantic typesNo type safetyNewtype
Option for uninitializedUnclear invariantBuilder
Public fields with invariantsInvariant violationPrivate + validated new()

反模式危害替代方案
用布尔标志表示状态运行时错误Type state
用字符串表示语义类型无类型安全Newtype
用可选类型表示未初始化不变式不清晰Builder
带有不变式的公共字段可能违反不变式私有字段 + 已验证的new()方法

Related Skills

相关技能

WhenSee
Domain modelingm09-domain
Trait designm04-zero-cost
Error handling in constructorsm06-error-handling
Anti-patternsm15-anti-pattern
场景参考
领域建模m09-domain
Trait设计m04-zero-cost
构造函数中的错误处理m06-error-handling
反模式m15-anti-pattern