<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Tony Bai &#187; Go语言</title>
	<atom:link href="http://tonybai.com/tag/go%e8%af%ad%e8%a8%80/feed/" rel="self" type="application/rss+xml" />
	<link>https://tonybai.com</link>
	<description>一个程序员的心路历程</description>
	<lastBuildDate>Thu, 23 Apr 2026 23:15:02 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Go 代码设计的“第一天原则”：一份能让你少走五年弯路的实战模式清单</title>
		<link>https://tonybai.com/2026/04/24/go-code-design-day-one-principle-practical-patterns-list/</link>
		<comments>https://tonybai.com/2026/04/24/go-code-design-day-one-principle-practical-patterns-list/#comments</comments>
		<pubDate>Thu, 23 Apr 2026 23:13:22 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[CodeDesign]]></category>
		<category><![CDATA[ConfigurationManagement]]></category>
		<category><![CDATA[ContextManagement]]></category>
		<category><![CDATA[DayOnePrinciple]]></category>
		<category><![CDATA[DefensiveProgramming]]></category>
		<category><![CDATA[DependencyInjection]]></category>
		<category><![CDATA[EngineeringPractices]]></category>
		<category><![CDATA[ErrorHandling]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[GoLanguage]]></category>
		<category><![CDATA[Go语言]]></category>
		<category><![CDATA[GracefulShutdown]]></category>
		<category><![CDATA[InterfaceDesign]]></category>
		<category><![CDATA[metrics]]></category>
		<category><![CDATA[MinimumContract]]></category>
		<category><![CDATA[Mock]]></category>
		<category><![CDATA[observability]]></category>
		<category><![CDATA[prometheus]]></category>
		<category><![CDATA[Refactoring]]></category>
		<category><![CDATA[StructuredLogging]]></category>
		<category><![CDATA[TechnicalDebt]]></category>
		<category><![CDATA[Testability]]></category>
		<category><![CDATA[TypedErrors]]></category>
		<category><![CDATA[上下文管理]]></category>
		<category><![CDATA[代码设计]]></category>
		<category><![CDATA[代码重构]]></category>
		<category><![CDATA[优雅停机]]></category>
		<category><![CDATA[依赖注入]]></category>
		<category><![CDATA[可测试性]]></category>
		<category><![CDATA[可观测性]]></category>
		<category><![CDATA[工程实践]]></category>
		<category><![CDATA[技术债]]></category>
		<category><![CDATA[接口设计]]></category>
		<category><![CDATA[最小契约]]></category>
		<category><![CDATA[第一天原则]]></category>
		<category><![CDATA[类型化错误]]></category>
		<category><![CDATA[结构化日志]]></category>
		<category><![CDATA[配置管理]]></category>
		<category><![CDATA[错误处理]]></category>
		<category><![CDATA[防御性编程]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=6221</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2026/04/24/go-code-design-day-one-principle-practical-patterns-list 大家好，我是Tony Bai。 世界读书日送福利活动火热进行中，点击这里留言参与，赢取属于你的幸运！ 每一个 Go 开发者，大概都经历过这样的心路历程： 项目启动初期，为了追求“快”，我们怎么方便怎么来。配置到处写，数据库连接随手建，错误日志直接 fmt.Println。我们安慰自己：“先跑起来，以后再重构。” 结果呢？ 半年后，项目变成了一座摇摇欲坠的“屎山”。配置散落在几十个文件里，改一个端口号要动十个地方；数据库连接池因为没关，把连接数打满；线上出了 Bug，日志里只有一行孤零零的 record not found，查个问题比登天还难。 技术债，就像滚雪球，你越是假装看不见，它就滚得越大。 这时候，你的内心肯定在呐喊：有没有一些在Go项目刚创建时期就应该知道的Go代码模式，可以让我在项目的“第一天”，就建立起一套健壮、可维护、可观测的骨架呢！ 有的！ 我将这套方法论，称为 Go 语言架构的“第一天原则”。掌握它，足以让你在Go 代码设计的道路上，少走五年弯路。 这些原则，没有一条是关于炫技的复杂设计模式。 今天，我们就来逐条硬核拆解这些原则，并用可运行的 Go 代码，手把手教你如何将它们落地。 原则一：配置集中解析，依赖显式注入 这是所有“混乱”的根源。如果你的代码里，到处都是 os.Getenv(“DB_HOST”)，那你的项目已经走在了通往地狱的路上。 反模式： 在某个业务函数的深处，为了连一下 Redis，临时去读环境变量。这使得你的函数与外部环境强耦合，极难进行单元测试。 第一天原则： 在 main 函数中，一次性完成所有配置的解析和校验，然后通过构造函数，将“配置好”的依赖（如数据库连接池），以“接口”的形式，显式地注入到需要的服务中。 【Go 代码实战】 // https://go.dev/play/p/CrGDShmoFFJ package main import ( "context" "database/sql" "fmt" "log" "net/http" "os" _ "github.com/lib/pq" ) [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2026/go-code-design-day-one-principle-practical-patterns-list-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2026/04/24/go-code-design-day-one-principle-practical-patterns-list">本文永久链接</a> &#8211; https://tonybai.com/2026/04/24/go-code-design-day-one-principle-practical-patterns-list</p>
<p>大家好，我是Tony Bai。</p>
<blockquote>
<p>世界读书日送福利活动火热进行中，<a href="https://mp.weixin.qq.com/s/tSboOai1CE9IJBNg7BMPCg">点击这里</a>留言参与，赢取属于你的幸运！</p>
</blockquote>
<p>每一个 Go 开发者，大概都经历过这样的心路历程：</p>
<p>项目启动初期，为了追求“快”，我们怎么方便怎么来。配置到处写，数据库连接随手建，错误日志直接 fmt.Println。我们安慰自己：“先跑起来，以后再重构。”</p>
<p>结果呢？</p>
<p>半年后，项目变成了一座摇摇欲坠的“屎山”。配置散落在几十个文件里，改一个端口号要动十个地方；数据库连接池因为没关，把连接数打满；线上出了 Bug，日志里只有一行孤零零的 record not found，查个问题比登天还难。</p>
<p><strong>技术债，就像滚雪球，你越是假装看不见，它就滚得越大。</strong></p>
<p>这时候，你的内心肯定在呐喊：有没有一些在Go项目刚创建时期就应该知道的Go代码模式，可以让我在项目的<strong>“第一天”</strong>，就建立起一套健壮、可维护、可观测的骨架呢！</p>
<p>有的！</p>
<p>我将这套方法论，称为 <strong>Go 语言架构的“第一天原则”</strong>。掌握它，足以让你在Go 代码设计的道路上，少走五年弯路。</p>
<p>这些原则，没有一条是关于炫技的复杂设计模式。</p>
<p>今天，我们就来逐条硬核拆解这些原则，并用可运行的 Go 代码，手把手教你如何将它们落地。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/agentic-software-engineering-qr.png" alt="" /></p>
<h2>原则一：配置集中解析，依赖显式注入</h2>
<p>这是所有“混乱”的根源。如果你的代码里，到处都是 os.Getenv(“DB_HOST”)，那你的项目已经走在了通往地狱的路上。</p>
<p><strong>反模式：</strong></p>
<blockquote>
<p>在某个业务函数的深处，为了连一下 Redis，临时去读环境变量。这使得你的函数与外部环境强耦合，极难进行单元测试。</p>
</blockquote>
<p><strong>第一天原则：</strong></p>
<blockquote>
<p><strong>在 main 函数中，一次性完成所有配置的解析和校验，然后通过构造函数，将“配置好”的依赖（如数据库连接池），以“接口”的形式，显式地注入到需要的服务中。</strong></p>
</blockquote>
<p><strong>【Go 代码实战】</strong></p>
<pre><code class="go">// https://go.dev/play/p/CrGDShmoFFJ
package main

import (
    "context"
    "database/sql"
    "fmt"
    "log"
    "net/http"
    "os"

    _ "github.com/lib/pq"
)

type Config struct {
    DatabaseURL string
    ListenAddr  string
}

func loadConfig() Config {
    dbURL := os.Getenv("DATABASE_URL")
    if dbURL == "" {
        log.Fatal("DATABASE_URL is not set")
    }
    return Config{
        DatabaseURL: dbURL,
        ListenAddr:  ":8080",
    }
}

type UserRepo interface {
    GetUser(ctx context.Context, id int) (string, error)
}

type PostgresUserRepo struct {
    db *sql.DB
}

func (r *PostgresUserRepo) GetUser(ctx context.Context, id int) (string, error) {
    var name string
    err := r.db.QueryRowContext(ctx, "SELECT name FROM users WHERE id=$1", id).Scan(&amp;name)
    return name, err
}

func NewPostgresUserRepo(db *sql.DB) *PostgresUserRepo {
    return &amp;PostgresUserRepo{db: db}
}

type Server struct {
    repo UserRepo
}

func NewServer(repo UserRepo) *Server {
    return &amp;Server{repo: repo}
}

func (s *Server) HandleGetUser(w http.ResponseWriter, r *http.Request) {
    name, err := s.repo.GetUser(r.Context(), 1)
    if err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
        return
    }
    fmt.Fprintf(w, "User: %s", name)
}

func main() {
    cfg := loadConfig()

    db, err := sql.Open("postgres", cfg.DatabaseURL)
    if err != nil {
        log.Fatalf("failed to connect to database: %v", err)
    }
    defer db.Close()

    repo := NewPostgresUserRepo(db)
    server := NewServer(repo)

    http.HandleFunc("/user", server.HandleGetUser)
    log.Printf("Server starting on %s", cfg.ListenAddr)
    log.Fatal(http.ListenAndServe(cfg.ListenAddr, nil))
}
</code></pre>
<p>这样一来，你的业务代码将变得极其纯粹，不依赖任何全局状态，测试时也可以轻松地 Mock 掉 UserRepo 接口。</p>
<h2>原则二：为可观测性而设计：结构化日志与 Metrics</h2>
<p>“不就是打个日志吗，fmt.Println 走起！”——这是毁掉一个项目最快的方式。</p>
<p><strong>反模式：</strong></p>
<blockquote>
<p>遇到错误，直接 log.Printf(“Error: %v”, err)。当线上出现几万条这样的日志时，你根本无法进行聚合、告警和趋势分析。</p>
</blockquote>
<p><strong>第一天原则：</strong></p>
<blockquote>
<p><strong>从第一天起，就引入结构化日志（如 log/slog 或 zap）。将所有关键信息（如 user_id, trace_id）作为独立的字段打印。同时，为关键业务指标（如缓存命中率、数据库查询延迟）埋入 Metrics。</strong></p>
</blockquote>
<p><strong>【Go 代码实战】</strong></p>
<pre><code class="go">// https://go.dev/play/p/h4_8a4nzCFx
package main

import (
    "log/slog"
    "net/http"
    "os"
    "time"

    "github.com/prometheus/client_golang/prometheus"
    "github.com/prometheus/client_golang/prometheus/promhttp"
)

var (
    cacheHits = prometheus.NewCounter(prometheus.CounterOpts{
        Name: "myapp_cache_hits_total",
        Help: "Total number of cache hits.",
    })
    dbQueryDuration = prometheus.NewHistogram(prometheus.HistogramOpts{
        Name:    "myapp_db_query_duration_seconds",
        Help:    "Histogram of database query durations.",
        Buckets: prometheus.DefBuckets,
    })
)

func init() {
    prometheus.MustRegister(cacheHits, dbQueryDuration)
}

func handleRequest(w http.ResponseWriter, r *http.Request) {
    logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))

    logger.Info("handling request", "method", r.Method, "path", r.URL.Path, "remote_addr", r.RemoteAddr)

    cacheHits.Inc()

    start := time.Now()
    time.Sleep(100 * time.Millisecond)
    duration := time.Since(start)
    dbQueryDuration.Observe(duration.Seconds())

    logger.Info("request handled successfully", "duration_ms", duration.Milliseconds())
    w.WriteHeader(http.StatusOK)
}

func main() {
    http.HandleFunc("/", handleRequest)
    http.Handle("/metrics", promhttp.Handler())

    log.Println("Server starting on :8080")
    log.Fatal(http.ListenAndServe(":8080", nil))
}
</code></pre>
<p>有了结构化日志和Metrics的加持，你的系统不再是一个“黑盒”。通过 Grafana 和 VictoriaLogs，你可以清晰地看到它的每一个内部状态，问题定位速度提升 10 倍。</p>
<h2>原则三：永不启动一个你不知道如何停止的 Goroutine</h2>
<p>这是 <a href="https://tonybai.com/2026/04/13/dave-cheney-goroutine-management-philosophy/">Dave Cheney 反复强调的血泪教训</a>。一个失控的 Goroutine，就是一个内存炸弹。</p>
<p><strong>反模式：</strong></p>
<blockquote>
<p>go doSomething()。然后呢？它什么时候结束？如果它卡住了怎么办？</p>
</blockquote>
<p><strong>第一天原则：</strong></p>
<blockquote>
<p><strong>任何一个需要长久运行的 Goroutine，都必须接受一个 context.Context 参数，并在 select 中监听 ctx.Done()。将所有后台 Goroutine 的生命周期，与你的应用程序生命周期绑定。</strong></p>
</blockquote>
<p><strong>【Go 代码实战】</strong></p>
<pre><code class="go">// https://go.dev/play/p/Fi1JUZfs4E-
package main

import (
    "context"
    "log"
    "os"
    "os/signal"
    "syscall"
    "time"
)

func worker(ctx context.Context, id int) {
    ticker := time.NewTicker(1 * time.Second)
    defer ticker.Stop()

    log.Printf("Worker %d started", id)
    for {
        select {
        case &lt;-ticker.C:
            log.Printf("Worker %d is doing work", id)
        case &lt;-ctx.Done():
            log.Printf("Worker %d is shutting down...", id)
            return
        }
    }
}

func main() {
    ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
    defer cancel()

    go worker(ctx, 1)

    &lt;-ctx.Done()

    log.Println("Main application shutting down.")
    time.Sleep(100 * time.Millisecond)
}
</code></pre>
<p>这样，你的应用就可以实现优雅停机（Graceful Shutdown），在 k8s 环境中滚动更新时，不会丢失任何正在处理的数据。</p>
<h2>原则四：为可测试性而设计，构建你的“数据靶场”</h2>
<p>在复杂的业务系统中，最难测试的不是“Happy Path”，而是各种千奇百怪的“Unhappy Paths”。</p>
<p><strong>第一天原则：</strong></p>
<blockquote>
<p><strong>为你的核心业务逻辑，构建独立的“数据生成器（Data Generators）”和“数据接收器（Sinks）”。在测试中，用内存中的模拟实现（Mocks）替换掉真实的外部依赖，从而能 100% 控制输入和验证输出。</strong></p>
</blockquote>
<p><strong>【Go 代码实战】</strong></p>
<pre><code class="go">// https://go.dev/play/p/NBsxpVE84Zb
package main

import (
    "context"
    "fmt"
    "sync"
    "testing"
)

type Order struct { ID int }

type OrderNotifier interface {
    Notify(ctx context.Context, order Order) error
}

type OrderProcessor struct {
    notifier OrderNotifier
}

func NewOrderProcessor(notifier OrderNotifier) *OrderProcessor {
    return &amp;OrderProcessor{notifier: notifier}
}

func (p *OrderProcessor) Process(ctx context.Context, order Order) error {
    return p.notifier.Notify(ctx, order)
}

type MockNotifier struct {
    mu        sync.Mutex
    Notified  []Order
    ShouldErr bool
}

func (m *MockNotifier) Notify(ctx context.Context, order Order) error {
    m.mu.Lock()
    defer m.mu.Unlock()
    if m.ShouldErr {
        return fmt.Errorf("mock notifier failed")
    }
    m.Notified = append(m.Notified, order)
    return nil
}

func TestOrderProcessor_Success(t *testing.T) {
    mockNotifier := &amp;MockNotifier{}
    processor := NewOrderProcessor(mockNotifier)
    order := Order{ID: 1}
    err := processor.Process(context.Background(), order)

    if err != nil {
        t.Errorf("expected no error, got %v", err)
    }
    if len(mockNotifier.Notified) != 1 || mockNotifier.Notified[0].ID != 1 {
        t.Errorf("notifier was not called correctly")
    }
}
</code></pre>
<p>遵守该原则后，你的单元测试将变得极快、极度稳定，并且能够 100% 覆盖所有你能想到的成功和失败分支。</p>
<h2>原则五：防御性编程，构建你的“代码防火墙”</h2>
<p>不相信任何外部输入。这是所有安全系统的第一性原理。</p>
<p><strong>第一天原则：</strong></p>
<blockquote>
<p><strong>在数据的入口处（如 HTTP Handler、gRPC Server），对所有传入的数据进行严格的、显式的校验（Validation）。只有通过了“安检”的干净数据，才能被允许进入系统的核心领域。</strong></p>
</blockquote>
<p><strong>【Go 代码实战(不完全示例)】</strong></p>
<pre><code class="go">package main

import (
    "encoding/json"
    "fmt"
    "net/http"
    "net/mail"
)

type CreateUserRequest struct {
    Username string json:"username"
    Email    string json:"email"
    Age      int    json:"age"
}

func (r *CreateUserRequest) Validate() error {
    if len(r.Username) &lt; 3 || len(r.Username) &gt; 20 {
        return fmt.Errorf("username length must be between 3 and 20")
    }
    if _, err := mail.ParseAddress(r.Email); err != nil {
        return fmt.Errorf("invalid email format: %w", err)
    }
    if r.Age &lt; 18 {
        return fmt.Errorf("user must be at least 18 years old")
    }
    return nil
}

func HandleCreateUser(w http.ResponseWriter, r *http.Request) {
    var req CreateUserRequest
    if err := json.NewDecoder(r.Body).Decode(&amp;req); err != nil {
        http.Error(w, "Invalid request body", http.StatusBadRequest)
        return
    }

    if err := req.Validate(); err != nil {
        http.Error(w, err.Error(), http.StatusBadRequest)
        return
    }

    // processValidatedRequest(req) ...
    w.WriteHeader(http.StatusCreated)
}
</code></pre>
<p>这种防御可以让你的核心业务逻辑变得极其纯粹和安全，不再需要处理各种脏数据和边界情况。</p>
<blockquote>
<p>注：如果是服务器，外部(甚至是内部其他服务的)请求的速度也可能是一种“安全威胁”。因此无论是通过中间件，还是代码自行实现，<strong>限速机制</strong>是必不可少的。</p>
</blockquote>
<h2>原则六：错误包裹与类型化错误，让错误自己开口说话</h2>
<p>一个好的错误信息，应该像一份精准的“尸检报告”，而不是一句无意义的“他死了”。</p>
<p><strong>第一天原则：</strong></p>
<blockquote>
<p><strong>在错误产生的最底层，用 fmt.Errorf(“&#8230;: %w”, err) 详细包裹上下文。对于可预期的业务异常，定义成自定义的“类型化错误（Typed Errors）”，让上层逻辑可以通过 errors.As 进行精准的判断和处理。</strong></p>
</blockquote>
<p><strong>【Go 代码实战(不完全示例)】</strong></p>
<pre><code class="go">package main

import (
    "errors"
    "fmt"
    "net/http"
)

type ErrDuplicateUser struct { Email string }

func (e *ErrDuplicateUser) Error() string {
    return fmt.Sprintf("user with email %s already exists", e.Email)
}

func RegisterUser(email string) error {
    // 模拟数据库层返回一个已知类型的错误
    if email == "test@example.com" {
        return &amp;ErrDuplicateUser{Email: email}
    }
    return fmt.Errorf("db connection failed: %w", errors.New("timeout"))
}

func HandleRegister(w http.ResponseWriter, r *http.Request) {
    err := RegisterUser("test@example.com")
    if err != nil {
        var dupErr *ErrDuplicateUser
        if errors.As(err, &amp;dupErr) {
            http.Error(w, dupErr.Error(), http.StatusConflict)
        } else {
            // 对于未知的底层错误，只打日志，不暴露给用户
            slog.Error("failed to register user", "error", err)
            http.Error(w, "Internal server error", http.StatusInternalServerError)
        }
        return
    }
    w.WriteHeader(http.StatusCreated)
}
</code></pre>
<p>这样处理后，你的错误处理逻辑变得极其清晰和健壮，业务异常可以被优雅地反馈给用户。</p>
<h2>原则七：接口定义在消费侧，实现“最小化契约”</h2>
<p>这是 Go 语言最精髓、也最反直觉的一条哲学。</p>
<p><strong>第一天原则：</strong></p>
<blockquote>
<p><strong>永远不要在“定义侧”声明臃肿的接口。而是在“消费侧”，根据你真正需要的功能，定义一个只包含 1-2 个方法的“小接口”。</strong></p>
</blockquote>
<p><strong>【Go 代码实战（不完全示例）】</strong></p>
<pre><code class="go">// --- cache/cache.go ---
package cache
type BigCache struct {}
func (c *BigCache) Get(key string) (string, error) { /* ... */ }
func (c *BigCache) Set(key, val string) error     { /* ... */ }

// --- user/service.go ---
package user
import "fmt"
// 我们在 user 包里，只定义我们真正需要的小接口
type Getter interface {
    Get(key string) (string, error)
}
type UserService struct {
    cache Getter // 依赖的是小接口，而不是具体的 BigCache
}
func (s *UserService) GetUserName(id int) (string, error) {
    return s.cache.Get(fmt.Sprintf("user:%d", id))
}
</code></pre>
<p>示例代码中，你的 UserService 彻底与 BigCache 的具体实现解耦。在测试时可以极其轻松地传入 Mock 对象。</p>
<h2>小结：架构的本质，是与未来的自己对话</h2>
<p>看完上述的七条原则，你是否发现所有这些“第一天原则”都指向了一个共同的核心：<strong>可维护性（Maintainability）</strong>。</p>
<p>你在项目第一天偷的每一个懒，都会在未来的某一个深夜，变成一颗狠狠炸伤你或你同事的“技术地雷”。<strong>架构的本质，不是选择一个多么牛逼的框架，而是与未来的自己、未来的同事进行一场清晰、友好的对话。</strong></p>
<p>关掉这篇文章，打开你手头那个最新的项目。看看这 7 条原则，你触犯了哪几条？是时候，给你的代码库做一次“体检”了。</p>
<hr />
<p><strong>今日互动探讨：</strong></p>
<p>在你过去的 Go 项目中，踩过哪些因为早期“野蛮生长”而导致的设计大坑？除了这 7 条，你还有哪些“压箱底”的项目启动最佳实践？</p>
<p>欢迎在评论区分享你的血泪史与独家心法！</p>
<hr />
<p>还在为写 Agent 框架频频死循环、上下文爆炸而束手无策？我的新专栏 <strong>《<a href="http://gk.link/a/12IzL">从0 开始构建 Agent Harness</a>》</strong> 将带你：</p>
<ul>
<li>抛弃臃肿框架，回归“驾驭工程 (Harness Engineering)”的第一性原理</li>
<li>用 Go 语言手写 ReAct 循环、并发拦截与上下文压缩引擎等，复刻极简OpenClaw</li>
<li>构建坚不可摧的 Safety Middleware 与飞书人工审批防线</li>
<li>在底层实现 Token 成本审计、链路追踪与自动化跑分评估</li>
<li>从“调包侠”进化为掌控大模型边界的“AI 操作系统架构师”</li>
</ul>
<p>扫描下方二维码，开启从 0 开始构建Agent Harness 的实战之旅。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/build-agent-harness-from-scratch-qr.png" alt="" /></p>
<hr />
<p><strong>原「Gopher部落」已重装升级为「Go &amp; AI 精进营」知识星球，快来加入星球，开启你的技术跃迁之旅吧！</strong></p>
<p>我们致力于打造一个高品质的 <strong>Go 语言深度学习</strong> 与 <strong>AI 应用探索</strong> 平台。在这里，你将获得：</p>
<ul>
<li><strong>体系化 Go 核心进阶内容:</strong> 深入「Go原理课」、「Go进阶课」、「Go避坑课」等独家深度专栏，夯实你的 Go 内功。</li>
<li><strong>前沿 Go+AI 实战赋能:</strong> 紧跟时代步伐，学习「Go+AI应用实战」、「Agent开发实战课」、「Agentic软件工程课」、「Claude Code开发工作流实战课」、「OpenClaw实战分享」等，掌握 AI 时代新技能。 </li>
<li><strong>星主 Tony Bai 亲自答疑:</strong> 遇到难题？星主第一时间为你深度解析，扫清学习障碍。</li>
<li><strong>高活跃 Gopher 交流圈:</strong> 与众多优秀 Gopher 分享心得、讨论技术，碰撞思想火花。</li>
<li><strong>独家资源与内容首发:</strong> 技术文章、课程更新、精选资源，第一时间触达。</li>
</ul>
<p>衷心希望「Go &amp; AI 精进营」能成为你学习、进步、交流的港湾。让我们在此相聚，享受技术精进的快乐！欢迎你的加入！</p>
<p><img src="http://image.tonybai.com/img/tonybai/gopher-and-ai-tribe-zsxq-small-card.jpg" alt="img{512x368}" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2026, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2026/04/24/go-code-design-day-one-principle-practical-patterns-list/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>HashiCorp 创始人亲口“认错”：AI 让我重新爱上了 Go (文末福利)</title>
		<link>https://tonybai.com/2026/04/23/hashicorp-founder-admits-go-is-alive-thanks-to-ai/</link>
		<comments>https://tonybai.com/2026/04/23/hashicorp-founder-admits-go-is-alive-thanks-to-ai/#comments</comments>
		<pubDate>Thu, 23 Apr 2026 00:18:03 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[AgentHarness]]></category>
		<category><![CDATA[AgenticWorkflow]]></category>
		<category><![CDATA[AIAgent]]></category>
		<category><![CDATA[APICalling]]></category>
		<category><![CDATA[API调用]]></category>
		<category><![CDATA[ArtificialIntelligence]]></category>
		<category><![CDATA[CodeGeneration]]></category>
		<category><![CDATA[CrossCompilation]]></category>
		<category><![CDATA[DevelopmentEfficiency]]></category>
		<category><![CDATA[EngineeringPhilosophy]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[GoLanguage]]></category>
		<category><![CDATA[Go语言]]></category>
		<category><![CDATA[HarnessEngineering]]></category>
		<category><![CDATA[hashicorp]]></category>
		<category><![CDATA[MachineEngineering]]></category>
		<category><![CDATA[Minimalism]]></category>
		<category><![CDATA[MitchellHashimoto]]></category>
		<category><![CDATA[Rust]]></category>
		<category><![CDATA[SoftwareEngineering]]></category>
		<category><![CDATA[StaticTyping]]></category>
		<category><![CDATA[Zig]]></category>
		<category><![CDATA[交叉编译]]></category>
		<category><![CDATA[人工智能]]></category>
		<category><![CDATA[代码生成]]></category>
		<category><![CDATA[工程哲学]]></category>
		<category><![CDATA[开发效率]]></category>
		<category><![CDATA[智能体]]></category>
		<category><![CDATA[机器工程学]]></category>
		<category><![CDATA[极简主义]]></category>
		<category><![CDATA[软件工程]]></category>
		<category><![CDATA[静态类型]]></category>
		<category><![CDATA[驾驭工程]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=6217</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2026/04/23/hashicorp-founder-admits-go-is-alive-thanks-to-ai 大家好，我是Tony Bai。 今天是世界读书日，在同款公众号文章的文末我将送出两个价值 99 元的《从 0 开始构建 Agent Harness》专栏的免费兑换码，欢迎大家点击这里积极留言参与！ 在技术圈的江湖里，总有那么几位“扫地僧”级别的人物。他们的一言一行，足以引发整个行业的地震。Mitchell Hashimoto，正是其中之一。 作为 HashiCorp 的创始人，曾连续12年，一手使用Go 缔造了Consul、Nomad、Terraform、Vagrant、Vault 等一系列云原生基础设施与Devops“神器”以及Ghostty Terminal (使用 Zig )的他，被无数开发者奉为“云基础设施时代教父级的人物”。 但在 Go 社区，Mitchell 的形象却颇具争议。因为他曾在公开场合不止一次地表达过对 Go 语言的失望，甚至抛出过“Go has no place anymore”（Go 已无立足之地）这样的“暴论”。 然而，就在最近，这位曾经的“Go 社区的争议人物”，却在 X 平台上发表了一篇 180 度大转弯的“认错”长推，瞬间引爆了整个技术圈，获得了超过 21 万的阅读量。 他写道： “我又开始写 Go 了……‘等等，我以为你说过 Go 已经没有位置了？’我错了。” “我错的原因，主要是因为 AI 智能体（Agent）在 Go 语言上的生产力高得惊人。我不会把其他语言扯进来，因为我不想喂饱那些螃蟹（暗指 Rust 社区）。” [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2026/hashicorp-founder-admits-go-is-alive-thanks-to-ai-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2026/04/23/hashicorp-founder-admits-go-is-alive-thanks-to-ai">本文永久链接</a> &#8211; https://tonybai.com/2026/04/23/hashicorp-founder-admits-go-is-alive-thanks-to-ai</p>
<p>大家好，我是Tony Bai。</p>
<blockquote>
<p>今天是世界读书日，在<a href="https://mp.weixin.qq.com/s/tSboOai1CE9IJBNg7BMPCg">同款公众号文章</a>的文末我将送出两个价值 99 元的《<a href="http://gk.link/a/12IzL">从 0 开始构建 Agent Harness</a>》专栏的免费兑换码，欢迎大家<a href="https://mp.weixin.qq.com/s/tSboOai1CE9IJBNg7BMPCg">点击这里</a>积极留言参与！</p>
</blockquote>
<p>在技术圈的江湖里，总有那么几位“扫地僧”级别的人物。他们的一言一行，足以引发整个行业的地震。<strong>Mitchell Hashimoto</strong>，正是其中之一。</p>
<p>作为 HashiCorp 的创始人，曾连续12年，一手使用Go 缔造了Consul、Nomad、Terraform、Vagrant、Vault 等一系列云原生基础设施与Devops“神器”以及Ghostty Terminal (使用 Zig )的他，被无数开发者奉为“云基础设施时代教父级的人物”。</p>
<p>但在 Go 社区，Mitchell 的形象却颇具争议。因为他曾在公开场合不止一次地表达过对 Go 语言的失望，甚至抛出过<strong>“Go has no place anymore”（Go 已无立足之地）</strong>这样的“暴论”。</p>
<p>然而，就在最近，这位曾经的“Go 社区的争议人物”，却在 X 平台上发表了<a href="https://x.com/mitchellh/status/2046319366489407803">一篇 180 度大转弯的“认错”长推</a>，瞬间引爆了整个技术圈，获得了超过 <strong>21 万</strong>的阅读量。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/hashicorp-founder-admits-go-is-alive-thanks-to-ai-2.png" alt="" /></p>
<p>他写道：</p>
<blockquote>
<p>“我又开始写 Go 了……‘等等，我以为你说过 Go 已经没有位置了？’<strong>我错了。</strong>”</p>
<p>“我错的原因，主要是因为 AI 智能体（Agent）在 Go 语言上的生产力高得惊人。我不会把其他语言扯进来，因为我不想喂饱那些螃蟹（暗指 Rust 社区）。”</p>
</blockquote>
<p>是什么，让这位顶级大神发生了如此戏剧性的转变？</p>
<p>今天，我们就来深度扒开 Mitchell 的这篇“忏悔录”，看看在 AI Agent 席卷一切的时代，Go 语言那些曾被我们疯狂吐槽的“缺点”，是如何摇身一变，成为最顶级的“超能力”的。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/agentic-software-engineering-qr.png" alt="" /></p>
<h2>惊天反转：“糟糕的人体工程学”，竟是完美的“机器工程学”</h2>
<p>Mitchell 在推文中，首先就点出了一个极其“讽刺”的现象：</p>
<blockquote>
<p>“这很有趣，因为 Go 的很多 CLI 工具，比如 go doc 和 gopls，它们糟糕的人体工程学（shitty ergonomics）……竟然被 Agent 完美地规避了。不仅如此，讽刺的是，它们对 Agent 来说简直是天赐之物。”</p>
</blockquote>
<p>这句话，堪称整篇推文的点睛之笔。</p>
<p>如果你是一个有经验的 Go 开发者，你一定吐槽过 go doc 的简陋，或者早期 gopls 的各种不智能。相比于 Rust 的 rust-analyzer 那种极其强大的类型推断和代码补全，Go 的工具链显得既“笨”又“直白”。</p>
<p>但在 AI Agent 的世界里，这种“笨拙”，恰恰成了最顶级的优点！</p>
<p>Mitchell 指出，他现在根本不需要给 Agent 写任何复杂的 Skill。只需要在 AGENTS.md 里写一句极其简单的指令：<strong>“想找 API 或者调用者？去用 gopls。”</strong></p>
<p>Agent 就能利用 gopls 提供的底层 LSP（语言服务器协议）接口，以极低的 Token 成本，精准地找到接口的实现、方法的定义，以及所有的调用关系。</p>
<p>另一位开发者在评论中也补充道：</p>
<blockquote>
<p>“我们一直抱怨 Go 的啰嗦（verbosity），结果证明这恰恰是 LLM 最喜欢的。它们能清晰地读懂意图，而且工具链（如 go doc）给了它们足够的上下文，让它们第一次就能写出能跑通的代码。”</p>
</blockquote>
<p><strong>看懂了吗？</strong></p>
<p>那些曾经被人类程序员嫌弃的“机器友好”的接口，在 AI Agent 这个“硅基程序员”面前，摇身一变成了最高效、最廉价的沟通方式。</p>
<p>我们过去追求的“CLI 人体工程学”，在 AI 时代，正在被<strong>“Agent 机器工程学”</strong>所降维打击。</p>
<h2>王者归来：当“无聊”成为 AI 的最佳温床</h2>
<p>Mitchell 的“认错”，不仅仅是因为工具链的意外适配。更深层次的原因，在于 Go 语言本身的“无聊”哲学。</p>
<p>在另一场由 <a href="https://tonybai.com/2026/03/23/go-is-the-best-programming-language-for-llm/">OpenAI 创始人引发的“Go vs Rust”论战</a>中，我们已经探讨过这个观点：</p>
<p>Go 语言极简的语法、强制的 gofmt 格式化、以及“万物皆 for 循环”的单一表达方式，使得所有 Go 代码库看起来都像是一个模子里刻出来的。</p>
<p>这种极度的“同质化”，对于基于概率预测的 AI Agent 来说，简直就是天堂。</p>
<p>AI 在生成 Go 代码时，不需要去猜测这个项目是函数式风格还是面向对象风格，不需要去处理复杂的生命周期和所有权问题。它只需要遵循那套刻在骨子里的“Go Way”，就能生成出八九不离十的、能跑通的代码。</p>
<p>评论区里，HashiCorp 的前同事现身说法：</p>
<blockquote>
<p>“我当年就是看到 HashiCorp 在用 Go 才入坑的。你今天的这篇帖子，完美地解释了为什么我最近又回到了 Go 的怀抱。”</p>
</blockquote>
<p><strong>简单、可预测、没有魔法。</strong> 这些在人类极客眼中可能是“缺点”的特质，在 AI Agent 眼里，却成了最宝贵的“确定性”。</p>
<h2>终极答案：Go + Zig，基础设施的“黄金搭档”</h2>
<p>当然，Mitchell 也并非无脑吹捧 Go。作为一个顶级的开发者，他清醒地认识到 Go 的边界。</p>
<p>当他需要编写一个<strong>“可移植的、能轻松嵌入各种生态系统”</strong>的底层库时，他并没有选择 Go，而是选择了 <strong>Zig</strong>。</p>
<blockquote>
<p>“对我来说，重要的是可移植性。我正在写一个必须能轻松嵌入各种生态系统的通用库。一个独立的、不依赖 libc、没有操作系统原语要求、能说 C ABI、并且只有 100KB 大小的库，是一个很容易推销的方案。”</p>
</blockquote>
<p>在这里，Mitchell 亮出了他的答案：<strong>Go + Zig。</strong></p>
<ul>
<li><strong>Go</strong>：负责上层的、高并发的业务逻辑和网络调度。</li>
<li><strong>Zig</strong>：负责底层的、需要极致性能、零依赖、跨平台 C ABI 兼容的核心组件。</li>
<li><strong>CGO</strong>：通过 Zig 强大的交叉编译能力，将 Go 与底层 C-ABI 组件的胶水成本降到最低。</li>
</ul>
<p>这套组合拳，既享受了 Go 无与伦比的开发效率和并发模型，又利用了 Zig 对底层的极致压榨能力，同时还避开了原生 CGO 的种种编译噩梦。</p>
<p>这或许是比“Go vs Rust”之争，更具前瞻性和实操价值的“版本答案”。</p>
<h2>英雄所见略同：Pandas 之父的“痛苦告别”</h2>
<p>如果说 Mitchell Hashimoto 的“回归”还带有一丝 云原生以及DevOps 创始人的恋旧情结，那么另一位顶级大神——<strong>Pandas 库的创始人、数据科学界的“教父级”人物 Wes McKinney</strong>——的2026表态，则更像是一封写给 Python 的“分手信”，充满了痛苦、不舍，但又极其决绝。</p>
<p>就在 Mitchell 的推文引发热议的同时，有人在评论区挖出了 Wes McKinney 今年年初的一篇极具前瞻性的博文《<a href="https://wesmckinney.com/blog/agent-ergonomics/">从人类工程学到智能体工程学</a>》。</p>
<p>在这篇文章里，Wes McKinney 抛出了一个极其震撼的开场白：</p>
<blockquote>
<p><strong>“我最近用 Go 写了很多新软件。但问题是，我这辈子其实一行 Go 代码都没写过。这到底是怎么回事？”</strong></p>
</blockquote>
<p>答案，同样是 AI Agent。</p>
<p>作为一个将毕生心血都奉献给了 Python 数据科学生态的巨匠，Wes McKinney 坦言，当软件的“主要作者”从人类变成 AI 时，我们评判一门编程语言优劣的标准，发生了根本性的改变。</p>
<blockquote>
<p><strong>“人类工程学（Human Ergonomics）的重要性正在急剧下降。Python 对人类来说极其愉快和高效，但当 Agent 替你写所有代码时，这个好处就显得无足轻重了。”</strong></p>
</blockquote>
<p>他用一种近乎“残忍”的视角，剖析了 Python 在 AI Agent 时代的三个致命缺陷：</p>
<ol>
<li><strong>缓慢的编译-测试循环</strong>：Agent 编译和测试的频率比人类高出一到两个数量级。Python 缓慢的测试启动和依赖安装，对 Agent 来说是一种“惩罚”。</li>
<li><strong>痛苦的软件分发</strong>：Agent 需要大量自包含的、无依赖的二进制工具。而 Python 拖着一个沉重的解释器，感觉就像“我们当年拼命想摆脱的 Java 虚拟机（JVM）”。</li>
<li><strong>性能与内存的短板</strong>：这些在人类开发时可以容忍的问题，在 Agent 24 小时高强度运行时，会被无限放大。</li>
</ol>
<p><img src="https://tonybai.com/wp-content/uploads/2026/hashicorp-founder-admits-go-is-alive-thanks-to-ai-3.png" alt="" /><br />
<center>图 Python Environment https://xkcd.com/1987/ </center></p>
<p><strong>那么，AI Agent 时代的“赢家”是谁？</strong></p>
<p>Wes McKinney 给出了和 Mitchell Hashimoto 几乎一模一样的答案：<strong>Go</strong>。当然在数据科学以及人工智能的基础设施层面，Wes McKinney认为 Rust 也将会占据着越来越重要的地位。</p>
<p>因为它们解决了最关键的三个问题：</p>
<ul>
<li><strong>无痛构建静态二进制文件。</strong></li>
<li><strong>极速、确定性的构建过程。</strong></li>
<li><strong>精简的资源占用和出色的运行时性能。</strong></li>
</ul>
<p>他甚至更进一步指出，由于 Go 拥有比 Rust 快得多的编译时间，在 Agent 高频迭代的场景下，Go 甚至比 Rust 更具优势。</p>
<blockquote>
<p>“我依然深爱着 Python，并为我们建立的生态系统感到自豪。但很明显，鉴于 Agent 循环带来的生产力优势，我和业界的大部分人，将会写越来越少的 Python，转而拥抱 Go 和其他现代编译语言。”</p>
</blockquote>
<p>一个为 Python 奋斗了近 20 年的灵魂人物，最终为了 AI，选择了自己从未写过的 Go。</p>
<p>这已经不是简单的技术选型，这是一场关于<strong>“工程师生存法则”</strong>的深刻变革。</p>
<h2>英雄惜英雄：一场关于“回归”的集体狂欢</h2>
<p>Mitchell 的这篇“认错”长文，像一声号角，引来了无数在 Go 与其他语言之间摇摆的开发者的共鸣。</p>
<p>Bun 的创始人 Jarred Sumner 激动地在评论区留言：“我想看看你到底在搞什么！”（Mitchell 回复：“我早点联系你！”）</p>
<p>一位前 Vercel 工程师更是直言：“老哥你终于兜了一圈又回来了！”</p>
<p>当然也有一些开发者表示这也许是Mitchell的“幻觉”或“偏见”，一位开发者(显然不是很熟悉 Mitchell 的开发过往)写道：</p>
<blockquote>
<p>“也许你只是比 Zig 更不习惯 Go，所以你注意到的 Go 的问题更少。而且你已经是 Zig 的专家了，用它提升的空间不大了(想学习一下新的编程语言)。LLM 让你看到在你不懂的领域(指Go)正确率是 100%，但在你懂 60% 的领域(指Zig)，只对了 60%”。<br />
  <em>（Mitchell 则毫不客气地回怼：“我写了 12 年全职的、纯粹的 Go。我的判断力很可靠。”）</em></p>
</blockquote>
<p>这场大讨论，最终演变成了一场关于“回归 Go”的集体狂欢。</p>
<h2>小结：在 AI 时代，重新审视“简单”的价值</h2>
<p>Mitchell Hashimoto 的故事，是 AI 时代软件工程演进的一个完美缩影。</p>
<p>一个曾经因为 Go 的“不够底层”、“人体工程学差”而选择离开的顶级大神，最终又因为 AI Agent 的出现，重新发现了这门语言在“机器工程学”上的巨大价值。</p>
<p>这提醒我们所有技术人：<strong>对一门语言的评判，永远不能脱离其所处的时代背景和生产力工具。</strong></p>
<p>在人类手搓代码的时代，我们追求的是表达力的丰富和语法的灵巧。</p>
<p>而在 AI 自动生成的时代，<strong>简单、可预测、无歧义、易于机器理解</strong>，反而成了最稀缺的“黄金法则”。</p>
<p>Go 语言的缔造者们，在十几年前就用近乎偏执的克制，为我们埋下了一颗时间的种子。</p>
<p>直到今天，在 AI 的催化下，这颗种子，终于长成了参天大树。</p>
<p>资料链接：</p>
<ul>
<li>https://x.com/mitchellh/status/2046319366489407803</li>
<li>https://wesmckinney.com/blog/agent-ergonomics/</li>
</ul>
<hr />
<p><strong>今日互动探讨：</strong></p>
<p>在 AI 编程的浪潮中，你是否也像 Mitchell 一样，重新审视了自己对某门语言的看法？你认为在 AI Agent 眼里，最“友好”和最“劝退”的语言分别是什么？</p>
<p>欢迎在评论区分享你的观点！</p>
<hr />
<p><strong>世界图书日特别福利：一本定义未来的“活书”</strong></p>
<p>今天（4月23日）就是世界图书日。</p>
<p>在这个属于知识与智慧的节日里，与其被动地阅读别人写的书，不如我们亲手来“写”一本定义未来的“书”——<strong>构建一个属于你自己的 AI Agent Harness</strong>。</p>
<p>Mitchell Hashimoto 和 Wes McKinney 的故事告诉我们，AI Agent 正在成为这个时代最强大的生产力杠杆。而驾驭这头巨兽的核心，不在于你会背多少 Prompt，而在于你是否懂得如何为它构建一个坚不可摧的“驾驭系统（Harness）”。</p>
<p>为了庆祝我的全新极客时间专栏 <strong>《<a href="http://gk.link/a/12IzL">从 0 开始构建 Agent Harness</a>》</strong> 上线，并感谢大家一直以来的支持，我将拿出 <strong>2 个免费的专栏兑换码</strong>送给大家！</p>
<p><strong>参与方式：</strong></p>
<p>关注本公众号，并在本文的评论区留言，聊一聊：<strong>“在 AI Agent 时代，你认为一个程序员最不可被替代的核心技能是什么？为什么？”</strong></p>
<p>我将在 <strong>72 小时后</strong>，从所有精选留言中，挑选 <strong>2 位最深刻、最走心的思考</strong>，每人赠送一份价值 99 元的《<a href="http://gk.link/a/12IzL">从 0 开始构建 Agent Harness</a>》专栏兑换码。</p>
<hr />
<p>还在为写 Agent 框架频频死循环、上下文爆炸而束手无策？我的新专栏 <strong>《<a href="http://gk.link/a/12IzL">从0 开始构建 Agent Harness</a>》</strong> 将带你：</p>
<ul>
<li>抛弃臃肿框架，回归“驾驭工程 (Harness Engineering)”的第一性原理</li>
<li>用 Go 语言手写 ReAct 循环、并发拦截与上下文压缩引擎等，复刻极简OpenClaw</li>
<li>构建坚不可摧的 Safety Middleware 与飞书人工审批防线</li>
<li>在底层实现 Token 成本审计、链路追踪与自动化跑分评估</li>
<li>从“调包侠”进化为掌控大模型边界的“AI 操作系统架构师”</li>
</ul>
<p>扫描下方二维码，开启从 0 开始构建Agent Harness 的实战之旅。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/build-agent-harness-from-scratch-qr.png" alt="" /></p>
<hr />
<p>还在为“复制粘贴喂AI”而烦恼？我的新专栏 <strong>《<a href="http://gk.link/a/12EPd">AI原生开发工作流实战</a>》</strong> 将带你：</p>
<ul>
<li>告别低效，重塑开发范式</li>
<li>驾驭AI Agent(Claude Code)，实现工作流自动化</li>
<li>从“AI使用者”进化为规范驱动开发的“工作流指挥家”</li>
</ul>
<p>扫描下方二维码，开启你的AI原生开发之旅。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/ai-native-dev-workflow-qr.png" alt="" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2026, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2026/04/23/hashicorp-founder-admits-go-is-alive-thanks-to-ai/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>为什么说 go 语句是新时代的 goto？四大法则拯救失控 goroutine</title>
		<link>https://tonybai.com/2026/04/16/structured-concurrency-in-go-research-oriented-perspective/</link>
		<comments>https://tonybai.com/2026/04/16/structured-concurrency-in-go-research-oriented-perspective/#comments</comments>
		<pubDate>Wed, 15 Apr 2026 23:34:11 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[conc]]></category>
		<category><![CDATA[deadlock]]></category>
		<category><![CDATA[DistributedSystems]]></category>
		<category><![CDATA[errgroup]]></category>
		<category><![CDATA[ErrorPropagation]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[GoLanguage]]></category>
		<category><![CDATA[goroutine]]></category>
		<category><![CDATA[GoToStatementConsideredHarmful]]></category>
		<category><![CDATA[Goto有害论]]></category>
		<category><![CDATA[Go语言]]></category>
		<category><![CDATA[LexicalScope]]></category>
		<category><![CDATA[LifecycleManagement]]></category>
		<category><![CDATA[MonitorPattern]]></category>
		<category><![CDATA[OwnershipPrinciple]]></category>
		<category><![CDATA[PhysicalEncapsulationPrinciple]]></category>
		<category><![CDATA[RaceCondition]]></category>
		<category><![CDATA[ResourceLeak]]></category>
		<category><![CDATA[ScopeClosurePrinciple]]></category>
		<category><![CDATA[SpaghettiCode]]></category>
		<category><![CDATA[StructuredConcurrency]]></category>
		<category><![CDATA[StructuredProgramming]]></category>
		<category><![CDATA[SynchronousAppearancePrinciple]]></category>
		<category><![CDATA[waitgroup]]></category>
		<category><![CDATA[作用域闭环原则]]></category>
		<category><![CDATA[分布式系统]]></category>
		<category><![CDATA[协程]]></category>
		<category><![CDATA[同步外观原则]]></category>
		<category><![CDATA[意大利面条代码]]></category>
		<category><![CDATA[所有权原则]]></category>
		<category><![CDATA[死锁]]></category>
		<category><![CDATA[物理封装原则]]></category>
		<category><![CDATA[生命周期管理]]></category>
		<category><![CDATA[监控模式]]></category>
		<category><![CDATA[竞态条件]]></category>
		<category><![CDATA[结构化并发]]></category>
		<category><![CDATA[结构化编程]]></category>
		<category><![CDATA[词法作用域]]></category>
		<category><![CDATA[资源泄漏]]></category>
		<category><![CDATA[错误传播]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=6186</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2026/04/16/structured-concurrency-in-go-research-oriented-perspective 大家好，我是Tony Bai。 Go 语言的 go 关键字是并发编程史上的一次民主化革命，它让并发变得前所未有的廉价和简单。只需在一个函数调用前加上 go，我们就拥有了一个并发执行的任务。 这种语法是如此的诱人，以至于新手 Gopher 往往会沉迷于创建成千上万个 Goroutine。 随着 Go 语言步入第 16 个年头，学术界和工程界也开始重新审视这种“极简主义”带来的副作用。 2025 年 3 月，一篇发表在《Scientific Research Journal》上的重磅论文《Structured Concurrency in Go: A Research-Oriented Perspective》，将 Go 的并发模型与 1968 年 Dijkstra 对 Goto 语句的批判联系了起来。 论文作者 Georgii Kliukovkin 指出，这种“发射后不管（Fire-and-Forget）”的模式，虽然在 Hello World 级别的程序中运行良好，但在大规模分布式系统中，它是资源泄漏、死锁和竞态条件的温床。 我们日常也常听到这样的抱怨：“Go 的并发很简单，但写出正确的并发代码很难。” 这并非语言本身的缺陷，而是因为我们缺乏一种与语言灵活性相匹配的约束纪律。这种纪律，就是结构化并发。 本文将深入解读这篇论文，探讨为何“不受限制的 Goroutine”正在成为新时代的“Goto 语句”，以及我们如何通过结构化并发（Structured Concurrency）的四大法则，将失控的协程重新关回笼子，构建坚如磐石的系统。 历史的镜像——从 Goto [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2026/structured-concurrency-in-go-research-oriented-perspective-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2026/04/16/structured-concurrency-in-go-research-oriented-perspective">本文永久链接</a> &#8211; https://tonybai.com/2026/04/16/structured-concurrency-in-go-research-oriented-perspective</p>
<p>大家好，我是Tony Bai。</p>
<p>Go 语言的 go 关键字是并发编程史上的一次民主化革命，它让并发变得前所未有的廉价和简单。只需在一个函数调用前加上 go，我们就拥有了一个并发执行的任务。</p>
<p>这种语法是如此的诱人，以至于新手 Gopher 往往会沉迷于创建成千上万个 Goroutine。</p>
<p>随着 Go 语言步入第 16 个年头，学术界和工程界也开始重新审视这种“极简主义”带来的副作用。</p>
<p>2025 年 3 月，一篇发表在《Scientific Research Journal》上的重磅论文《<a href="https://www.scirj.org/papers-0325/scirj-P03251013.pdf">Structured Concurrency in Go: A Research-Oriented Perspective</a>》，将 Go 的并发模型与 1968 年 Dijkstra 对 Goto 语句的批判联系了起来。</p>
<p>论文作者 Georgii Kliukovkin 指出，这种“发射后不管（Fire-and-Forget）”的模式，虽然在 Hello World 级别的程序中运行良好，但在大规模分布式系统中，它是资源泄漏、死锁和竞态条件的温床。</p>
<p>我们日常也常听到这样的抱怨：“Go 的并发很简单，但写出正确的并发代码很难。” 这并非语言本身的缺陷，而是因为我们缺乏一种与语言灵活性相匹配的约束纪律。这种纪律，就是<strong>结构化并发</strong>。</p>
<p>本文将深入解读这篇论文，探讨为何“不受限制的 Goroutine”正在成为新时代的“Goto 语句”，以及我们如何通过<strong>结构化并发（Structured Concurrency）</strong>的四大法则，将失控的协程重新关回笼子，构建坚如磐石的系统。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/paid/inside-goroutine-scheduler-qr.png" alt="" /></p>
<h2>历史的镜像——从 Goto 有害论到 Goroutine 有害论？</h2>
<p>要理解“结构化并发”，我们必须先回顾历史。</p>
<h3>1968年的呼喊：结构化编程的诞生</h3>
<p>在 20 世纪 60 年代，编程界流行的是“非结构化编程”。开发者可以随心所欲地使用 goto 语句在代码的任意位置跳转。这种自由带来了极大的灵活性，但也导致了所谓的“<a href="https://tonybai.com/2025/07/16/when-spaghetti-code-knocks">意大利面条代码（Spaghetti Code）</a>”——控制流杂乱无章，难以追踪程序的执行路径，维护简直是噩梦。</p>
<p>1968 年，图灵奖得主 Edsger W. Dijkstra 发表了那篇著名的《Go To Statement Considered Harmful》（Goto 语句有害论）。他主张废除无限制的跳转，转而使用结构化编程（Structured Programming）：即所有的逻辑都应由顺序结构、选择结构（if/else）和循环结构（for/while）以及函数调用（Function Call）组成。</p>
<p>结构化编程的核心价值在于“黑盒化”。当你调用一个函数时，你确信控制权最终会回到你手中（除非死循环或崩溃）；你确信该函数内部的变量不会污染外部环境。这种“入口-出口”的对称性，是软件可维护性的基石。</p>
<h3>2025年的回响：go 语句 即 Goto</h3>
<p>论文提出了一个让人振聋发聩的观点：<strong>Go 语言中的 go 语句，在某种意义上，就是并发领域的 goto。</strong></p>
<p>当你执行 go func() 时，你实际上是启动了一个新的执行流，它跳出了当前的词法作用域（Lexical Scope）。</p>
<ul>
<li>它什么时候开始？不确定。</li>
<li>它什么时候结束？不知道。</li>
<li>它如果 Panic 了会怎样？可能会炸掉整个程序。</li>
<li>父函数返回了，它还在运行吗？很有可能。</li>
</ul>
<p>这种“射后不理（Fire-and-Forget）”的模式，破坏了代码的封装性。就像当年的 goto 打破了控制流的结构一样，不受约束的 go 语句打破了并发流的结构。</p>
<p>结构化并发的目标，就是要把这些“野生”的 Goroutine 重新关进“代码块”的笼子里，让并发程序的生命周期像同步程序一样清晰、可预测。</p>
<h2>打破幻象——Go 并发的三个误区</h2>
<p>在引入解决方案之前，论文首先抨击了 Go 社区中常见的三个关于并发的迷思。这些误区往往是导致系统不稳定的根源。</p>
<h3>误区 1：“Goroutine 极度廉价，所以可以随便开”</h3>
<p>是的，Goroutine 的初始栈只有 2KB，但这只是“内存”成本。从“生命周期”的角度看，一个泄露的 Goroutine 是极其昂贵的。</p>
<p>如果不加控制地启动 Goroutine 而不确保其退出，这些“孤儿”协程可能会：</p>
<ul>
<li>持有数据库连接或文件句柄不释放。</li>
<li>阻塞在某个永远不会发送数据的 Channel 上。</li>
<li>阻止垃圾回收器（GC）回收其引用的对象。</li>
</ul>
<p>在长期运行的服务中，这种微小的泄漏会像滚雪球一样，最终导致服务 OOM（内存溢出）。</p>
<h3>误区 2：“Channel 解决了所有同步问题”</h3>
<p>Rob Pike 的名言“不要通过共享内存来通信，要通过通信来共享内存”被许多人奉为圭臬。然而，Channel 并不是银弹。</p>
<p>Channel 实际上引入了复杂的状态机问题：</p>
<ul>
<li>向已关闭的 Channel 发送数据会 Panic。</li>
<li>从 nil Channel 读取会永久阻塞。</li>
<li>无缓冲 Channel 容易导致死锁。</li>
<li>过多的 Channel 会导致逻辑碎片化，增加认知负担。</li>
</ul>
<p>论文强调，Channel 是一种传输机制，而不是一种架构保障。没有设计良好的生命周期管理，Channel 只会让 Bug 变得更难调试。</p>
<h3>误区 3：“Go 的并发代码很容易测试”</h3>
<p>Go 提供了 go test -race，但这远远不够。并发 Bug 往往是<strong>非确定性</strong>的（Heisenbugs），在本地开发环境（低负载、少核）下可能永远不会出现，一上生产环境（高负载、多核）就崩溃。</p>
<p>如果代码缺乏结构化，测试将变得极其困难。你无法确定在断言（Assert）的那一刻，后台的 Goroutine 是否已经完成了数据的写入。结构化并发通过明确的“等待”机制，能让并发测试变得像同步测试一样稳定。</p>
<h2>核心法则——构建坚固的并发大厦</h2>
<p>既然 Go 语言层面（目前）没有强制的结构化并发语法（不同于 Java Project Loom 的 StructuredTaskScope 或 Python Trio 的 Nursery），我们需要依靠工程纪律和设计模式来实现它。论文详细阐述了四大核心法则。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/structured-concurrency-in-go-research-oriented-perspective-2.png" alt="" /></p>
<h3>法则一：Scope 闭环原则 —— 在谁的 Scope 启动，就在谁的 Scope 等待</h3>
<p><strong>定义</strong>：<strong>任何启动 Goroutine 的函数，必须负责等待它们结束。</strong></p>
<p>这是结构化并发的第一天条。绝不允许 Goroutine 的生命周期“逃逸”出启动它的函数。这保证了当函数返回时，它所衍生的所有并发工作都已完结，资源已释放。</p>
<p><strong>❌ 反模式：泄露的抽象</strong></p>
<pre><code class="go">// 这是一个危险的模式：函数返回了，但后台任务还在跑
// 调用者无法知道任务何时完成，也无法处理 panic
func FireAndForget() {
    go func() {
        // 执行一些可能会阻塞很久的任务
        // 这里发生的一切，父函数都无法控制
    }()
}
</code></pre>
<p><strong>✅ 正模式：Wait 优于 Sleep</strong></p>
<p>论文强烈建议使用 sync.WaitGroup 或 errgroup 来显式地界定生命周期边界。</p>
<pre><code class="go">func ProcessStructured(items []Data) {
    var wg sync.WaitGroup

    for _, item := range items {
        wg.Add(1)
        // 使用闭包捕获变量时需注意
        go func(val Data) {
            defer wg.Done()
            process(val)
        }(item)
    }

    // 关键点：在函数返回前，必须收敛所有并发流
    // 这形成了一个清晰的“并发块”
    wg.Wait()
}
</code></pre>
<p>通过这种方式，ProcessStructured 函数的行为变成了“同步”的黑盒。调用者不需要知道它内部是否使用了并发，只需要知道“当函数返回时，所有工作都已完成”。</p>
<h3>法则二：同步外观原则 —— API 应当表现为“同步”</h3>
<p><strong>定义</strong>：<strong>即使函数内部使用了高并发，对外暴露的 API 签名应当是同步阻塞的。</strong></p>
<p>这是一个看似反直觉的建议。既然我们写的是并发程序，为什么 API 要设计成同步的？</p>
<p>论文指出，异步 API（如返回一个 &lt;-chan Result 或 Future）具有“传染性”。一旦你的函数返回了一个 Future，调用者就必须处理这个 Future 的等待逻辑，这会层层向上传递，导致整个调用链都充满了并发管理的细节。</p>
<p><strong>经典案例：http.ListenAndServe</strong></p>
<p>Go 标准库的 http.ListenAndServe(“:8080&#8243;, nil) 是结构化并发 API 设计的典范。</p>
<ul>
<li>内部：它是一个极其复杂的并发系统，为每个进来的 TCP 连接启动一个新的 Goroutine。</li>
<li>外部：它是一个简单的阻塞函数。</li>
</ul>
<pre><code class="go">// 调用者代码
err := http.ListenAndServe(":8080", nil)

// 当这行代码返回时，我们确切地知道：
// 1. 服务已经停止了。
// 2. 或者发生了错误（如端口冲突）。
</code></pre>
<p>如果 ListenAndServe 被设计成异步返回（即在后台启动服务后立即返回），那么调用者将面临巨大的困扰：我该如何知道服务启动成功了？如果启动失败，错误去哪里了？主进程该何时退出？</p>
<p>除非是专门的任务调度器，否则业务逻辑函数的 API 应该看起来是同步阻塞的。让调用者去决定是否使用 go 关键字来调用它。</p>
<h3>法则三：所有权原则 —— 在哪写入，就在哪关闭</h3>
<p><strong>定义</strong>：<strong>只有负责向 Channel 写入数据的 Goroutine，才有资格关闭该 Channel。</strong></p>
<p>Channel 的关闭操作是 Go 并发中最容易导致 Panic 的环节（向已关闭的 Channel 发送数据）。论文强调，结构化并发可以极大地简化 Channel 的管理。</p>
<p>原则非常简单：<strong>谁生产，谁负责清理。</strong> 接收者（Consumer）永远不应该关闭 Channel，因为通过关闭 Channel 来通知生产者“我读完了”是一种错误的设计（应该使用 Context 来取消）。</p>
<p>结合法则一，如果生产者 Goroutine 的生命周期是受控的，那么 Channel 的生命周期自然也是受控的。</p>
<pre><code class="go">func Producer() &lt;-chan int {
    ch := make(chan int)

    // 启动生产者协程
    go func() {
        // defer close 确保无论正常退出还是 panic，channel 都会关闭
        // 避免接收者永久阻塞
        defer close(ch) 

        for i := 0; i &lt; 10; i++ {
            ch &lt;- i
        }
    }()

    return ch
}
</code></pre>
<h3>法则四：物理封装原则 —— 数据与锁不分家</h3>
<p><strong>定义</strong>：<strong>将共享的可变数据（Mutable State）与保护它的同步原语（Mutex）封装在同一个结构体中。</strong></p>
<p>在共享内存的并发模型中，最大的噩梦是“锁与数据分离”。例如，你定义了一个全局变量 var Cache map[string]int，然后又定义了一个全局锁 var Mu sync.Mutex。随着代码量的增加，开发者很容易忘记在访问 Cache 时加锁，或者错误地使用了其他的锁。</p>
<p>论文建议采用一种“物理强绑定”的策略：</p>
<pre><code class="go">type SafeCounter struct {
    // 1. 将锁作为结构体的第一个字段
    mu sync.Mutex

    // 2. 受保护的数据应当是私有的（小写）
    // 强制外部必须通过方法来访问
    values map[string]int
}

// 3. 只有通过这个方法才能访问数据
func (c *SafeCounter) Inc(key string) {
    c.mu.Lock()
    // 4. 利用 defer 确保锁的释放与函数作用域绑定
    defer c.mu.Unlock()

    c.values[key]++
}
</code></pre>
<p>这种模式被称为 Monitor Pattern（监视器模式）。它通过封装强制实施了并发安全，将“会不会加锁”的问题变成了“能不能调用方法”的问题，后者由编译器保证，前者只能靠人品。</p>
<h2>进阶——超越标准库的尝试</h2>
<p>虽然标准库提供了 sync.WaitGroup 和 context，但要完美实现结构化并发，样板代码依然繁多。论文提到了社区中一些优秀的尝试，其中最值得关注的是 <strong>Sourcegraph 开源的 conc 库</strong>。</p>
<p>conc 库试图解决标准库 WaitGroup 的两个痛点：</p>
<ol>
<li>Panic 逃逸：在标准 go func 中，如果子协程 panic，整个程序会直接崩溃（Crash），父协程无法 recover。这对于高可用服务是致命的。</li>
<li>Error 传播：WaitGroup 不支持错误返回，需要开发者自己维护一个 err 变量或使用 errgroup。</li>
</ol>
<p>conc 提供了增强版的 WaitGroup：</p>
<pre><code class="go">import "github.com/sourcegraph/conc"

func main() {
    var wg conc.WaitGroup

    wg.Go(func() {
        // 如果这里 panic 了
        panic("something went wrong")
    })

    // Wait() 会自动捕获子协程的 panic
    // 并将其重新抛出或作为错误返回（取决于具体 API）
    // 从而避免进程直接崩溃
    wg.Wait()
}
</code></pre>
<p>这种工具库的出现，标志着 Go 社区正在从“手动管理并发”向“自动化管理并发”演进，这正是结构化并发理念的工程化落地。</p>
<h2>小结：从“能用”到“可控”</h2>
<p>Go 语言通过 go 关键字将并发编程的门槛降到了历史最低，赢得了云计算时代的入场券。但在构建大规模、高可靠的系统时，我们不能止步于“能用”。</p>
<p>这篇学术论文为我们提供了一个冷静的视角：<strong>并发不是目的，只是手段。</strong> 失控的并发是灾难，只有受控的并发才是生产力。</p>
<p>结构化并发不是一种束缚，而是一种保护。它要求我们在写下每一个 go func 的时候，都要问自己三个问题：</p>
<ol>
<li>它什么时候结束？</li>
<li>谁负责等待它结束？</li>
<li>如果它出错了，谁来处理？</li>
</ol>
<p>只有当这三个问题都有明确答案时，我们才能说，我们真正掌握了 Go 的并发艺术。</p>
<h2>参考资料</h2>
<ul>
<li>Kliukovkin, G. (2025). <a href="https://www.scirj.org/papers-0325/scirj-P03251013.pdf">Structured Concurrency in Go: A Research-Oriented Perspective*. Scientific Research Journal</a></li>
<li>Dijkstra, E. W. (1968). <em>Go To Statement Considered Harmful</em>.</li>
<li>Sourcegraph conc Library: https://github.com/sourcegraph/conc</li>
</ul>
<hr />
<p><strong>你更倾向于哪一派？</strong></p>
<p>有人认为 Go 的自由是生产力之源，有人认为约束才是工程的救赎。在你的项目中，你是否也曾因为“射后不理”的 goroutine 踩过坑？你认为 Go 官方是否应该在语言层面引入类似 Java 或 Python 的结构化并发原生支持？</p>
<p>欢迎在评论区分享你的看法或“血泪史”！</p>
<p>想深入掌握 Go 并发调度的底层原理？点击查看我的微专栏《<a href="https://mp.weixin.qq.com/mp/appmsgalbum?__biz=MzIyNzM0MDk0Mg==&amp;action=getalbum&amp;album_id=4036682086282166273#wechat_redirect">Go 并发调度艺术</a>》。</p>
<hr />
<p>还在为“复制粘贴喂AI”而烦恼？我的新专栏 <strong>《<a href="http://gk.link/a/12EPd">AI原生开发工作流实战</a>》</strong> 将带你：</p>
<ul>
<li>告别低效，重塑开发范式</li>
<li>驾驭AI Agent(Claude Code)，实现工作流自动化</li>
<li>从“AI使用者”进化为规范驱动开发的“工作流指挥家”</li>
</ul>
<p>扫描下方二维码，开启你的AI原生开发之旅。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/ai-native-dev-workflow-qr.png" alt="" /></p>
<hr />
<p>你的Go技能，是否也卡在了“熟练”到“精通”的瓶颈期？</p>
<ul>
<li>想写出更地道、更健壮的Go代码，却总在细节上踩坑？</li>
<li>渴望提升软件设计能力，驾驭复杂Go项目却缺乏章法？</li>
<li>想打造生产级的Go服务，却在工程化实践中屡屡受挫？</li>
</ul>
<p>继《<a href="http://gk.link/a/10AVZ">Go语言第一课</a>》后，我的《<a href="http://gk.link/a/12yGY">Go语言进阶课</a>》终于在极客时间与大家见面了！</p>
<p>我的全新极客时间专栏 《<a href="http://gk.link/a/12yGY">Tony Bai·Go语言进阶课</a>》就是为这样的你量身打造！30+讲硬核内容，带你夯实语法认知，提升设计思维，锻造工程实践能力，更有实战项目串讲。</p>
<p>目标只有一个：助你完成从“Go熟练工”到“Go专家”的蜕变！ 现在就加入，让你的Go技能再上一个新台阶！</p>
<p><img src="https://tonybai.com/wp-content/uploads/course-card/iamtonybai-banner-2.gif" alt="" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2026, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2026/04/16/structured-concurrency-in-go-research-oriented-perspective/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>别搞“小而美”了！Rust 开发者请愿：求求标准库学学 Go 吧</title>
		<link>https://tonybai.com/2026/04/09/stop-being-small-and-beautiful-rust-petition-to-learn-from-go/</link>
		<comments>https://tonybai.com/2026/04/09/stop-being-small-and-beautiful-rust-petition-to-learn-from-go/#comments</comments>
		<pubDate>Thu, 09 Apr 2026 00:20:15 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[BackwardCompatibility]]></category>
		<category><![CDATA[BatteriesIncluded]]></category>
		<category><![CDATA[cargo]]></category>
		<category><![CDATA[CodeAudit]]></category>
		<category><![CDATA[crates]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[GoLanguage]]></category>
		<category><![CDATA[Go语言]]></category>
		<category><![CDATA[Maintainability]]></category>
		<category><![CDATA[Modularity]]></category>
		<category><![CDATA[npm]]></category>
		<category><![CDATA[OpenSourceCommunity]]></category>
		<category><![CDATA[PackageManager]]></category>
		<category><![CDATA[Rust]]></category>
		<category><![CDATA[safety]]></category>
		<category><![CDATA[standardlibrary]]></category>
		<category><![CDATA[SupplyChainSecurity]]></category>
		<category><![CDATA[SwordOfDamocles]]></category>
		<category><![CDATA[ThirdPartyDependencies]]></category>
		<category><![CDATA[ZerocostAbstraction]]></category>
		<category><![CDATA[代码审计]]></category>
		<category><![CDATA[供应链安全]]></category>
		<category><![CDATA[可维护性]]></category>
		<category><![CDATA[向后兼容性]]></category>
		<category><![CDATA[安全性]]></category>
		<category><![CDATA[开源社区]]></category>
		<category><![CDATA[标准库]]></category>
		<category><![CDATA[模块化]]></category>
		<category><![CDATA[电池内置]]></category>
		<category><![CDATA[第三方依赖]]></category>
		<category><![CDATA[软件包管理]]></category>
		<category><![CDATA[达摩克利斯之剑]]></category>
		<category><![CDATA[零成本抽象]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=6161</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2026/04/09/stop-being-small-and-beautiful-rust-petition-to-learn-from-go 大家好，我是Tony Bai。 如果你之前经常听 Go 社区最火的播客 GoTime(很遗憾，该播客2024年末因平台原因停播了)，你一定会熟悉每期节目最后的那个经典环节——“Unpopular Opinion”（非主流观点）。在这个环节，嘉宾们会分享一些看似离经叛道、却往往一针见血的“暴论”。 但就在前几天，这个流行于 Go 社区的“梗”，却被隔壁的 Rust 社区“偷”了过去，并掀起了一场史诗级的“路线之争”。 一位 Rust 开发者，在 r/rust 论坛上发了一篇帖子，标题就叫：《Unpopular opinion: Rust should have a larger standard library》（非主流观点：Rust 应该有一个更大的标准库）。 他在这篇帖子中发出了灵魂拷问： “我不想为了写一个程序，被迫去拉几百个我根本没时间、也没人去审计的第三方依赖包。看看隔壁的 Go 是怎么做标准库的，你几乎可以不依赖任何三方包就构建出复杂的系统！” 这篇帖子瞬间引爆了 Rust 社区。短短一天，帖子收获了近 700 的高赞和近 300 条激烈辩论。 这看起来像是一场简单的“库多库少”之争，但本质上，它背后是 Rust 这门以“零成本抽象、极致安全”著称的语言，在面对日益猖獗的供应链安全威胁和 Go 语言“开箱即用”的降维打击时，所爆发的一场深刻的身份危机与哲学反思。 “小而美”的代价：悬在每个 Rust 项目头顶的达摩克利斯之剑 长期以来，Rust 社区一直为自己“小核心、强生态”的模式感到自豪。Rust 的标准库（std）极其精简，只提供最基础、最核心的功能。任何稍微高级一点的需求，比如随机数生成、异步运行时、序列化，官方都鼓励你去 crates.io 上找社区“钦定”的“明星库”（Blessed Crates）。 这套模式在早期极大地促进了生态的繁荣。但随着 [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2026/stop-being-small-and-beautiful-rust-petition-to-learn-from-go-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2026/04/09/stop-being-small-and-beautiful-rust-petition-to-learn-from-go">本文永久链接</a> &#8211; https://tonybai.com/2026/04/09/stop-being-small-and-beautiful-rust-petition-to-learn-from-go</p>
<p>大家好，我是Tony Bai。</p>
<p>如果你之前经常听 Go 社区最火的播客 <a href="https://changelog.com/gotime/">GoTime</a>(很遗憾，该播客2024年末因平台原因停播了)，你一定会熟悉每期节目最后的那个经典环节——“Unpopular Opinion”（非主流观点）。在这个环节，嘉宾们会分享一些看似离经叛道、却往往一针见血的“暴论”。</p>
<p>但就在前几天，这个流行于 Go 社区的“梗”，却被隔壁的 Rust 社区“偷”了过去，并掀起了一场史诗级的“路线之争”。</p>
<p>一位 Rust 开发者，在 r/rust 论坛上发了一篇帖子，标题就叫：《<a href="https://www.reddit.com/r/rust/comments/1seu7p2/unpopular_opinion_rust_should_have_a_larger/">Unpopular opinion: Rust should have a larger standard library</a>》（非主流观点：Rust 应该有一个更大的标准库）。</p>
<p>他在这篇帖子中发出了灵魂拷问：</p>
<blockquote>
<p>“我不想为了写一个程序，被迫去拉几百个我根本没时间、也没人去审计的第三方依赖包。看看隔壁的 Go 是怎么做标准库的，你几乎可以不依赖任何三方包就构建出复杂的系统！”</p>
</blockquote>
<p>这篇帖子瞬间引爆了 Rust 社区。短短一天，帖子收获了近 700 的高赞和近 300 条激烈辩论。</p>
<p>这看起来像是一场简单的“库多库少”之争，但本质上，它背后是 Rust 这门以“零成本抽象、极致安全”著称的语言，在面对日益猖獗的<a href="https://tonybai.com/2026/02/25/govulncheck-high-signal-to-noise-ratio-security-workflow">供应链安全威胁</a>和 Go 语言“开箱即用”的降维打击时，所爆发的一场深刻的身份危机与哲学反思。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/agentic-api-in-action-qr.png" alt="" /></p>
<h2>“小而美”的代价：悬在每个 Rust 项目头顶的达摩克利斯之剑</h2>
<p>长期以来，Rust 社区一直为自己“小核心、强生态”的模式感到自豪。Rust 的标准库（std）极其精简，只提供最基础、最核心的功能。任何稍微高级一点的需求，比如随机数生成、异步运行时、序列化，官方都鼓励你去 crates.io 上找社区“钦定”的“明星库”（Blessed Crates）。</p>
<p>这套模式在早期极大地促进了生态的繁荣。但随着 npm left-pad 事件和各种开源投毒攻击的阴影笼罩全球，这套模式的代价也变得越来越难以承受。</p>
<p>原帖作者一针见血地指出了所有人的噩梦：</p>
<blockquote>
<p>“是的，你可以采取各种缓解措施。但等你发现某个藏在你依赖树第三层的、不起眼的包被植入了恶意软件时，你的服务器密钥可能早就被偷光了！”</p>
</blockquote>
<p>评论区里的一位开发者用一句话概括了所有人的痛点：</p>
<blockquote>
<p>“我完全同意。有时候 std 里就是缺了那么一点至关重要的东西。我能理解这背后的原因，但为了生成一个随机数就要去装一个第三方包，这实在有点小题大做了。”</p>
</blockquote>
<p>这正是 Rust 开发者面临的尴尬：当你只是想生成一个 UUID，或者发起一个 HTTP 请求时，你被迫要对 rand、reqwest、tokio 这些由社区个人或小团体维护的库，付出与 Rust 官方核心团队同等级别的“信任”。</p>
<p>而这种信任，正在变得越来越昂贵和危险。</p>
<h2>隔壁的诱惑：Go 语言的“大一统”模式</h2>
<p>在这场大讨论中，一个名字被反复提及，它就是 Go 语言。</p>
<p>Go 从诞生之初，就选择了与 Rust 截然相反的“自带电池（Batteries Included）”哲学。</p>
<ul>
<li>你想做 Web 开发？net/http 原生支持，性能强大到可以直接裸奔在生产环境。</li>
<li>你想做 JSON/XML 解析？encoding/json(以及实验性的encoding/json/v2)、encoding/xml 是标配。</li>
<li>你想做并发？goroutine 和 channel 是语言级原生特性。</li>
<li>你想生成随机数？math/rand、crypto/rand 随便用。</li>
</ul>
<p>评论区里，一位 Rust 开发者的对比极其扎心：</p>
<blockquote>
<p>“把恶意代码偷偷塞进一个（流行的）Crate 的第四层依赖里，比把它塞进 Rust 的 std 里要容易得多。”</p>
</blockquote>
<p>Go 语言通过一个庞大、稳定、由官方核心团队直接维护的标准库，为开发者提供了一道坚固的“安全护城河”。你可以在不引入任何一个第三方依赖的情况下，构建出一个功能极其完备、性能强大的高并发网络服务。</p>
<p>这种“开箱即用”的安全感和便利性，对于那些深受<a href="https://tonybai.com/2025/05/21/go-crypto-audit">供应链安全审计</a>折磨的企业开发者来说，是致命的诱惑。</p>
<h2>社区的挣扎：当“保守”成为“瓶颈”</h2>
<p>面对社区的“呐喊”，Rust 核心团队的成员和社区大佬们也纷纷下场，给出了极其理性和深刻的解释。他们的回复，揭示了 Rust 在标准库扩张上，面临的“三重枷锁”。</p>
<p><strong>枷锁一：向后兼容性的“诅咒”</strong></p>
<p>一位核心成员引用了 Python 社区的一句名言：</p>
<blockquote>
<p><strong>“标准库，是模块最终的坟场（The standard library is where modules go to die）。”</strong></p>
</blockquote>
<p>一旦一个 API 进入了 std，它就必须背上永不破坏向后兼容的沉重承诺。哪怕 10 年后发现这个设计有缺陷，也只能眼睁睁地看着它腐烂，或者推出一个 urllib2、urllib3 这样极其丑陋的补丁。</p>
<p>Rust 团队宁愿让这些库在社区里自由进化、大浪淘沙，等到它们的设计真正成熟、稳定到可以“永恒”时，再考虑纳入 std。比如 once_cell 和最新的 rand（目前在 nightly 版本中）。</p>
<p><strong>枷锁二：无休止的“维护地狱”</strong></p>
<p>另外一名核心成员指出，将一个库纳入 std，意味着它的维护成本将全部转移到人数本就捉襟见肘的官方维护者身上。而在社区，每个 Crate 都有自己专门的维护者。这是两种完全不同的成本模型。</p>
<p><strong>枷锁三：设计的“过早僵化”</strong></p>
<p>最典型的例子就是异步。原帖作者提议：“Rust 能不能偷一下 Zig 的 IO 思想，这样我们就不需要在 Tokio 和 non-Tokio 生态之间分裂了？”</p>
<p>一位社区大佬立刻反驳：Zig 没有 Rust 的 Send/Sync 标记，两者的异步模型有本质区别。Rust 的异步生态之所以看起来“分裂”，恰恰是语言给了开发者在不同场景下做最优选择的自由。如果过早地在 std 里统一一个官方运行时，反而会扼杀创新。</p>
<h2>破局之路：从“大一统”到“邦联制”</h2>
<p>在这场激烈的辩论中，一些极具建设性的“折中方案”也开始浮现。这或许预示着 Rust 未来的演进方向。</p>
<p><strong>方案一：官方背书的“准标准库（Semi-official）”</strong></p>
<p>一位开发者提出，Rust 项目组可以借鉴 C++ Boost 库的模式，官方接管 serde、rand、tokio 这些“钦定”的明星库，将它们纳入一个统一的 extd (extended) 命名空间下。</p>
<pre><code class="rust">use extd::regex::Regex;
use extd::rand;
</code></pre>
<p>这并不会增加 std 的体积，但给了这些库一个“官方认证”的金字招牌，极大地解决了开发者的信任和审计问题。</p>
<p><strong>方案二：引入“孵化期（Incubation Phase）”</strong></p>
<p>一位开发者建议，应该有一个更明确的孵化流程，让那些有潜力进入 std 的库，先在一个类似 Go golang.org/x 的“实验场”里进行检验，而不是直接从某个个人开发者仓库里一步登天。</p>
<p><strong>方案三：强化 Cargo 的安全审计能力</strong></p>
<p>一些核心成员则认为，问题的根源不在于 std 的大小，而在于 crates.io 的分发机制不够安全。与其“因噎废食”地把所有东西都塞进 std，不如去建立更强大的包安全审计机制，比如：</p>
<ul>
<li><strong>发布隔离期</strong>：新发布的包必须经过 72 小时自动化扫描才能被下载。</li>
<li><strong>签名与信任链</strong>：通过 cargo 增强包签名和审计者签名，让企业可以选择只使用“可信审计者”批准的依赖列表。</li>
</ul>
<h2>小结：一场关于“灵魂”的拷问</h2>
<p>这场由“非主流观点(Unpopular Opinion)”引发的大讨论，表面上是在争论标准库的大小，但其核心，却是一场关于 Rust 与 Go 两种截然不同建国哲学的灵魂拷问。</p>
<ul>
<li><strong>Go 语言</strong>，像一个大一统的、中央集权的帝国。它为你提供了从道路、货币到度量衡的一切基础设施。你享受着极高的安全感和便利性，代价是必须忍受它某些时候的“独裁”与“不灵活”。</li>
<li><strong>Rust 语言</strong>，则更像一个松散的、充满活力的城邦联盟。官方只提供最基础的法律和军队，剩下的一切都交给各个城邦（Crates）自由发展。你拥有无与伦比的自由和选择权，代价是你必须自己承担选择的风险，并时刻提防“外敌入侵”（供应链攻击）。</li>
</ul>
<p>这两种哲学没有绝对的优劣，只有不同场景下的取舍。</p>
<p>但 Rust 社区的这场“请愿”，无疑为我们所有技术人敲响了警钟：<strong>在软件供应链日益脆弱的今天，一个强大、可靠、由顶级专家背书的“官方基础设施”，其价值正在被无限放大。</strong></p>
<p>或许，Rust 的未来，真的需要在“自由”与“安全”之间，找到一个新的平衡点。而隔壁 Go 的作业，他们可能真的需要抄一抄了。</p>
<p>资料链接：https://www.reddit.com/r/rust/comments/1seu7p2/unpopular_opinion_rust_should_have_a_larger/</p>
<hr />
<p><strong>今日互动探讨：</strong></p>
<p>在你的日常开发中，你是更喜欢 Go 这种“自带电池”的大标准库模式，还是 Rust 这种“小核心+强生态”的自由模式？你是否也曾因为“拉了一堆三方库”而感到安全焦虑？</p>
<p>欢迎在评论区分享你的看法!</p>
<hr />
<p>还在为“复制粘贴喂AI”而烦恼？我的新专栏 <strong>《<a href="http://gk.link/a/12EPd">AI原生开发工作流实战</a>》</strong> 将带你：</p>
<ul>
<li>告别低效，重塑开发范式</li>
<li>驾驭AI Agent(Claude Code)，实现工作流自动化</li>
<li>从“AI使用者”进化为规范驱动开发的“工作流指挥家”</li>
</ul>
<p>扫描下方二维码，开启你的AI原生开发之旅。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/ai-native-dev-workflow-qr.png" alt="" /></p>
<hr />
<p>你的Go技能，是否也卡在了“熟练”到“精通”的瓶颈期？</p>
<ul>
<li>想写出更地道、更健壮的Go代码，却总在细节上踩坑？</li>
<li>渴望提升软件设计能力，驾驭复杂Go项目却缺乏章法？</li>
<li>想打造生产级的Go服务，却在工程化实践中屡屡受挫？</li>
</ul>
<p>继《<a href="http://gk.link/a/10AVZ">Go语言第一课</a>》后，我的《<a href="http://gk.link/a/12yGY">Go语言进阶课</a>》终于在极客时间与大家见面了！</p>
<p>我的全新极客时间专栏 《<a href="http://gk.link/a/12yGY">Tony Bai·Go语言进阶课</a>》就是为这样的你量身打造！30+讲硬核内容，带你夯实语法认知，提升设计思维，锻造工程实践能力，更有实战项目串讲。</p>
<p>目标只有一个：助你完成从“Go熟练工”到“Go专家”的蜕变！ 现在就加入，让你的Go技能再上一个新台阶！</p>
<p><img src="https://tonybai.com/wp-content/uploads/course-card/iamtonybai-banner-2.gif" alt="" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2026, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2026/04/09/stop-being-small-and-beautiful-rust-petition-to-learn-from-go/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>倒计时 33 个月？Go 前安全负责人：量子计算机将“摧毁”互联网</title>
		<link>https://tonybai.com/2026/04/08/perspective-on-quantum-computing-timeline/</link>
		<comments>https://tonybai.com/2026/04/08/perspective-on-quantum-computing-timeline/#comments</comments>
		<pubDate>Wed, 08 Apr 2026 00:15:14 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[DigitalSignatures]]></category>
		<category><![CDATA[ECC]]></category>
		<category><![CDATA[FilippoValsorda]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[GoLanguage]]></category>
		<category><![CDATA[Go语言]]></category>
		<category><![CDATA[infrastructure]]></category>
		<category><![CDATA[KeyExchange]]></category>
		<category><![CDATA[kyber]]></category>
		<category><![CDATA[MLDSA]]></category>
		<category><![CDATA[mlkem]]></category>
		<category><![CDATA[PostQuantumCryptography]]></category>
		<category><![CDATA[PQC]]></category>
		<category><![CDATA[QDay]]></category>
		<category><![CDATA[QuantumComputing]]></category>
		<category><![CDATA[RSA]]></category>
		<category><![CDATA[SecurityAudit]]></category>
		<category><![CDATA[ShorAlgorithm]]></category>
		<category><![CDATA[Shor算法]]></category>
		<category><![CDATA[SNDL]]></category>
		<category><![CDATA[StoreNowDecryptLater]]></category>
		<category><![CDATA[TLS]]></category>
		<category><![CDATA[x509]]></category>
		<category><![CDATA[先收集后破解]]></category>
		<category><![CDATA[基础设施]]></category>
		<category><![CDATA[安全审计]]></category>
		<category><![CDATA[密钥交换]]></category>
		<category><![CDATA[抗量子密码学]]></category>
		<category><![CDATA[数字签名]]></category>
		<category><![CDATA[椭圆曲线]]></category>
		<category><![CDATA[量子末日]]></category>
		<category><![CDATA[量子计算机]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=6158</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2026/04/08/perspective-on-quantum-computing-timelines 大家好，我是Tony Bai。 过去三十年，我们一直活在一个笑话里：“能够破解 RSA 加密的量子计算机，永远在十年之后。” 作为一名软件工程师，我曾和你们中的大多数人一样，对所谓的“量子末日（Q-Day）”嗤之以鼻。我们觉得，在有生之年，我们赖以生存的 RSA、ECC 加密体系坚不可摧，那一天遥遥无期。 但就在昨天（2026年4月6日），这个笑话，似乎被终结了。 Go 语言前核心团队安全负责人、Go密码学专家之一 Filippo Valsorda，在他的个人博客上发表了一篇极其沉重的文章。 在文章的开头，他用一种近乎“忏悔”的口吻写道： “在推出抗量子密码学的紧迫性上，我的立场与几个月前相比，已经发生了改变。……是时候公开表明并解释我改变想法的原因了。” 在这篇长文中，Filippo 引用了 Google 和 Oratomic 上周刚刚发表的两篇重磅论文，以及多位顶级物理学家的最新警告，最终得出了一个令整个软件工程界脊背发凉的结论：我们不再拥有十年。具备破解当前所有主流加密算法能力的量子计算机（CRQC），其到来的时间线，已经被一些顶级专家压缩到了一个令人绝望的数字——2029 年。 是的，只剩下 33 个月。 今天，就让我们跟随这位曾经的“官方守护者”的视角，看看这场已经兵临城下的“加密世界末日”，到底是怎么回事，以及我们作为普通的后端开发者，该如何在这场史无前例的迁移中生存下来。 冰山撞来：Google 的论文与被撕碎的幻想 Filippo 指出，在过去的一周里，两篇论文彻底改变了游戏规则。 第一篇，来自 Google。 这篇论文极大地修正了破解 256 位椭圆曲线（如我们每天都在用的 HTTPS 证书、比特币签名 secp256k1）所需的逻辑量子比特（qubits）和门电路数量。结论是：在超导量子比特这种高速架构上，攻击可以在几分钟内完成。 第二篇，来自 Oratomic。 这篇论文更加激进。它指出，如果拥有非局部连接能力（如中性原子方案），破解 256 位椭圆曲线甚至只需要 10,000 个物理量子比特。这种攻击虽然更慢，但哪怕一个月只能破解一个密钥，也足以引发灾难。 那张出现在论文第二页、堪称“末日倒计时”的图表，清晰地展示了攻破 RSA-2048 和 ECC-256 所需的物理量子比特数，正在以肉眼可见的速度急剧下降。 Filippo 坦言：“我不是物理学家，我看不懂论文里所有的物理学原理。但我的工作是风险评估。我知道的是，至少有一部分真正的专家正在告诉我们：硬件在变好，算法在变便宜，纠错要求在降低。一切都在加速。” [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2026/perspective-on-quantum-computing-timeline-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2026/04/08/perspective-on-quantum-computing-timeline">本文永久链接</a> &#8211; https://tonybai.com/2026/04/08/perspective-on-quantum-computing-timelines</p>
<p>大家好，我是Tony Bai。</p>
<p>过去三十年，我们一直活在一个笑话里：<strong>“能够破解 RSA 加密的量子计算机，永远在十年之后。”</strong></p>
<p>作为一名软件工程师，我曾和你们中的大多数人一样，对所谓的“量子末日（Q-Day）”嗤之以鼻。我们觉得，在有生之年，我们赖以生存的 RSA、ECC 加密体系坚不可摧，那一天遥遥无期。</p>
<p><strong>但就在昨天（2026年4月6日），这个笑话，似乎被终结了。</strong></p>
<p>Go 语言前核心团队安全负责人、Go密码学专家之一 <strong>Filippo Valsorda</strong>，在他的个人博客上发表了<a href="https://words.filippo.io/crqc-timeline/">一篇极其沉重的文章</a>。</p>
<p>在文章的开头，他用一种近乎“忏悔”的口吻写道：</p>
<blockquote>
<p>“在推出抗量子密码学的紧迫性上，我的立场与几个月前相比，已经发生了改变。……是时候公开表明并解释我改变想法的原因了。”</p>
</blockquote>
<p>在这篇长文中，Filippo 引用了 Google 和 Oratomic 上周刚刚发表的两篇重磅论文，以及多位顶级物理学家的最新警告，最终得出了一个令整个软件工程界脊背发凉的结论：我们不再拥有十年。具备破解当前所有主流加密算法能力的量子计算机（CRQC），其到来的时间线，已经被一些顶级专家压缩到了一个令人绝望的数字——2029 年。</p>
<p><strong>是的，只剩下 33 个月。</strong></p>
<p>今天，就让我们跟随这位曾经的“官方守护者”的视角，看看这场已经兵临城下的“加密世界末日”，到底是怎么回事，以及我们作为普通的后端开发者，该如何在这场史无前例的迁移中生存下来。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/paid/go-crypto-101-qr.png" alt="" /></p>
<h2>冰山撞来：Google 的论文与被撕碎的幻想</h2>
<p>Filippo 指出，在过去的一周里，两篇论文彻底改变了游戏规则。</p>
<p><strong><a href="https://research.google/blog/safeguarding-cryptocurrency-by-disclosing-quantum-vulnerabilities-responsibly/">第一篇</a>，来自 Google。</strong> 这篇论文极大地修正了破解 256 位椭圆曲线（如我们每天都在用的 HTTPS 证书、比特币签名 secp256k1）所需的逻辑量子比特（qubits）和门电路数量。结论是：<strong>在超导量子比特这种高速架构上，攻击可以在几分钟内完成。</strong></p>
<p><strong><a href="https://arxiv.org/abs/2603.28627">第二篇</a>，来自 Oratomic。</strong> 这篇论文更加激进。它指出，如果拥有非局部连接能力（如中性原子方案），破解 256 位椭圆曲线甚至只需要 <strong>10,000 个物理量子比特</strong>。这种攻击虽然更慢，但哪怕一个月只能破解一个密钥，也足以引发灾难。</p>
<p>那张出现在论文第二页、堪称“末日倒计时”的图表，清晰地展示了攻破 RSA-2048 和 ECC-256 所需的物理量子比特数，正在以肉眼可见的速度急剧下降。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/perspective-on-quantum-computing-timeline-2.png" alt="" /></p>
<p>Filippo 坦言：“我不是物理学家，我看不懂论文里所有的物理学原理。但我的工作是风险评估。我知道的是，至少有一部分真正的专家正在告诉我们：<strong>硬件在变好，算法在变便宜，纠错要求在降低。一切都在加速。</strong>”</p>
<h2>精英的警告：当你还在嘲笑，他们已经开始行动</h2>
<p>更让 Filippo 感到警惕的，不是冷冰冰的论文，而是行业顶尖精英们近乎“反常”的表态。</p>
<ul>
<li>Google 的安全总监 Heather Adkins 和 Sophie Schmieg 公开宣布，他们的<strong>最后期限是 2029 年</strong>。Filippo 强调：“在此之前，从没有人给出过如此激进的时间表。”</li>
<li>著名的量子计算理论家 Scott Aaronson，将当前的状态比作 <strong>1939 年到 1940 年之间</strong>——那段时间，关于核裂变研究的公开发表突然在全球范围内“神秘消失”了。</li>
<li>Scott Aaronson 更是抛出了一个灵魂拷问，戳破了所有人的侥幸心理：<br />
> “一旦你理解了量子容错，再问‘你什么时候能用 Shor 算法分解 35？’，就好像在 1943 年问曼哈顿计划的物理学家‘你什么时候能搞出一次小小的核爆？’一样可笑。”</li>
</ul>
<p>Filippo 写道，如果你还在想“这事儿可能成，也可能不成”，那你已经输了。</p>
<p>现在的赌注不是“你 100% 确定 2030 年会有量子计算机吗？”，而是<strong>“你 100% 确定 2030 年绝对不会有吗？你敢拿你所有用户的身家性命去赌那不到 1% 的可能性吗？”</strong></p>
<h2>SNDL 攻击：你的数据，正在被黑客“先存后破”</h2>
<p>为什么我们必须立刻行动？因为黑客们正在疯狂执行一种极其阴险的战略：<strong>“Store Now, Decrypt Later”（先收集，后破解，SNDL）。</strong></p>
<p>他们把现在通过网络截获的、由 RSA/ECC 加密的、看似安全的核心机密数据（比如你的银行交易、公司的商业合同、国家的敏感情报）全部存储在巨大的硬盘阵列里。</p>
<p>等几年后量子计算机成熟，他们就能在一瞬间，把这些尘封的历史数据全部解开，一览无余。</p>
<p>这意味着，我们今天发送的每一封加密邮件，每一次 HTTPS 访问，都在为未来的某一次“数字考古”提供素材。</p>
<h2>行动指南：我们必须立刻开始“造船”</h2>
<p>面对这场已经兵临城下的风暴，Filippo 作为Go 密码学界的专家，给出了极其具体、甚至有些“痛苦”的行动指南。</p>
<p><strong>1. 密钥交换（Key Exchange）：立即迁移到 ML-KEM</strong></p>
<p>这是抵御 SNDL 攻击的第一道防线。Filippo 强调，任何非抗量子的密钥交换（如经典的 ECDH）都应被视为潜在的“主动破解”行为，并像 OpenSSH 那样向用户发出明确警告。</p>
<p><strong>2. 数字签名（Digital Signatures）：硬着头皮上 ML-DSA，放弃幻想</strong></p>
<p>这是最痛苦的部分。Filippo 不无遗憾地承认，他原本希望我们能有更多时间去设计更优雅的、适应大签名体积的协议。但现在，没时间了。</p>
<p>我们必须接受 <strong>ML-DSA 签名体积巨大</strong>（几千字节，而 ECDSA 只有几十字节）的残酷现实，并开始在为小签名设计的协议（如 X.509 证书）中强行塞入这些“肥胖”的签名。</p>
<p>他甚至激进地提出：<strong>应该彻底放弃“混合签名”（经典+后量子）的过渡方案</strong>，直接一步到位使用纯 ML-DSA-44。因为混合签名带来的复杂性和性能开销，已经超过了它能提供的那点微不足道的“对冲”收益。</p>
<p><strong>3. 对 Go 开发者意味着什么？</strong></p>
<p>Filippo 直言不讳：</p>
<blockquote>
<p>“在我的世界里，我们必须开始思考，<strong>Go 标准库中一半的密码学包突然变得不安全意味着什么</strong>。……这是我们职业生涯中从未遇到过的事情：从 SHA-1 到 SHA-256 的迁移，远没有这次这么具有破坏性。”</p>
</blockquote>
<p>这意味着，我们很快就要在 Go 的 crypto/tls, crypto/x509, x/crypto/ssh 中看到翻天覆地的变化。</p>
<h2>小结： weird, but it is what it is</h2>
<p>在文章的结尾，Filippo 提到，他本周刚刚开始在博洛尼亚大学教授一门密码学博士课程。他告诉学生，RSA、ECDSA 这些我们曾经引以为傲的算法，<strong>现在只能作为“遗留算法（Legacy Algorithms）”来介绍了</strong>。</p>
<p>他写道：<strong>“我知道，这感觉很奇怪。但，现实就是如此（it is what it is）。”</strong></p>
<p>Filippo 的这声叹息，既是对一个技术时代的告别，也是对我们所有软件工程师拉响的高级别警报。</p>
<p>当 Go 语言前核心团队的安全负责人、一个以极度严谨和保守著称的密码学专家，都开始用如此紧迫的口吻催促我们行动时，我们没有理由再把头埋在沙子里，假装危机还很遥远。</p>
<p><strong>那艘名为“量子计算”的巨轮，已经出现在了海平面上。现在不是争论它会不会撞上来的时候，现在是立刻开始造救生艇的时候。</strong></p>
<p>资料链接：</p>
<ul>
<li>https://words.filippo.io/crqc-timeline/</li>
<li>https://research.google/blog/safeguarding-cryptocurrency-by-disclosing-quantum-vulnerabilities-responsibly/</li>
<li>https://arxiv.org/abs/2603.28627</li>
</ul>
<hr />
<p><strong>今日互动探讨：</strong></p>
<p>在你的公司或个人项目中，有哪些核心数据是绝对不能在 5-10 年后被解密的？面对这场迫在眉睫的密码学大迁移，你觉得我们应该从哪个环节开始着手准备？</p>
<p>欢迎在评论区分享你的看法和焦虑！</p>
<hr />
<p>还在为“复制粘贴喂AI”而烦恼？我的新专栏 <strong>《<a href="http://gk.link/a/12EPd">AI原生开发工作流实战</a>》</strong> 将带你：</p>
<ul>
<li>告别低效，重塑开发范式</li>
<li>驾驭AI Agent(Claude Code)，实现工作流自动化</li>
<li>从“AI使用者”进化为规范驱动开发的“工作流指挥家”</li>
</ul>
<p>扫描下方二维码，开启你的AI原生开发之旅。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/ai-native-dev-workflow-qr.png" alt="" /></p>
<hr />
<p>你的Go技能，是否也卡在了“熟练”到“精通”的瓶颈期？</p>
<ul>
<li>想写出更地道、更健壮的Go代码，却总在细节上踩坑？</li>
<li>渴望提升软件设计能力，驾驭复杂Go项目却缺乏章法？</li>
<li>想打造生产级的Go服务，却在工程化实践中屡屡受挫？</li>
</ul>
<p>继《<a href="http://gk.link/a/10AVZ">Go语言第一课</a>》后，我的《<a href="http://gk.link/a/12yGY">Go语言进阶课</a>》终于在极客时间与大家见面了！</p>
<p>我的全新极客时间专栏 《<a href="http://gk.link/a/12yGY">Tony Bai·Go语言进阶课</a>》就是为这样的你量身打造！30+讲硬核内容，带你夯实语法认知，提升设计思维，锻造工程实践能力，更有实战项目串讲。</p>
<p>目标只有一个：助你完成从“Go熟练工”到“Go专家”的蜕变！ 现在就加入，让你的Go技能再上一个新台阶！</p>
<p><img src="https://tonybai.com/wp-content/uploads/course-card/iamtonybai-banner-2.gif" alt="" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2026, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2026/04/08/perspective-on-quantum-computing-timeline/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>AI 编程时代，我挖出了一本 1999 年的“删库跑路”指南</title>
		<link>https://tonybai.com/2026/04/06/how-to-write-unmaintainable-code/</link>
		<comments>https://tonybai.com/2026/04/06/how-to-write-unmaintainable-code/#comments</comments>
		<pubDate>Mon, 06 Apr 2026 00:27:24 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[AIProgramming]]></category>
		<category><![CDATA[AI编程]]></category>
		<category><![CDATA[ArchitectureDesign]]></category>
		<category><![CDATA[ClaudeCode]]></category>
		<category><![CDATA[CodeAudit]]></category>
		<category><![CDATA[CodeReuse]]></category>
		<category><![CDATA[Codereview]]></category>
		<category><![CDATA[CodeStandards]]></category>
		<category><![CDATA[Codex]]></category>
		<category><![CDATA[DefensiveProgramming]]></category>
		<category><![CDATA[EmptyInterface]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[gofmt]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[GoLanguage]]></category>
		<category><![CDATA[Go语言]]></category>
		<category><![CDATA[InterfaceDesign]]></category>
		<category><![CDATA[LegacyCode]]></category>
		<category><![CDATA[ReverseEngineering]]></category>
		<category><![CDATA[SoftwareEngineering]]></category>
		<category><![CDATA[TechnicalDebt]]></category>
		<category><![CDATA[TypeSafety]]></category>
		<category><![CDATA[UnmaintainableCode]]></category>
		<category><![CDATA[不可维护代码]]></category>
		<category><![CDATA[代码复用]]></category>
		<category><![CDATA[代码审查]]></category>
		<category><![CDATA[代码审计]]></category>
		<category><![CDATA[代码规范]]></category>
		<category><![CDATA[反向编程]]></category>
		<category><![CDATA[屎山]]></category>
		<category><![CDATA[技术债务]]></category>
		<category><![CDATA[接口设计]]></category>
		<category><![CDATA[架构设计]]></category>
		<category><![CDATA[空接口]]></category>
		<category><![CDATA[类型安全]]></category>
		<category><![CDATA[软件工程]]></category>
		<category><![CDATA[防御性编程]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=6150</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2026/04/06/how-to-write-unmaintainable-code 大家好，我是Tony Bai。 在这个由 Claude、GPT、Gemini等大模型定义的 2026 年，我们似乎已经习惯了 AI 那种近乎“洁癖”的编码风格：优雅的接口设计、滴水不漏的错误处理、以及永远对齐的工整格式。 AI 正在用它那冰冷的、毫无感情的逻辑，将软件工程推向一个前所未有的标准化时代。 但就在前几天，我在一个尘封的互联网角落里，挖出了一本写于 1999 年的上古奇文——《How To Write Unmaintainable Code》（如何编写不可维护的代码）。 这篇文章的作者 Roedy Green，怀着一种极其黑色幽默的极客精神，手把手教导当年的 Java 程序员们，如何写出能让“接盘侠”当场崩溃、从而保证自己“终身就业”的屎山代码。 当我用 AI 时代的眼光，去重新审视这本 27 年前的“反向圣经”时，我感到既荒谬又亲切。它就像一面镜子，照出了在没有 gofmt、没有 AI、没有 Claude Code 的“古法编程”时代，我们曾如何野蛮生长，以及 Go 语言在设计之初，就已经用多么前瞻性的眼光，封印了那些曾经肆虐一时的“魔鬼”。 今天，就让我们开启一场技术考古之旅，用现代 Go 语言，来“复刻”一下这些差点失传的“防御性”编程之术。 底层哲学：把你的同事想象成一个“管中窥豹”的傻子 Roedy Green 在开篇就点明了核心：维护者看代码，就像通过一个卫生纸筒的中心在看世界，视野极其狭窄。 你的任务，就是让他永远无法拼凑出完整的画面。 古法复刻：让同事“提刀来见”的 骚操作 命名之罪 用 l 冒充 1，用 O 冒充 0：利用字体的模糊性，制造视觉混乱。 [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2026/how-to-write-unmaintainable-code-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2026/04/06/how-to-write-unmaintainable-code">本文永久链接</a> &#8211; https://tonybai.com/2026/04/06/how-to-write-unmaintainable-code</p>
<p>大家好，我是Tony Bai。</p>
<p>在这个由 Claude、GPT、Gemini等大模型定义的 2026 年，我们似乎已经习惯了 AI 那种近乎“洁癖”的编码风格：优雅的接口设计、滴水不漏的错误处理、以及永远对齐的工整格式。</p>
<p>AI 正在用它那冰冷的、毫无感情的逻辑，将软件工程推向一个前所未有的标准化时代。</p>
<p>但就在前几天，我在一个尘封的互联网角落里，挖出了一本写于 1999 年的上古奇文——<strong>《<a href="https://www.doc.ic.ac.uk/%7Esusan/475/unmain.html">How To Write Unmaintainable Code</a>》（如何编写不可维护的代码）</strong>。</p>
<p>这篇文章的作者 Roedy Green，怀着一种极其黑色幽默的极客精神，手把手教导当年的 Java 程序员们，如何写出能让“接盘侠”当场崩溃、从而保证自己“终身就业”的屎山代码。</p>
<p>当我用 AI 时代的眼光，去重新审视这本 27 年前的“反向圣经”时，我感到既荒谬又亲切。它就像一面镜子，照出了在没有 gofmt、没有 AI、没有 Claude Code 的“古法编程”时代，我们曾如何野蛮生长，以及 Go 语言在设计之初，就已经用多么前瞻性的眼光，封印了那些曾经肆虐一时的“魔鬼”。</p>
<p>今天，就让我们开启一场技术考古之旅，用现代 Go 语言，来“复刻”一下这些差点失传的“防御性”编程之术。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/agentic-software-engineering-qr.png" alt="" /></p>
<h2>底层哲学：把你的同事想象成一个“管中窥豹”的傻子</h2>
<p>Roedy Green 在开篇就点明了核心：维护者看代码，就像通过一个卫生纸筒的中心在看世界，视野极其狭窄。</p>
<p>你的任务，就是让他永远无法拼凑出完整的画面。</p>
<h2>古法复刻：让同事“提刀来见”的 骚操作</h2>
<h3>命名之罪</h3>
<ol>
<li><strong>用 l 冒充 1，用 O 冒充 0</strong>：利用字体的模糊性，制造视觉混乱。<br />
<code>go<br />
// 古法复刻<br />
var l int64 = 11 // 这是 11 还是 1l？<br />
var speed int = O1 // 这是 O1 还是 01？</code></li>
<li><strong>创造极其相似的变量名</strong>：仅通过大小写或一个不显眼的字母进行区分。<br />
<code>go<br />
// 古法复刻<br />
var swimmer, swimner string // 99% 的 Code Review 都会看走眼<br />
var hashTable, HashTable *map[string]int</code></li>
<li><strong>滥用缩写，且不保持一致</strong>：在不同的地方使用同一个单词的不同缩写，让全局搜索彻底失效。<br />
<code>go<br />
// 古法复刻<br />
func GetUserAuth(...) {}<br />
func GetUsrAuthorization(...) {}<br />
var athnClient *Client</code></li>
<li><strong>使用与业务逻辑无关的变量名</strong>：比如，在屏幕上显示“Postal Code”(邮政编码)，但在代码里把它命名为 zip。</li>
<li><strong>在函数名中使用极其抽象的词汇</strong>：比如 HandleIt, ProcessData, DoStuff。让调用者永远猜不透这个函数到底干了什么。</li>
</ol>
<h3>注释之罪</h3>
<ol>
<li><strong>在注释里撒谎</strong>：最简单的一招，改了代码，但不更新注释。</li>
<li><strong>写废话注释</strong>：为每一行显而易见的代码配上同样显而易见的注释，用大量的噪音淹没真正有价值的信息。<br />
<code>go<br />
// 古法复刻<br />
i++ // i plus 1</code></li>
<li><strong>永远不要注释一个变量</strong>：它的单位、取值范围、边界条件，全让维护者自己去猜。</li>
</ol>
<h3>结构之罪</h3>
<ol>
<li><strong>极限压行</strong>：在一行里塞进尽可能多的逻辑，挑战显示器的宽度极限。</li>
<li><strong>深度嵌套</strong>：以能嵌套 10 层以上的 if-else 为荣，坚决不使用 early return或happy path。</li>
<li>
<p><strong>滥用全局变量</strong>：永远不要使用局部变量，把一切都提升为包级变量，让并发的 Goroutine 们去为了争夺它而自相残杀。</p>
<pre><code class="go">// 古法复刻
var tempResult string // 提升为包级变量

func HandleRequestA() {
    tempResult = "result_from_A"
    // ...
}

func HandleRequestB() {
    tempResult = "result_from_B"
    // ...
}
// 当这两个函数并发执行时，一场血案即将发生。
</code></pre>
</li>
<li><strong>复制-粘贴-修改</strong>：当有相似功能时，坚决不抽象，直接复制粘贴。在一个代码库里埋下 5 份只有细微差别的一模一样的代码，等待日后引爆。</li>
<li><strong>一个函数只做一件事？不，一个函数必须干三件事！</strong> 让一个名为 IsValid() 的函数，在校验的同时，偷偷地把数据写入数据库。</li>
</ol>
<h3>Go 语言的反击</h3>
<p>当然原文中，Roedy Green的“骚操作”不止这些。</p>
<p>但其中的一些“防御”手段对今天的Go语言来说，并不生效。</p>
<p>你会发现 Go 语言在设计之初，就已经对这些“手段”进行了“免疫”，比如：</p>
<ul>
<li><strong>关于缩进与格式</strong>：Roedy Green 痛斥当年程序员通过“故意错位”的缩进来制造 if-else 匹配的视觉陷阱。
<ul>
<li><strong>Go 的反击</strong>：对不起，我们有 gofmt。在 Go 的世界里，关于代码格式的“圣战”在第一天就结束了。无论你的代码写得多乱，Ctrl+S 的瞬间，一切都会变得整齐划一。</li>
</ul>
</li>
<li><strong>关于花括号</strong>：原文建议省略非必须的 {}。
<ul>
<li><strong>Go 的反击</strong>：Go 语言强制要求 if, for 后面必须跟 {}，从语法层面彻底消灭了这种的“防御”写法。</li>
</ul>
</li>
</ul>
<h2>现代化的“魔鬼”：用 Go 复刻那些更高级的骚操作</h2>
<p>当然，Go 也不是万能的。很多源自 Java/C++ 时代的“高级骚操作”，在 Go 里依然可以“继续存在”。</p>
<ol>
<li><strong>伪装成构造函数</strong>：<br />
<code>go<br />
// 古法复刻：这个函数名和类型名完全一样，但它不是构造函数！<br />
type User struct{ name string }<br />
func User(name string) { /* ... do something evil */ }</code></li>
<li><strong>滥用 interface{}</strong>：把所有的函数参数都定义成 interface{}，然后在函数内部进行大量的类型断言（Type Assertion）。这能完美地把编译时错误，转化为运行时 panic。</li>
<li><strong>颠倒参数顺序</strong>：定义一个 DrawRectangle(height, width int) 函数。在几个版本之后，神不知鬼不觉地把它改成 DrawRectangle(width, height int)，但函数名保持不变。</li>
<li><strong>魔数（Magic Numbers）</strong>：在代码里硬编码大量的数字 100，但就是不定义一个常量。更高级的玩法是，偶尔用 99 代替 100-1，用 50*2 代替 100。<br />
<code>go<br />
// 古法复刻<br />
if len(users) &gt; 99 { // 这里是 &gt; 99<br />
    // ...<br />
}<br />
for i := 0; i &lt; 100; i++ { // 这里是 &lt; 100<br />
    // ...<br />
}</code></li>
<li><strong>迷惑性的函数重载（Go 版本）</strong>：Go 没有函数重载，但我们可以用“接口”来模拟。<br />
<code>go<br />
// 古法复刻<br />
func Process(input interface{}) {<br />
    switch v := input.(type) {<br />
    case string: // 处理字符串<br />
    case int:    // 处理整数，但逻辑和 string 完全不同<br />
    // ...<br />
    }<br />
}</code><br />
当你的同事传入一个他以为是数字的字符串 “123&#8243; 时，他将收获一个意想不到的结果。</li>
</ol>
<h2>小结：在 AI 时代，我们为什么要回顾“屎山”？</h2>
<p>重温这本 27 年前的“反向圣经”，在今天这个 AI 编程时代，显得格外有意义。</p>
<p>AI 的出现，正在把“编写可维护代码”的门槛，拉到前所未有的低点。一个初级程序员，在 AI 的辅助下，也能写出格式工整、变量命名规范的代码。</p>
<p><strong>但这是否意味着“屎山”将成为历史？</strong></p>
<p>恰恰相反。AI 在解放我们生产力的同时，也正在<strong>“批量化”和“隐蔽化”</strong>地制造着“新时代的屎山”。AI 可能会生成一段逻辑上看似完美，但在高并发下会引发严重数据竞争的代码；它也可能会为了实现一个简单功能，引入一个庞大且带有安全漏洞的第三方库。</p>
<p>这本古老的指南提醒我们：<strong>技术的进步可以消灭“语法层面”的丑陋，但永远无法替代人类工程师在“架构层面”的审美与抉择。</strong></p>
<p>在 AI 时代，我们不再需要像 Roedy Green 那样，靠着“加密代码”来保住饭碗。但我们比以往任何时候，都更需要理解那些“不可维护代码”背后的设计缺陷，从而在 Code Review 中，扮演好 AI 的“最终质检员”角色。</p>
<p>代码的整洁与混乱，终究是一场关于“责任心”的博弈。无论时代如何变迁，这，或许是软件工程永恒的真理。</p>
<p>当然，如果你真的想了解古法编程时代的更多“骚操作”，可以看看Roedy Green的原文：https://www.doc.ic.ac.uk/%7Esusan/475/unmain.html</p>
<hr />
<p><strong>今日互动探讨：</strong></p>
<p>在你见过的 Go 项目中，遇到过哪些让你拍案叫绝、或者让你想“提刀来见”的“屎山代码”骚操作？</p>
<p>欢迎在评论区分享你的“开眼”经历！</p>
<hr />
<p>还在为“复制粘贴喂AI”而烦恼？我的新专栏 <strong>《<a href="http://gk.link/a/12EPd">AI原生开发工作流实战</a>》</strong> 将带你：</p>
<ul>
<li>告别低效，重塑开发范式</li>
<li>驾驭AI Agent(Claude Code)，实现工作流自动化</li>
<li>从“AI使用者”进化为规范驱动开发的“工作流指挥家”</li>
</ul>
<p>扫描下方二维码，开启你的AI原生开发之旅。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/ai-native-dev-workflow-qr.png" alt="" /></p>
<hr />
<p>你的Go技能，是否也卡在了“熟练”到“精通”的瓶颈期？</p>
<ul>
<li>想写出更地道、更健壮的Go代码，却总在细节上踩坑？</li>
<li>渴望提升软件设计能力，驾驭复杂Go项目却缺乏章法？</li>
<li>想打造生产级的Go服务，却在工程化实践中屡屡受挫？</li>
</ul>
<p>继《<a href="http://gk.link/a/10AVZ">Go语言第一课</a>》后，我的《<a href="http://gk.link/a/12yGY">Go语言进阶课</a>》终于在极客时间与大家见面了！</p>
<p>我的全新极客时间专栏 《<a href="http://gk.link/a/12yGY">Tony Bai·Go语言进阶课</a>》就是为这样的你量身打造！30+讲硬核内容，带你夯实语法认知，提升设计思维，锻造工程实践能力，更有实战项目串讲。</p>
<p>目标只有一个：助你完成从“Go熟练工”到“Go专家”的蜕变！ 现在就加入，让你的Go技能再上一个新台阶！</p>
<p><img src="https://tonybai.com/wp-content/uploads/course-card/iamtonybai-banner-2.gif" alt="" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2026, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2026/04/06/how-to-write-unmaintainable-code/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>一天重写 JSONata，我用 400 美元干掉了公司 50 万美元的 K8s 集群</title>
		<link>https://tonybai.com/2026/04/01/rewrote-jsonata-in-golang-with-ai/</link>
		<comments>https://tonybai.com/2026/04/01/rewrote-jsonata-in-golang-with-ai/#comments</comments>
		<pubDate>Wed, 01 Apr 2026 00:29:37 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[AIDriven]]></category>
		<category><![CDATA[AI驱动]]></category>
		<category><![CDATA[ArtificialIntelligence]]></category>
		<category><![CDATA[AutomationTools]]></category>
		<category><![CDATA[CodeGeneration]]></category>
		<category><![CDATA[CostOptimization]]></category>
		<category><![CDATA[CrossLanguageRPC]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[GoLanguage]]></category>
		<category><![CDATA[Go语言]]></category>
		<category><![CDATA[HighPerformance]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[JSONata]]></category>
		<category><![CDATA[k8s]]></category>
		<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[latency]]></category>
		<category><![CDATA[MemoryManagement]]></category>
		<category><![CDATA[Microservices]]></category>
		<category><![CDATA[nodejs]]></category>
		<category><![CDATA[PerformanceBoost]]></category>
		<category><![CDATA[Refactoring]]></category>
		<category><![CDATA[Rewrite]]></category>
		<category><![CDATA[TechnicalDebt]]></category>
		<category><![CDATA[TestDrivenDevelopment]]></category>
		<category><![CDATA[ZeroHeapAllocation]]></category>
		<category><![CDATA[人工智能]]></category>
		<category><![CDATA[代码生成]]></category>
		<category><![CDATA[代码重构]]></category>
		<category><![CDATA[内存管理]]></category>
		<category><![CDATA[延迟]]></category>
		<category><![CDATA[微服务]]></category>
		<category><![CDATA[性能提升]]></category>
		<category><![CDATA[成本优化]]></category>
		<category><![CDATA[技术债]]></category>
		<category><![CDATA[测试驱动开发]]></category>
		<category><![CDATA[自动化工具]]></category>
		<category><![CDATA[跨语言调用]]></category>
		<category><![CDATA[重写]]></category>
		<category><![CDATA[零内存分配]]></category>
		<category><![CDATA[零堆内存分配]]></category>
		<category><![CDATA[高性能]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=6127</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2026/04/01/rewrote-jsonata-in-golang-with-ai 大家好，我是Tony Bai。 过去的几年，我们见证了 AI 编程工具从“玩具”到“神器”的进化。无数开发者都在分享自己效率翻倍的喜悦。 你有没有想过，用 AI 来完成一次“外科手术式”的精准重构，一天之内，就能帮你把公司每年烧掉的 50 万美元（约 360 万人民币）的服务器成本，直接砍到零？ 这听起来像天方夜谭，但它真实地发生了。 就在前几天，以色列安全公司 Reco 的工程师 Nir Barak 发表了一篇极其硬核的博客。他详细复盘了自己是如何在一天之内，花费了仅仅 400 美元的 Token 费用，利用 AI 将一个用 JavaScript 编写的核心组件 JSONata，完美地重写为了纯 Go 版本，最终为公司节省了每年 50 万美元的开销，并带来了 1000 倍的性能提升。 这不仅仅是一个“AI 真牛逼”的简单故事。它背后揭示的，是一套足以改变我们未来架构选型和技术债偿还方式的“AI 驱动重构（AI-Driven Refactoring）”实用方法。 跨语言 RPC，微服务架构中最昂贵的“性能税” 要理解这次重构的意义有多么重大，首先得看看 Nir Barak 的团队曾经陷入了多深的泥潭。 他们的核心业务是一个用 Go 编写的高性能数据管道，每天处理数十亿的事件。但其中有一个环节，需要用到一个名为 JSONata 的查询语言（你可以把它想象成带 Lambda 函数的 jq）来执行动态策略。 [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2026/rewrote-jsonata-in-golang-with-ai-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2026/04/01/rewrote-jsonata-in-golang-with-ai">本文永久链接</a> &#8211; https://tonybai.com/2026/04/01/rewrote-jsonata-in-golang-with-ai</p>
<p>大家好，我是Tony Bai。</p>
<p>过去的几年，我们见证了 AI 编程工具从“玩具”到“神器”的进化。无数开发者都在分享自己效率翻倍的喜悦。</p>
<p>你有没有想过，用 AI 来完成一次“外科手术式”的精准重构，一天之内，就能帮你把公司每年烧掉的 50 万美元（约 360 万人民币）的服务器成本，直接砍到零？</p>
<p>这听起来像天方夜谭，但它真实地发生了。</p>
<p>就在前几天，以色列安全公司 Reco 的工程师 Nir Barak 发表了<a href="https://www.reco.ai/blog/we-rewrote-jsonata-with-ai">一篇极其硬核的博客</a>。他详细复盘了自己是如何在<strong>一天之内，花费了仅仅 400 美元的 Token 费用</strong>，利用 AI 将一个用 JavaScript 编写的核心组件 JSONata，完美地重写为了纯 Go 版本，最终为公司节省了每年 50 万美元的开销，并带来了 1000 倍的性能提升。</p>
<p>这不仅仅是一个“AI 真牛逼”的简单故事。它背后揭示的，是一套足以改变我们未来架构选型和技术债偿还方式的<strong>“AI 驱动重构（AI-Driven Refactoring）”</strong>实用方法。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/agentic-software-engineering-qr.png" alt="" /></p>
<h2>跨语言 RPC，微服务架构中最昂贵的“性能税”</h2>
<p>要理解这次重构的意义有多么重大，首先得看看 Nir Barak 的团队曾经陷入了多深的泥潭。</p>
<p>他们的核心业务是一个用 Go 编写的高性能数据管道，每天处理数十亿的事件。但其中有一个环节，需要用到一个名为 JSONata 的查询语言（你可以把它想象成带 Lambda 函数的 jq）来执行动态策略。</p>
<p>尴尬的是，JSONata 的官方实现是 JavaScript 写的。</p>
<p>这就导致了一个极其痛苦的架构：他们的主业务 Go 服务，为了执行这些规则，不得不去远程调用（RPC）一个专门部署在 Kubernetes 上的庞大的 Node.js 服务集群。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/rewrote-jsonata-in-golang-with-ai-2.png" alt="" /></p>
<p>这个“小小的”跨语言调用，给他们带来了三大噩梦：</p>
<ol>
<li><strong>恐怖的成本</strong>：为了扛住流量，这个 jsonata-js 集群常年需要维持 <strong>300 多个 Pod 副本</strong>，光是这部分，每年就要烧掉 <strong>30 万美元</strong>的计算资源。</li>
<li><strong>惊人的延迟</strong>：一次最简单的字段查找，比如 email = “admin@co.com”，在 Node.js 内部执行可能只需要几纳秒。但算上序列化、跨进程网络往返的开销，一次 RPC 调用在啥也没干之前，<strong>150 微秒</strong>的延迟就先进来了。对于一个每天处理几十亿事件的系统来说，这简直是灾难。</li>
<li><strong>意想不到的运维黑洞</strong>：随着业务增长，Pod 数量一度多到<strong>耗尽了 Kubernetes 集群的 IP 地址分配上限！</strong></li>
</ol>
<p>Nir Barak 的团队当然也尝试过各种小修小补：优化表达式、加缓存、甚至用 CGO 把 V8 引擎直接嵌进 Go 里……但这些都只是“头痛医头”，无法根治“跨语言”这颗毒瘤。</p>
<h2>Cloudflare 的“抄作业”哲学</h2>
<p>转机发生在前几周。Nir Barak 看到了 Cloudflare 那篇刷爆全网的文章《<a href="https://blog.cloudflare.com/vinext/">我们如何用 AI 在一周内重构 Next.js</a>》。</p>
<p>Cloudflare 的做法极其“暴力”且有效：他们没有让 AI 去创造新东西，而是把 Next.js 现成的spec，以及包含几千个 case 的官方测试套件（Test Suite）直接扔给大模型，然后对 AI 下达了一个简单粗暴的指令：</p>
<p><strong>“我不管你怎么实现，给我写一个能在 Vite 上跑通所有这些测试的 API 就行！”</strong></p>
<p>Nir Barak 看到这里，瞬间被点醒了：<strong>“我们面临的问题一模一样！我们也有 jsonata-js 官方那套包含 1778 个测试用例的完整套件啊！”</strong></p>
<p>与其让 AI 去搞创新，不如把它变成一个任劳任怨、24 小时待命的“代码翻译工”！</p>
<p>于是，他花了一个周末，用 AI 制定了一个极其清晰的“三步走”作战计划：</p>
<ol>
<li>第一步（人类智慧）：用 Go 语言把 jsonata-js 的测试套件先“翻译”过来。</li>
<li>第二步（AI 体力）：把 JSONata 2.x 的官方文档和规范全部喂给 AI。</li>
<li>第三步（测试驱动）：对 AI 下达指令：“开始写 Go 代码，目标是跑通第一步的所有测试用例。”</li>
</ol>
<p>第二天，他按下了“开始键”。</p>
<h2>7 小时，400 美元，13000 行 Go 代码</h2>
<p>接下来的故事，充满了令人肾上腺素飙升的极客快感。</p>
<p>Nir Barak 坐在电脑前，看着 AI Agent 像一台失控的缝纫机一样，疯狂地生成 Go 代码、运行测试、读取报错、然后自我修正。</p>
<p>整个过程被划分成了几个“波次（Waves）”：先实现核心解析器，再实现内置函数，最后处理各种边缘 case。</p>
<p>在 AI 与测试用例的左右互搏之下，仅仅 <strong>7 个小时</strong> 后，奇迹发生了：</p>
<p>一个包含 13,000 多行纯 Go 代码的、名为 gnata 的全新 JSONata 实现诞生了。它完美通过了官方所有的 1778 个测试用例。</p>
<p>而这整个过程的成本呢？</p>
<p><strong>400 美元的 Token 费用。</strong></p>
<p>Nir Barak 在博客中晒出了一张截图，数据显示，在重构 gnata 的那一天，AI 生成的代码占比高达 <strong>91.7%</strong>！</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/rewrote-jsonata-in-golang-with-ai-3.png" alt="" /></p>
<p>当他把这个 PR 提交到公司内部时，立刻有人质疑 ROI（投资回报率）。而他的回答简单粗暴：</p>
<p><strong>“上个月，jsonata-js 集群的成本是 2.5 万美元。现在，是 0。”</strong></p>
<h2>百倍性能与意外之喜：“手术刀式”重构的深远影响</h2>
<p>成本降为零已经足够震撼，但性能上的收益更是堪称“恐怖”。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/rewrote-jsonata-in-golang-with-ai-4.png" alt="" /></p>
<p>这还只是开始。由于 gnata 是纯 Go 实现，Nir Barak 团队得以进行更深度的“魔改”：他们设计了一套<strong>两层评估架构</strong>。对于简单的字段查找，gnata 直接在原始的 JSON 字节流上操作，实现了 <strong>零堆内存分配（Zero Heap Allocations）</strong>！只有遇到复杂表达式时，才会启动完整的解析器。</p>
<p>在接下来的两周内，他们乘胜追击，用 gnata 的批量处理能力，替换掉了主数据管道中另一个极其臃肿、靠启动上万个 Goroutine 来并发处理规则的旧引擎。 结果：又省下了每年 20 万美元。</p>
<p>短短两周，两次“外科手术式”的重构，总共为公司节省了每年 50 万美元的开销。</p>
<p>最让人意想不到的是，这次重构还带来了组织层面的“意外之喜”：</p>
<p>gnata 是公司内部第一个完全由 AI Agent 大规模参与生成的 PR。在 Code Review 的过程中，团队成员被迫去学习如何分辨“AI 真正发现的并发 Bug”和“AI 瞎操心的代码格式问题”。这次经历，为他们后续制定全公司的 AI Code Review 规范积累了宝贵的实战经验。</p>
<h2>小结：我们不再只是“氛围感编码”</h2>
<p>在文章的结尾，Nir Barak 提到了 AI 大神 Andrej Karpathy 最近的观点，大意是：</p>
<blockquote>
<p>“编程正在变得面目全非。在底层，深厚的技术专长正成为比以往任何时候都更强大的‘乘数效应放大器’。”</p>
</blockquote>
<p>Nir Barak 感慨道，直到最近，他自己都对那种完全由 AI Agent 生成代码的“氛围编码（Vibe coding）”持怀疑态度。但 2026 年 2 月，成为了一个连他这样固执的开发者都无法忽视的<strong>“拐点”</strong>。</p>
<p>gnata 的诞生，标志着我们不再只是用 AI 去写一些无关紧要的玩具项目。<strong>在拥有明确测试用例和边界规范的前提下，AI 已经具备了对生产环境核心组件进行“手术刀式重构”的惊人能力。</strong></p>
<p>你准备好拿起这把名为“AI”的手术刀，去切掉你系统里那些最昂贵、最臃肿的“技术肿瘤”了吗？</p>
<p>资料链接：https://www.reco.ai/blog/we-rewrote-jsonata-with-ai</p>
<hr />
<p><strong>今日互动探讨：</strong></p>
<p>在你的公司里，是否存在类似的“异构技术栈”调用导致的性能瓶颈或成本黑洞？你有没有想过，可以用 AI + 测试用例的方式，对某个核心组件进行“代码翻译”式的重构？</p>
<p>欢迎在评论区分享你的架构痛点与大胆构想！</p>
<hr />
<p>还在为“复制粘贴喂AI”而烦恼？我的新专栏 <strong>《<a href="http://gk.link/a/12EPd">AI原生开发工作流实战</a>》</strong> 将带你：</p>
<ul>
<li>告别低效，重塑开发范式</li>
<li>驾驭AI Agent(Claude Code)，实现工作流自动化</li>
<li>从“AI使用者”进化为规范驱动开发的“工作流指挥家”</li>
</ul>
<p>扫描下方二维码，开启你的AI原生开发之旅。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/ai-native-dev-workflow-qr.png" alt="" /></p>
<hr />
<p>你的Go技能，是否也卡在了“熟练”到“精通”的瓶颈期？</p>
<ul>
<li>想写出更地道、更健壮的Go代码，却总在细节上踩坑？</li>
<li>渴望提升软件设计能力，驾驭复杂Go项目却缺乏章法？</li>
<li>想打造生产级的Go服务，却在工程化实践中屡屡受挫？</li>
</ul>
<p>继《<a href="http://gk.link/a/10AVZ">Go语言第一课</a>》后，我的《<a href="http://gk.link/a/12yGY">Go语言进阶课</a>》终于在极客时间与大家见面了！</p>
<p>我的全新极客时间专栏 《<a href="http://gk.link/a/12yGY">Tony Bai·Go语言进阶课</a>》就是为这样的你量身打造！30+讲硬核内容，带你夯实语法认知，提升设计思维，锻造工程实践能力，更有实战项目串讲。</p>
<p>目标只有一个：助你完成从“Go熟练工”到“Go专家”的蜕变！ 现在就加入，让你的Go技能再上一个新台阶！</p>
<p><img src="https://tonybai.com/wp-content/uploads/course-card/iamtonybai-banner-2.gif" alt="" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2026, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2026/04/01/rewrote-jsonata-in-golang-with-ai/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>当 Go 还在追求极简时，C++ 26 却又加了四大“史诗级”新特性</title>
		<link>https://tonybai.com/2026/03/31/go-minimalism-vs-cpp26-epic-new-features/</link>
		<comments>https://tonybai.com/2026/03/31/go-minimalism-vs-cpp26-epic-new-features/#comments</comments>
		<pubDate>Mon, 30 Mar 2026 23:26:51 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[AsynchronousModel]]></category>
		<category><![CDATA[C++26]]></category>
		<category><![CDATA[comptime]]></category>
		<category><![CDATA[Concurrency]]></category>
		<category><![CDATA[Contracts]]></category>
		<category><![CDATA[generics]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[GoLanguage]]></category>
		<category><![CDATA[Go语言]]></category>
		<category><![CDATA[HerbSutter]]></category>
		<category><![CDATA[HighPerformance]]></category>
		<category><![CDATA[MemorySafety]]></category>
		<category><![CDATA[metaprogramming]]></category>
		<category><![CDATA[Reflection]]></category>
		<category><![CDATA[Rust]]></category>
		<category><![CDATA[SenderReceiver]]></category>
		<category><![CDATA[standardlibrary]]></category>
		<category><![CDATA[SystemProgramming]]></category>
		<category><![CDATA[Templates]]></category>
		<category><![CDATA[UndefinedBehavior]]></category>
		<category><![CDATA[ZerocostAbstraction]]></category>
		<category><![CDATA[元编程]]></category>
		<category><![CDATA[内存安全]]></category>
		<category><![CDATA[反射]]></category>
		<category><![CDATA[契约编程]]></category>
		<category><![CDATA[并发]]></category>
		<category><![CDATA[异步模型]]></category>
		<category><![CDATA[未定义行为]]></category>
		<category><![CDATA[标准库]]></category>
		<category><![CDATA[模板]]></category>
		<category><![CDATA[泛型]]></category>
		<category><![CDATA[系统级编程]]></category>
		<category><![CDATA[编译期计算]]></category>
		<category><![CDATA[零成本抽象]]></category>
		<category><![CDATA[高性能]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=6123</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2026/03/31/go-minimalism-vs-cpp26-epic-new-features 大家好，我是Tony Bai。 在这个 Go、Zig 等“小而美”新语言颇受青睐的时代，如果你去技术社区里问一句：“C++ 这门语言怎么样？” 你大概率会得到一堆充满戏谑的回答：“太复杂了，别学”、“从入门到放弃”、“面试造火箭，工作拧螺丝”。 C++，这门诞生于上世纪 80 年代的编程语言，似乎早已被贴上了“老旧、臃肿、极其反人类”的标签。在很多新生代开发者眼里，它就像一头步履蹒跚的史前巨兽，理应被时代所淘汰。 但就在前天（2026年3月29日），这头“史前巨兽”不仅没有倒下，反而亮出了它那足以撕裂天空的獠牙。 C++ 标准委员会主席、C++ 界的“教父级”人物 Herb Sutter 亲自在博客上宣布：C++26 标准的技术工作，已正式完成！ Herb Sutter 还用极其兴奋的口吻将其定义为“自 C++11 以来最具冲击力的一次发布”。而这次更新的核心，是四个被他称为“Fab Four”（神奇四侠）的史诗级新特性。 当我耐着性子看完全部内容后，我脑子里只剩下四个字：叹为观止。 当 Go 语言的开发者还在为“是否要给语言增加一个三元表达式”，或泛型方法而激烈辩论时，C++ 却反其道而行之，给自己又加装了四门“宇宙级”的重型武器。这到底是 C++ 吹响的绝地反击号角，还是压垮骆驼的最后一根稻草？ 今天，我们就来硬核扒开 C++26 这四大“金刚”，看看它们到底有多强，以及它们将如何影响将来程序员对编程语言的选择。 第一门重炮：反射（Reflection）——“代码生成代码”的终极魔法 Herb Sutter 将反射放在了四大特性之首，并称之为“自模板（Templates）发明以来 C++ 最重要的升级”。 什么是C++ 的反射？简单来说，就是让代码在编译期拥有了“自我审视”和“自我创造”的能力。 在 C++26 之前，如果你想实现一个通用的 JSON 序列/反序列化库，你必须写大量重复的模板代码，或者用各种丑陋的宏来“欺骗”编译器。 但在 C++26 中，你可以像这样写出充满“神性”的代码（代码示意）： 这段代码，在编译的时候就能根据编译时的输入(test.json)自动分析JSON构造，并生成编译时用于计算的一个新类型。这在 Go [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2026/go-minimalism-vs-cpp26-epic-new-features-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2026/03/31/go-minimalism-vs-cpp26-epic-new-features">本文永久链接</a> &#8211; https://tonybai.com/2026/03/31/go-minimalism-vs-cpp26-epic-new-features</p>
<p>大家好，我是Tony Bai。</p>
<p>在这个 Go、Zig 等“小而美”新语言颇受青睐的时代，如果你去技术社区里问一句：“C++ 这门语言怎么样？”</p>
<p>你大概率会得到一堆充满戏谑的回答：“太复杂了，别学”、“从入门到放弃”、“面试造火箭，工作拧螺丝”。</p>
<p>C++，这门诞生于上世纪 80 年代的编程语言，似乎早已被贴上了“老旧、臃肿、极其反人类”的标签。在很多新生代开发者眼里，它就像一头步履蹒跚的史前巨兽，理应被时代所淘汰。</p>
<p><strong>但就在前天（2026年3月29日），这头“史前巨兽”不仅没有倒下，反而亮出了它那足以撕裂天空的獠牙。</strong></p>
<p>C++ 标准委员会主席、C++ 界的“教父级”人物 <strong>Herb Sutter</strong> 亲自在博客上宣布：<a href="https://herbsutter.com/2026/03/29/c26-is-done-trip-report-march-2026-iso-c-standards-meeting-london-croydon-uk/">C++26 标准的技术工作，已正式完成！</a></p>
<p>Herb Sutter 还用极其兴奋的口吻将其定义为<strong>“自 C++11 以来最具冲击力的一次发布”</strong>。而这次更新的核心，是四个被他称为“Fab Four”（神奇四侠）的史诗级新特性。</p>
<p>当我耐着性子看完全部内容后，我脑子里只剩下四个字：<strong>叹为观止。</strong></p>
<p>当 Go 语言的开发者还在为“是否要给语言增加一个三元表达式”，或<a href="https://tonybai.com/2026/01/24/go-generics-finally-supports-generic-methods">泛型方法</a>而激烈辩论时，C++ 却反其道而行之，给自己又加装了四门“宇宙级”的重型武器。这到底是 C++ 吹响的绝地反击号角，还是压垮骆驼的最后一根稻草？</p>
<p>今天，我们就来硬核扒开 C++26 这四大“金刚”，看看它们到底有多强，以及它们将如何影响将来程序员对编程语言的选择。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/agentic-software-engineering-qr.png" alt="" /></p>
<h2>第一门重炮：反射（Reflection）——“代码生成代码”的终极魔法</h2>
<p>Herb Sutter 将<strong>反射</strong>放在了四大特性之首，并称之为“自模板（Templates）发明以来 C++ 最重要的升级”。</p>
<p>什么是C++ 的反射？简单来说，<strong>就是让代码在编译期拥有了“自我审视”和“自我创造”的能力。</strong></p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/go-minimalism-vs-cpp26-epic-new-features-2.png" alt="" /></p>
<p>在 C++26 之前，如果你想实现一个通用的 JSON 序列/反序列化库，你必须写大量重复的模板代码，或者用各种丑陋的宏来“欺骗”编译器。</p>
<p>但在 C++26 中，你可以像这样写出充满“神性”的代码（代码示意）：</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/go-minimalism-vs-cpp26-epic-new-features-3.png" alt="" /></p>
<p>这段代码，在编译的时候就能根据编译时的输入(test.json)自动分析JSON构造，并生成编译时用于计算的一个新类型。<strong>这在 Go 语言里，需要借助 reflect 包在运行时（Runtime）以牺牲性能为代价才能做到。而 C++，直接在静态编译期（Compile-time）零成本搞定了！</strong></p>
<p>Herb Sutter 将其形容为“C++ 的十年火箭引擎”。这意味着，未来 C++ 社区将涌现出无数极其强大、但又极其复杂的元编程（Metaprogramming）库。C++ 的学习曲线，将再次被拉到一个新的高度。</p>
<h2>第二道防线：内存安全（Memory Safety）——“只需重编，安全自来”</h2>
<p>如果说反射让 C++ 的上限变得更加遥不可及，那么内存安全的提升，则是 C++ 在向 Go 和 Rust 的核心优势区发起的正面冲锋。</p>
<p>C++ 常年被诟病的核心痛点是什么？<strong>内存不安全</strong>。悬垂指针、未初始化变量读取（导致<a href="https://tonybai.com/2026/03/16/go-language-eliminated-undefined-behavior-truth-investigation">未定义行为</a>）……这些噩梦困扰了 C++ 程序员几十年。</p>
<p>C++26 给出了一个极其诱人的承诺：<strong>你的老代码一行都不用改，只要用 C++26 模式重新编译，就能自动获得大幅度的安全提升！</strong></p>
<p>这主要来源于两个方面的改进：</p>
<ol>
<li><strong>消灭未初始化变量的 UB</strong>：在 C++26 中，读取未初始化局部变量不再是“未定义行为（Undefined Behavior）”。这意味着困扰无数新手的、极其诡异的程序崩溃，将成为历史。</li>
<li><strong>“加固”的标准库</strong>：Google 和 Apple 已经将它们内部经过“加固（Hardened）”的标准库实现贡献给了 C++26。这意味着，当你使用 std::vector, std::string 等容器时，大量的边界检查会自动开启。</li>
</ol>
<p>Herb Sutter 引用了 Google 的内部数据：</p>
<blockquote>
<p>“仅在 Google，这项技术就已经修复了超过 1000 个 Bug，预计每年可以预防 1000 到 2000 个新 Bug 的产生，并将整个生产环境的段错误（Segfault）率降低了 30%。”</p>
</blockquote>
<p>这简直是在对 Go 说：<strong>“你用 GC 换来的那点可怜的安全性，我 C++ 现在也能做到了，而且依然是零成本的！”</strong></p>
<h2>第三把利剑：契约（Contracts）——代码里的“法律条文”</h2>
<p>如果你写过 Go，你一定对满屏的 if param == nil { return errors.New(&#8230;) } 感到厌烦。这种防御性编程，虽然有效，但极其啰嗦。</p>
<p>C++26 正式引入了语言级的<a href="https://tonybai.com/2025/12/13/from-eiffel-contract-to-go-interface">契约编程</a>。</p>
<p>你可以像签合同一样，为你的函数制定严格的法律条文：</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/go-minimalism-vs-cpp26-epic-new-features-4.png" alt="" /></p>
<p>这些 pre 和 post 是编译器和运行时可以理解并强制执行的“法律”。如果调用者违反了前置条件，程序可以在开发阶段就立刻崩溃并给出明确的报错，而不是等到数据被污染后才在某个奇怪的地方爆炸。</p>
<p>虽然 Go 社区也在讨论类似的泛型断言，但 C++26 已经先行一步，将其做成了语言标准。</p>
<h2>第四个引擎：std::execution——C++ 的“亲儿子”协程模型</h2>
<p>在 C++20 中，虽然引入了 co_await 协程，但它只是一个语法糖，并没有提供一个统一的调度框架。</p>
<p>C++26 终于补上了这块短板，正式推出了 <strong>std::execution</strong>，也被称为 <strong>Sender/Receiver 模型</strong>。</p>
<p>这是一个极其强大、统一的异步模型框架。它让你能以一种声明式的方式，去描述、组合和调度复杂的并发任务流。</p>
<p>下面是一段使用std::execution的代码示例：</p>
<pre><code>// This is an example of a custom algorithm for starting work
// without allocations. This algorithm is also available in
// &lt;exec/start_now.hpp&gt;. (Users that don't write custom sender
// algorithms will not need to use receivers or call connect
// or start.)
template &lt;stdexec::sender_in&lt;stdexec::empty_env&gt; Sender&gt;
struct start_now {
  start_now(Sender sndr)
    : _op(stdexec::connect(std::move(sndr), _sink_rcvr())) {
    stdexec::start(_op);
  }
private:
  // start_now is implemented in terms of this custom receiver,
  // which is used to discard Sender's results.
  struct _sink_rcvr {
    using receiver_concept = stdexec::receiver_t;
    void set_value(auto&amp;&amp;...) noexcept {}
    void set_error(auto&amp;&amp;) noexcept {}
    void set_stopped() noexcept {}
  };
  stdexec::connect_result_t&lt;Sender, _sink_rcvr&gt; _op;
};

int main() {
  // A run loop is a fifo queue of work and a loop to execute the
  // work. It needs to be driven by calling its .run() member fn.
  stdexec::run_loop ctx;
  auto event_loop = ctx.get_scheduler();

  // Create two tasks that cooperatively multitask.
  auto task1 = stdexec::just()
             | stdexec::then([]{ std::puts("hello from task 1! suspending..."); })
             | stdexec::continue_on(event_loop) // suspend
             | exec::repeat_n(5)
             | stdexec::then([]{ std::puts("task 1 is done!"); });

  auto task2 = stdexec::just()
             | stdexec::then([]{ std::puts("hello from task 2! suspending..."); })
             | stdexec::continue_on(event_loop) // suspend
             | exec::repeat_n(8)
             | stdexec::then([]{ std::puts("task 2 is done!"); });

  // Start both tasks. This enqueues them for execution on the run loop.
  auto op1 = start_now(stdexec::start_on(event_loop, std::move(task1)));
  auto op2 = start_now(stdexec::start_on(event_loop, std::move(task2)));

  ctx.finish(); // tell the run loop to stop when the queue is empty
  ctx.run();    // tell the run loop to start executing work in the queue
}
</code></pre>
<p>这可以被看作是 C++ 对 Go 的 Goroutine + Channel 模型，以及 Rust 的 async/await + tokio 模型的终极回应。</p>
<p>它让 C++ 开发者第一次拥有了一套语言原生的、能够轻松编写“无数据竞争（Data-race-free by construction）”并发程序的“亲儿子”工具。</p>
<h2>小结：一场没有退路的豪赌</h2>
<p>反射、安全、契约、并发。C++26 的这四大金刚，每一个都足以在其他语言中引发一场大地震。</p>
<p>我们看到的是一头苏醒的巨兽。它没有选择像 Go 那样“断舍离”，也没有像 Rust 那样“偏执于安全”，而是极其贪婪地选择了：<strong>“我全都要！”</strong></p>
<p>它既想要极致的表达能力和零成本抽象（反射、模板），又想要与 Rust 媲美的内存安全（加固标准库），还想要不输 Go 的并发表达力（std::execution）。</p>
<p>C++26 给老兵们提供了前所未有的强大武器，但也把本就陡峭的学习曲线，又向上抬升了一个令人惊叹的高度，宇宙第一复杂的编程语言，实至名归！</p>
<p>当 Go 的开发者还在为“是否要加个三元表达式”而争论不休时，C++ 已经头也不回地奔向了“万神殿”。</p>
<p>或许，编程语言的终局，真的不是“大一统”，而是“两极分化”：一极是像 Go 一样追求极致简单的“工程师语言”；而另一极，则是像 C++ 这样，专为那 1% 的、追求极致性能和控制力的“宗师级”开发者准备的、布满荆棘的封神之路。</p>
<p><strong>C++26，欢迎来到神的世界，也欢迎来到神的炼狱。</strong></p>
<h2>参考资料</h2>
<ul>
<li>https://herbsutter.com/2026/03/29/c26-is-done-trip-report-march-2026-iso-c-standards-meeting-london-croydon-uk/</li>
<li>https://herbsutter.com/2025/06/21/trip-report-june-2025-iso-c-standards-meeting-sofia-bulgaria/ </li>
<li>https://herbsutter.com/2024/07/02/trip-report-summer-iso-c-standards-meeting-st-louis-mo-usa/</li>
<li>https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2025/p2996r13.html</li>
<li>https://www.youtube.com/watch?v=7z9NNrRDHQU</li>
<li>https://www.youtube.com/watch?v=oitYvDe4nps</li>
</ul>
<hr />
<p><strong>今日互动探讨：</strong></p>
<p>看完 C++26 的这四大“神仙”特性，你是感到兴奋，还是感到了深深的绝望？你觉得 C++ 的这种“大而全”的演进路线是对的，还是 Go 的“小而美”更代表未来？</p>
<p>欢迎在评论区分享你的看法！</p>
<hr />
<p>还在为“复制粘贴喂AI”而烦恼？我的新专栏 <strong>《<a href="http://gk.link/a/12EPd">AI原生开发工作流实战</a>》</strong> 将带你：</p>
<ul>
<li>告别低效，重塑开发范式</li>
<li>驾驭AI Agent(Claude Code)，实现工作流自动化</li>
<li>从“AI使用者”进化为规范驱动开发的“工作流指挥家”</li>
</ul>
<p>扫描下方二维码，开启你的AI原生开发之旅。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/ai-native-dev-workflow-qr.png" alt="" /></p>
<hr />
<p>你的Go技能，是否也卡在了“熟练”到“精通”的瓶颈期？</p>
<ul>
<li>想写出更地道、更健壮的Go代码，却总在细节上踩坑？</li>
<li>渴望提升软件设计能力，驾驭复杂Go项目却缺乏章法？</li>
<li>想打造生产级的Go服务，却在工程化实践中屡屡受挫？</li>
</ul>
<p>继《<a href="http://gk.link/a/10AVZ">Go语言第一课</a>》后，我的《<a href="http://gk.link/a/12yGY">Go语言进阶课</a>》终于在极客时间与大家见面了！</p>
<p>我的全新极客时间专栏 《<a href="http://gk.link/a/12yGY">Tony Bai·Go语言进阶课</a>》就是为这样的你量身打造！30+讲硬核内容，带你夯实语法认知，提升设计思维，锻造工程实践能力，更有实战项目串讲。</p>
<p>目标只有一个：助你完成从“Go熟练工”到“Go专家”的蜕变！ 现在就加入，让你的Go技能再上一个新台阶！</p>
<p><img src="https://tonybai.com/wp-content/uploads/course-card/iamtonybai-banner-2.gif" alt="" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2026, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2026/03/31/go-minimalism-vs-cpp26-epic-new-features/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>降低 74% 的 P99 尾延迟：揭秘 Go HTTP 客户端的“请求对冲”魔法</title>
		<link>https://tonybai.com/2026/03/30/reduced-p99-latency-by-request-hedging-in-go/</link>
		<comments>https://tonybai.com/2026/03/30/reduced-p99-latency-by-request-hedging-in-go/#comments</comments>
		<pubDate>Mon, 30 Mar 2026 00:10:00 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[Availability]]></category>
		<category><![CDATA[circuitbreaker]]></category>
		<category><![CDATA[Concurrency]]></category>
		<category><![CDATA[Context]]></category>
		<category><![CDATA[DistributedSystems]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[GoLanguage]]></category>
		<category><![CDATA[Go语言]]></category>
		<category><![CDATA[HedgeDelay]]></category>
		<category><![CDATA[HedgedRequests]]></category>
		<category><![CDATA[http.RoundTripper]]></category>
		<category><![CDATA[Idempotency]]></category>
		<category><![CDATA[LoadBalancing]]></category>
		<category><![CDATA[Microservices]]></category>
		<category><![CDATA[P99Latency]]></category>
		<category><![CDATA[P99延迟]]></category>
		<category><![CDATA[RequestHedging]]></category>
		<category><![CDATA[standardlibrary]]></category>
		<category><![CDATA[SyncWaitGroup]]></category>
		<category><![CDATA[TailLatency]]></category>
		<category><![CDATA[Throttling]]></category>
		<category><![CDATA[Throughput]]></category>
		<category><![CDATA[TimeoutRetry]]></category>
		<category><![CDATA[上下文]]></category>
		<category><![CDATA[分布式系统]]></category>
		<category><![CDATA[可用性]]></category>
		<category><![CDATA[同步机制]]></category>
		<category><![CDATA[吞吐量]]></category>
		<category><![CDATA[对冲延迟]]></category>
		<category><![CDATA[尾延迟]]></category>
		<category><![CDATA[幂等性]]></category>
		<category><![CDATA[并发]]></category>
		<category><![CDATA[微服务]]></category>
		<category><![CDATA[标准库]]></category>
		<category><![CDATA[熔断]]></category>
		<category><![CDATA[请求对冲]]></category>
		<category><![CDATA[负载均衡]]></category>
		<category><![CDATA[超时重试]]></category>
		<category><![CDATA[链路对冲]]></category>
		<category><![CDATA[限流]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=6119</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2026/03/30/reduced-p99-latency-by-request-hedging-in-go 大家好，我是Tony Bai。 在微服务和分布式系统的世界里，我们常常会遇到一个令人头疼的现象：服务在大部分时间（如 P50 或 P90 指标）表现得非常丝滑，但总有那么一小撮请求（P99 甚至 P99.9 指标）慢得令人发指。 近日，在 Reddit 的 r/golang 社区中，一位开发者分享了他将 Go 服务的 P99 延迟降低了 74% 的经验。令人惊讶的是，他所使用的绝招并非升级硬件或重构业务逻辑，而是引入了一个名为 Request Hedging（请求对冲） 的策略。 面对高延迟，我们本能的反应是“重试（Retry）”。但正如这位开发者所发现的：单纯的重试不仅无助于解决长尾延迟，反而可能在系统高负载时雪上加霜。真正有效的方法是处理“落后者”，而不是“失败者”。 本文将带你重温 Google 关于分布式系统的经典论文，深入剖析 Request Hedging 的原理，并手把手教你如何仅使用 Go 标准库，为你的 HTTP 客户端插上“对冲”的翅膀。 尾延迟的诅咒：为什么重试不是万能药？ 在深入 Hedging 之前，我们必须先理解什么是尾延迟（Tail Latency）。 2013 年，Google 的两位大神 Jeffrey Dean 和 Luiz André Barroso 在《Communications of the [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2026/reduced-p99-latency-by-request-hedging-in-go-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2026/03/30/reduced-p99-latency-by-request-hedging-in-go">本文永久链接</a> &#8211; https://tonybai.com/2026/03/30/reduced-p99-latency-by-request-hedging-in-go</p>
<p>大家好，我是Tony Bai。</p>
<p>在微服务和分布式系统的世界里，我们常常会遇到一个令人头疼的现象：服务在大部分时间（如 P50 或 P90 指标）表现得非常丝滑，但总有那么一小撮请求（P99 甚至 P99.9 指标）慢得令人发指。</p>
<p>近日，在 Reddit 的 r/golang 社区中，一位开发者分享了他<a href="https://www.reddit.com/r/golang/comments/1s4mb10/reduced_p99_latency_by_74_in_go_learned_something/">将 Go 服务的 P99 延迟降低了 74% 的经验</a>。令人惊讶的是，他所使用的绝招并非升级硬件或重构业务逻辑，而是引入了一个名为 <strong>Request Hedging（请求对冲）</strong> 的策略。</p>
<p>面对高延迟，我们本能的反应是“重试（Retry）”。但正如这位开发者所发现的：单纯的重试不仅无助于解决长尾延迟，反而可能在系统高负载时雪上加霜。真正有效的方法是处理“落后者”，而不是“失败者”。</p>
<p>本文将带你重温 Google 关于分布式系统的<a href="https://research.google/pubs/the-tail-at-scale/">经典论文</a>，深入剖析 Request Hedging 的原理，并手把手教你如何仅使用 Go 标准库，为你的 HTTP 客户端插上“对冲”的翅膀。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/distributed-system-guide-qr.png" alt="" /></p>
<h2>尾延迟的诅咒：为什么重试不是万能药？</h2>
<p>在深入 Hedging 之前，我们必须先理解什么是<strong>尾延迟（Tail Latency）</strong>。</p>
<p>2013 年，Google 的两位大神 Jeffrey Dean 和 Luiz André Barroso 在《Communications of the ACM》上发表了一篇神级论文：<a href="https://cacm.acm.org/research/the-tail-at-scale/">《The Tail at Scale》</a>。在这篇Paper中，他们详细阐述了在大规模分布式系统中，为什么长尾延迟是不可避免的。</p>
<p>哪怕你拥有世界上最优秀的工程师，底层硬件的物理特性（如 CPU 降频、网络拥塞）、操作系统的后台任务（如 IO 调度）、以及语言运行时的特性（如 Go 的 GC 停顿），都会导致某些请求的处理时间远高于平均值。</p>
<p><strong>当你的服务需要并行调用多个下游服务时，这种局部的延迟波动会被急剧放大。</strong> 假设一个服务需要调用 100 个叶子节点，如果单个节点响应时间超过 1 秒的概率是 1%，那么整个请求超过 1 秒的概率将飙升至 63%！</p>
<blockquote>
<p>注：节点总数 n = 100 ，已知单个节点响应时间超过 1 秒的概率 为1%。单个节点响应时间不超过 1 秒（即正常响应）的概率为1-1% = 99% = 0.99。由于 100 个请求是并行的且相互独立，整个请求“正常”的前提是所有 100 个节点都必须在 1 秒内返回。这种概率为0.99^100=0.366。这样只要这 100 个节点中有任何一个掉链子，整个请求（作为整体）的耗时就会超过 1 秒。其概率为1-0.366≈0.63=63%。</p>
</blockquote>
<p><img src="https://tonybai.com/wp-content/uploads/2026/reduced-p99-latency-by-request-hedging-in-go-2.png" alt="" /><br />
<center>图：来自《The Tail at Scale》</center></p>
<p>这张图直观地展示了随着服务器数量（Fan-out）增加，哪怕单机变慢的概率极低，整体响应时间变慢的概率也会陡峭上升。</p>
<p>面对超时的请求，传统的做法是实施超时重试（Timeout &amp; Retry）。但重试存在致命缺陷：</p>
<ol>
<li><strong>你必须等待超时发生。</strong> 如果超时设置为 1 秒，那么重试的请求至少要经历 1 秒的延迟，这根本无法改善 P99 延迟。</li>
<li><strong>加剧雪崩。</strong> 当下游服务因为负载过高而变慢时，大量的重试请求会瞬间淹没下游，导致系统彻底崩溃。</li>
</ol>
<h2>Request Hedging：优雅地跑赢时间</h2>
<p>为了解决长尾延迟，Google 论文中提出了一种极具工程智慧的策略：<strong>Hedged Requests（请求对冲/对冲请求）</strong>。</p>
<p>其核心思想非常简单直白：</p>
<p><strong>客户端首先向目标服务器发送一个请求。如果该请求在预期的时间（即“对冲延迟阈值”，Hedging Delay）内没有返回，客户端不会等待其超时或失败，而是立即向另一个副本（或者同一个负载均衡器后的其他实例）发送一模一样的备份请求。客户端将使用最先返回的那个成功响应，并主动取消其余的未决请求。</strong></p>
<p>这种方法之所以有效，是因为导致请求变慢的因素通常是瞬时的且与特定机器相关的（如某台机器刚好在做 GC，或者刚好被一个大查询阻塞了队列）。第二个请求很大概率会被路由到一台健康的、空闲的机器上，从而快速返回。</p>
<p><strong>Hedging 与 Retry 的本质区别：</strong></p>
<ul>
<li><strong>Retry</strong>：针对的是<strong>失败（Failure）</strong>。必须等第一个请求彻底失败或超时，才发起第二个。</li>
<li><strong>Hedging</strong>：针对的是<strong>慢（Slowness）</strong>。第一个请求还在运行（没报错），第二个请求就已经出发了。它们是并行竞争的关系。</li>
</ul>
<p><img src="https://tonybai.com/wp-content/uploads/2026/reduced-p99-latency-by-request-hedging-in-go-3.png" alt="" /></p>
<p>虽然这听起来像是在浪费服务器资源，但 Google 的实践证明，如果将 Hedging Delay 设置为 P95 延迟（即 95% 的请求都能在这个时间内完成），那么<strong>只有 5% 的请求会触发对冲。这仅仅增加了 5% 的系统负载，却能将 P99 或 P99.9 的长尾延迟削减大半！</strong></p>
<p>在现代微服务生态中，<a href="https://grpc.io/docs/guides/request-hedging/">gRPC 已经在 Service Config 中原生支持了 Hedging 策略</a>，但对于广泛使用的 HTTP/REST 接口，我们通常需要自己实现。</p>
<h2>实战：构建可压测的 Hedging HTTP Client</h2>
<p>为了验证 Hedging 的威力，我们将使用 Go 原生标准库，从零实现一个带有对冲机制的 http.RoundTripper，并构建一个完整的压测实验环境。</p>
<h3>项目布局</h3>
<p>首先，创建一个新的 Go 项目：</p>
<pre><code class="bash">mkdir go-hedging-demo
cd go-hedging-demo
go mod init hedging-demo
</code></pre>
<p>我们将创建三个文件：</p>
<ul>
<li>hedge.go：包含核心的 Hedging 逻辑实现。</li>
<li>server.go：一个模拟真实分布式环境、带有随机高延迟的测试服务器。</li>
<li>main.go：客户端压测入口，用于对比普通请求和 Hedging 请求的性能差异。</li>
</ul>
<pre><code class="text">go-hedging-demo/
├── go.mod
├── hedge.go
├── server.go
└── main.go
</code></pre>
<h3>核心实现：hedge.go</h3>
<p>我们将通过实现 http.RoundTripper 接口，优雅地将对冲逻辑无缝注入到 Go 标准库的 http.Client 中。</p>
<pre><code class="go">// hedge.go
package main

import (
    "context"
    "errors"
    "net/http"
    "sync"
    "time"
)

// HedgedTransport 实现了 http.RoundTripper 接口
type HedgedTransport struct {
    Transport   http.RoundTripper // 底层真正的 Transport
    MaxAttempts int               // 最大并发请求数（包括最初的1次）
    HedgeDelay  time.Duration     // 触发对冲的延迟时间
}

func (ht *HedgedTransport) RoundTrip(req *http.Request) (*http.Response, error) {
    // 如果没有设置，使用默认行为
    transport := ht.Transport
    if transport == nil {
        transport = http.DefaultTransport
    }
    attempts := ht.MaxAttempts
    if attempts &lt;= 0 {
        attempts = 1
    }

    // 使用带有取消功能的 context 控制整个对冲生命周期
    ctx, cancel := context.WithCancel(req.Context())
    defer cancel()

    // 结果通道，用于接收第一个成功的响应或错误
    type result struct {
        resp *http.Response
        err  error
    }
    resCh := make(chan result, attempts)
    var wg sync.WaitGroup

    // 启动一个请求的闭包函数
    doRequest := func() {
        wg.Add(1)
        go func() {
            defer wg.Done()
            // 克隆请求，防止并发修改
            cloneReq := req.Clone(ctx)
            resp, err := transport.RoundTrip(cloneReq)

            // 只有当请求不是因为 context 取消而失败时，才尝试写入结果
            if !errors.Is(err, context.Canceled) {
                select {
                case resCh &lt;- result{resp: resp, err: err}:
                default:
                    // 通道已满或已不再需要，直接丢弃（如果 resp 不为空，需要关闭 Body 以防泄露）
                    if resp != nil &amp;&amp; resp.Body != nil {
                        resp.Body.Close()
                    }
                }
            }
        }()
    }

    // 1. 发起第一个请求
    doRequest()

    // 2. 控制对冲的定时器和尝试次数
    timer := time.NewTimer(ht.HedgeDelay)
    defer timer.Stop()

    errs := make([]error, 0, attempts)
    requestsSent := 1

    for {
        select {
        case res := &lt;-resCh:
            // 收到结果
            if res.err == nil {
                // 成功！立即取消其他还在飞行的请求
                cancel()
                // 等待后台 goroutine 清理完成 (可选，这里为了简单不阻塞)
                return res.resp, nil
            }
            // 如果这个请求失败了，记录错误
            errs = append(errs, res.err)
            // 如果所有发出的请求都失败了，且已经达到最大尝试次数，返回错误
            if len(errs) == attempts {
                return nil, errors.Join(errs...)
            }

            // 如果一个请求失败了，且还没达到最大尝试次数，我们不应该死等 Timer，
            // 而应该立刻触发下一个对冲请求（这里为了简化逻辑，依然依赖下一次 Timer 或失败循环）
            // 实际生产级实现可以在这里直接触发 doRequest()

        case &lt;-timer.C:
            // 对冲延迟到达
            if requestsSent &lt; attempts {
                // 触发对冲请求
                doRequest()
                requestsSent++
                // 重置定时器，准备下一次可能的对冲
                timer.Reset(ht.HedgeDelay)
            }

        case &lt;-ctx.Done():
            // 整个请求超时或被调用方取消
            return nil, ctx.Err()
        }
    }
}
</code></pre>
<p>这里，我们使用了 req.Clone(ctx) 来复制请求，确保并发安全。通过 context.WithCancel 控制所有的下游请求，一旦有一个请求成功返回（res.err == nil），立即调用 cancel() 取消其余正在运行（in-flight）的请求。</p>
<h3>测试服务器：模拟“长尾效应” server.go</h3>
<p>为了看到效果，我们编写一个简单的 HTTP 服务。它在 90% 的情况下在 50ms 内快速响应，但在 10% 的情况下会遇到长达 500ms 到 1s 的长尾延迟。</p>
<pre><code class="go">// server.go
package main

import (
    "fmt"
    "math/rand"
    "net/http"
    "time"
)

func startServer() {
    http.HandleFunc("/data", func(w http.ResponseWriter, r *http.Request) {
        // 模拟 10% 的长尾延迟
        if rand.Float32() &lt; 0.1 {
            // 长尾延迟：500ms - 1000ms
            delay := 500 + rand.Intn(500)
            time.Sleep(time.Duration(delay) * time.Millisecond)
        } else {
            // 正常响应：10ms - 50ms
            delay := 10 + rand.Intn(40)
            time.Sleep(time.Duration(delay) * time.Millisecond)
        }

        fmt.Fprintln(w, "OK")
    })

    go func() {
        err := http.ListenAndServe(":8080", nil)
        if err != nil {
            panic(err)
        }
    }()
    time.Sleep(100 * time.Millisecond) // 等待服务器启动
}
</code></pre>
<h3>压测入口：对比见真章 main.go</h3>
<p>最后，我们编写压测代码，分别使用普通 Client 和 Hedged Client 发送 1000 个并发请求，并统计 P99 延迟。</p>
<pre><code class="go">// main.go
package main

import (
    "fmt"
    "io"
    "net/http"
    "sort"
    "sync"
    "time"
)

const RequestCount = 1000

func main() {
    startServer()

    fmt.Println("开始压测普通 HTTP Client...")
    normalClient := &amp;http.Client{
        Timeout: 2 * time.Second,
    }
    normalLatencies := runBenchmark(normalClient)

    fmt.Println("\n开始压测 Hedged HTTP Client...")
    hedgedClient := &amp;http.Client{
        Timeout: 2 * time.Second,
        Transport: &amp;HedgedTransport{
            Transport:   http.DefaultTransport,
            MaxAttempts: 3,                 // 最多发送3个请求
            HedgeDelay:  80 * time.Millisecond, // P95 延迟设为触发点（我们服务器正常响应 &lt; 50ms）
        },
    }
    hedgedLatencies := runBenchmark(hedgedClient)

    // 打印统计结果
    printStats("Normal Client", normalLatencies)
    printStats("Hedged Client", hedgedLatencies)
}

func runBenchmark(client *http.Client) []time.Duration {
    var wg sync.WaitGroup
    latencies := make([]time.Duration, RequestCount)

    for i := 0; i &lt; RequestCount; i++ {
        wg.Add(1)
        go func(index int) {
            defer wg.Done()

            start := time.Now()
            resp, err := client.Get("http://localhost:8080/data")
            if err != nil {
                fmt.Printf("Request failed: %v\n", err)
                return
            }
            io.Copy(io.Discard, resp.Body)
            resp.Body.Close()

            latencies[index] = time.Since(start)
        }(i)
    }

    wg.Wait()
    return latencies
}

func printStats(name string, latencies []time.Duration) {
    // 去除可能的失败请求（0值）
    valid := make([]time.Duration, 0, len(latencies))
    for _, l := range latencies {
        if l &gt; 0 {
            valid = append(valid, l)
        }
    }

    sort.Slice(valid, func(i, j int) bool {
        return valid[i] &lt; valid[j]
    })

    if len(valid) == 0 {
        fmt.Printf("No valid responses for %s\n", name)
        return
    }

    p50 := valid[len(valid)/2]
    p95 := valid[int(float64(len(valid))*0.95)]
    p99 := valid[int(float64(len(valid))*0.99)]

    fmt.Printf("\n=== %s 统计 ===\n", name)
    fmt.Printf("请求总数: %d\n", len(valid))
    fmt.Printf("P50 延迟: %v\n", p50)
    fmt.Printf("P95 延迟: %v\n", p95)
    fmt.Printf("P99 延迟: %v\n", p99)
}
</code></pre>
<h3>运行与验证</h3>
<p>在本地 MacBook Pro 的终端上执行 go run .，我得到了以下真实的性能对决：</p>
<pre><code class="text">$go run .
开始压测普通 HTTP Client...

开始压测 Hedged HTTP Client...

=== Normal Client 统计 ===
请求总数: 1000
P50 延迟: 115.226929ms
P95 延迟: 850.768537ms &lt;-- 注意看这里
P99 延迟: 1.045720114s &lt;-- 长尾效应严重

=== Hedged Client 统计 ===
请求总数: 1000
P50 延迟: 138.930108ms &lt;-- P50 轻微损耗
P95 延迟: 360.607686ms &lt;-- 巨大的改善！
P99 延迟: 376.98949ms  &lt;-- P99 降低了将近 70%！
</code></pre>
<p>正如你所见：</p>
<ul>
<li>P99 巨幅改善：对冲机制成功将 P99 延迟降低了 64%。原本需要 1 秒以上的极端慢请求，现在被控制在了 400ms 以内。</li>
<li>P50 轻微损耗：由于请求克隆、Context 管理以及本地 CPU 调度多出一倍请求的竞争，P50 上升了约 23ms。</li>
</ul>
<p>结论：在典型的分布式系统中，这种权衡是极度划算的。我们用极小的平均延迟上升，换取了尾部延迟的高稳定性。</p>
<h2>生产环境的避坑指南</h2>
<p>Request Hedging 虽好，但绝非能随意滥用的“银弹”。在将其部署到生产环境之前，你必须考虑以下几个核心约束：</p>
<ol>
<li><strong>绝对的幂等性（Idempotency）</strong>：对冲意味着同一笔请求可能同时发送给后端的两个节点。如果这是个 POST 扣款请求，而你的后端没有做好幂等性控制，这将会是一场灾难。<strong>Hedging 最好只用于幂等的只读请求（如 GET），或者有严格全局事务 ID 兜底的写入操作。</strong></li>
<li><strong>Hedge Delay 的设定</strong>：这是最考验架构师的参数。设得太短，所有的请求都会变成双倍发送，瞬间打挂后端（这叫放大攻击）；设得太长，起不到降低长尾的作用。最佳实践是通过 Prometheus 等监控工具，计算出该接口过去的 <strong>P95 响应时间</strong>，将其作为 Hedging Delay 的基准值。</li>
<li><strong>熔断与限流（Throttling）</strong>：如果下游服务整体宕机，所有的请求都会变慢，此时触发所有的对冲请求只会加速死亡。因此，正如 gRPC 规范中要求的，Hedging 必须与限流（Throttling）结合。例如，计算一个“对冲令牌池”，只有当成功请求大于失败请求达到一定比例时，才允许发送对冲请求。</li>
</ol>
<h2>小结</h2>
<p>软件工程是一门关于权衡的艺术。在追求极致性能的道路上，我们往往将目光局限于优化数据库索引、压缩 JSON 序列化，却忽视了分布式系统固有的宏观不确定性。</p>
<p>Request Hedging 是从宏观架构层面给出的一记漂亮的防守反击。通过上面几百行的 Go 代码，我们成功复现了 Google 级别的架构优化。下一次，当你的监控大盘上 P99 曲线再次异常抖动时，不妨收起单纯的“超时重试”，尝试给你的 Go 客户端加一点“对冲”的魔法吧。</p>
<p>本文中涉及的代码可以在<a href="https://github.com/bigwhite/experiments/tree/master/go-hedging-demo">这里</a>下载。https://github.com/bigwhite/experiments/tree/master/go-hedging-demo</p>
<p>资料链接：</p>
<ul>
<li>https://www.reddit.com/r/golang/comments/1s4mb10/reduced_p99_latency_by_74_in_go_learned_something/</li>
<li>https://grpc.io/docs/guides/request-hedging/</li>
<li>https://research.google/pubs/the-tail-at-scale/</li>
</ul>
<hr />
<p><strong>你的 P99 达标了吗？</strong></p>
<p>尾延迟是分布式系统中最难缠的对手。在你的项目中，主要的长尾延迟来源是什么？你会为了降低那 1% 的极端慢请求，而接受 5% 的额外系统负载吗？</p>
<p>欢迎在评论区分享你的性能调优“必杀技”！</p>
<hr />
<p>还在为“复制粘贴喂AI”而烦恼？我的新专栏 <strong>《<a href="http://gk.link/a/12EPd">AI原生开发工作流实战</a>》</strong> 将带你：</p>
<ul>
<li>告别低效，重塑开发范式</li>
<li>驾驭AI Agent(Claude Code)，实现工作流自动化</li>
<li>从“AI使用者”进化为规范驱动开发的“工作流指挥家”</li>
</ul>
<p>扫描下方二维码，开启你的AI原生开发之旅。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/ai-native-dev-workflow-qr.png" alt="" /></p>
<hr />
<p>你的Go技能，是否也卡在了“熟练”到“精通”的瓶颈期？</p>
<ul>
<li>想写出更地道、更健壮的Go代码，却总在细节上踩坑？</li>
<li>渴望提升软件设计能力，驾驭复杂Go项目却缺乏章法？</li>
<li>想打造生产级的Go服务，却在工程化实践中屡屡受挫？</li>
</ul>
<p>继《<a href="http://gk.link/a/10AVZ">Go语言第一课</a>》后，我的《<a href="http://gk.link/a/12yGY">Go语言进阶课</a>》终于在极客时间与大家见面了！</p>
<p>我的全新极客时间专栏 《<a href="http://gk.link/a/12yGY">Tony Bai·Go语言进阶课</a>》就是为这样的你量身打造！30+讲硬核内容，带你夯实语法认知，提升设计思维，锻造工程实践能力，更有实战项目串讲。</p>
<p>目标只有一个：助你完成从“Go熟练工”到“Go专家”的蜕变！ 现在就加入，让你的Go技能再上一个新台阶！</p>
<p><img src="https://tonybai.com/wp-content/uploads/course-card/iamtonybai-banner-2.gif" alt="" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2026, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2026/03/30/reduced-p99-latency-by-request-hedging-in-go/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rust 看了流泪，AI 看了沉默：扒开 Go 泛型最让你抓狂的“残疾”类型推断</title>
		<link>https://tonybai.com/2026/03/27/function-type-inference-should-work-in-all-assignment-contexts/</link>
		<comments>https://tonybai.com/2026/03/27/function-type-inference-should-work-in-all-assignment-contexts/#comments</comments>
		<pubDate>Thu, 26 Mar 2026 23:09:11 +0000</pubDate>
		<dc:creator>bigwhite</dc:creator>
				<category><![CDATA[技术志]]></category>
		<category><![CDATA[AIProgramming]]></category>
		<category><![CDATA[AI编程]]></category>
		<category><![CDATA[Assignability]]></category>
		<category><![CDATA[ClaudeCode]]></category>
		<category><![CDATA[Codex]]></category>
		<category><![CDATA[Compiler]]></category>
		<category><![CDATA[CompositeLiterals]]></category>
		<category><![CDATA[ErrorHandling]]></category>
		<category><![CDATA[generics]]></category>
		<category><![CDATA[Go]]></category>
		<category><![CDATA[Golang]]></category>
		<category><![CDATA[GoLanguage]]></category>
		<category><![CDATA[Go语言]]></category>
		<category><![CDATA[Instantiation]]></category>
		<category><![CDATA[Issue77245]]></category>
		<category><![CDATA[RobertGriesemer]]></category>
		<category><![CDATA[SoftwareEngineering]]></category>
		<category><![CDATA[StaticTyping]]></category>
		<category><![CDATA[SyntacticSugar]]></category>
		<category><![CDATA[typeinference]]></category>
		<category><![CDATA[TypeSystem]]></category>
		<category><![CDATA[可赋值性]]></category>
		<category><![CDATA[复合字面量]]></category>
		<category><![CDATA[实例化]]></category>
		<category><![CDATA[泛型]]></category>
		<category><![CDATA[类型推断]]></category>
		<category><![CDATA[类型系统]]></category>
		<category><![CDATA[编译器]]></category>
		<category><![CDATA[语法糖]]></category>
		<category><![CDATA[软件工程]]></category>
		<category><![CDATA[错误处理]]></category>
		<category><![CDATA[静态类型]]></category>

		<guid isPermaLink="false">https://tonybai.com/?p=6106</guid>
		<description><![CDATA[本文永久链接 &#8211; https://tonybai.com/2026/03/27/function-type-inference-should-work-in-all-assignment-contexts 大家好，我是Tony Bai。 在这个大模型（AI）写代码如喝水一般简单的时代，你有没有遇到过一种极其憋屈的场景： 你让 Claude Code 或者 Codex 帮你写了一段 Go 语言代码，逻辑清晰，结构优雅，连它自己都觉得这波操作满分。但当你满怀期待地按下 go run 时，Go 编译器却无情地丢给你一个红色报错： cannot use generic function g without instantiation （不能在未实例化的情况下使用泛型函数 g） AI 沉默了，它不明白自己错在哪；如果你是个习惯了 Rust 那种“地表最强类型推断”的开发者，你可能会当场流下心酸的眼泪—— 在 Rust 里闭着眼睛都能推断出来的泛型参数，怎么到了 Go 里，它就突然变成了“残疾”？ 如果你曾经被这个“诡异”的泛型报错折磨过，甚至因此怀疑过自己的智商，不要怪 AI 不懂 Go 语言。 因为就在最近，连“Go 语言之父之一” 的 Robert Griesemer 都亲自在官方 GitHub 上提了一个 Issue，承认这个语法限制不仅反直觉，甚至一度被认为是一个编译器 Bug！Griesemer 本人随即在 Issue 中自我更正，明确这需要语言规范(spec)层面的修改，而不只是修编译器。 今天，我们就来扒开这个在 [...]]]></description>
			<content:encoded><![CDATA[<p><img src="https://tonybai.com/wp-content/uploads/2026/function-type-inference-should-work-in-all-assignment-contexts-1.png" alt="" /></p>
<p><a href="https://tonybai.com/2026/03/27/function-type-inference-should-work-in-all-assignment-contexts">本文永久链接</a> &#8211; https://tonybai.com/2026/03/27/function-type-inference-should-work-in-all-assignment-contexts</p>
<p>大家好，我是Tony Bai。</p>
<p>在这个大模型（AI）写代码如喝水一般简单的时代，你有没有遇到过一种极其憋屈的场景：</p>
<p>你让 Claude Code 或者 Codex 帮你写了一段 Go 语言代码，逻辑清晰，结构优雅，连它自己都觉得这波操作满分。但当你满怀期待地按下 go run 时，Go 编译器却无情地丢给你一个红色报错：</p>
<pre><code>cannot use generic function g without instantiation
（不能在未实例化的情况下使用泛型函数 g）
</code></pre>
<p>AI 沉默了，它不明白自己错在哪；如果你是个习惯了 Rust 那种“地表最强类型推断”的开发者，你可能会当场流下心酸的眼泪—— 在 Rust 里闭着眼睛都能推断出来的泛型参数，怎么到了 Go 里，它就突然变成了“残疾”？</p>
<p>如果你曾经被这个“诡异”的泛型报错折磨过，甚至因此怀疑过自己的智商，不要怪 AI 不懂 Go 语言。</p>
<p>因为就在最近，连“Go 语言之父之一” 的 Robert Griesemer 都亲自在官方 GitHub 上提了一个 Issue，承认这个语法限制不仅反直觉，甚至一度被认为是一个编译器 Bug！Griesemer 本人随即在 Issue 中自我更正，明确这需要语言规范(spec)层面的修改，而不只是修编译器。</p>
<p>今天，我们就来扒开这个在 Go 官方仓库引发热议的 <a href="https://github.com/golang/go/issues/77245">Issue #77245</a>，看看这个即将改变Go工程师日常编码的“底层规范级修补”，到底是怎么回事。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2026/agentic-software-engineering-qr.png" alt="" /></p>
<h2>“薛定谔”式的类型推断</h2>
<p>自从 Go 1.18 引入泛型以来，“不够聪明”的类型推断（Type Inference）就一直被开发者诟病。直到 Go 1.21 发布，官方宣称大幅增强了这部分能力：<strong>只要在赋值上下文中，目标类型是明确的，Go 就可以帮你自动推断出泛型函数的参数类型，不需要你手动写 g[int] 了。</strong></p>
<p>这听起来很美好，对吧？</p>
<p>但现实是极其骨感的。我们来看看 Robert Griesemer 亲自给出的这个“薛定谔式的推断”的例子：</p>
<pre><code class="go">type S struct{ f func(int) }

func g[T any](T) {} // 这是一个简单的泛型函数

func _(s S) {
    s.f = g          // ✅ 没问题！Go 编译器智商在线，完美推断出 T 是 int

    s = S{f: g}      // ❌ 报错：不能在没有实例化的情况下使用泛型函数 g

    s = S{f: g[int]} // ✅ 没问题！必须手动写死 g[int]
}
</code></pre>
<p>看懂这个坑在哪里了吗？</p>
<p>当你写 s.f = g 的时候，编译器智商在线，它知道 s.f 需要一个 func(int)，所以它机智地把泛型函数 g 实例化成了 g[int]。</p>
<p><strong>但是（最气人的但是）！</strong></p>
<p>当你使用结构体字面量 S{f: g} 进行初始化时，编译器却突然“智力下线”了。它死活推断不出 g 需要被实例化为 int，非逼着你极其啰嗦地写上 g[int]！</p>
<p>这种“一半聪明，一半智障”的表现，不仅存在于结构体里。在切片（Slice）、数组、Map，甚至是 Channel 的发送操作中：</p>
<pre><code>type F func(int)
type A [10]F
type S []F
type M map[string]F
type C chan F

func g[T any](T) {}

func _() {
    var a A
    a[0] = g      // ok
    a = A{g}      // error: cannot use generic function g without instantiation
    a = A{g[int]} // ok

    var s S
    s[0] = g      // ok
    s = S{g}      // error: cannot use generic function g without instantiation
    s = S{g[int]} // ok

    var m M
    m["foo"] = g         // ok
    m = M{"foo": g}      // error: cannot use generic function g without instantiation
    m = M{"foo": g[int]} // ok

    var c C
    c &lt;- g      // error: cannot use generic function g without instantiation
    c &lt;- g[int] // ok
}
</code></pre>
<p>只要你使用了复合字面量（Composite Literals），这套“残疾”的类型推断就会集体失效。</p>
<h2>为什么 Rust 和 AI 看了会沉默？</h2>
<p>如果你去问一个 Rust 开发者：<em>“目标结构体的字段类型 f func(int) 明明就摆在那里，Go 编译器为什么会看不见？”</em></p>
<p>Rust 开发者可能会拍着你的肩膀叹气。在 Rust 强大的类型推断系统面前，这种上下文推导简直是基本操作，根本不需要开发者操心。</p>
<p>而在如今 AI 辅助编程大行其道的时代，这个问题更加被无限放大。</p>
<p>大模型在学习了海量代码后，它的“直觉（Next-token prediction）”告诉它，这里上下文极其明确，根本不需要写死类型参数。于是 AI 开心地生成了 S{f: g}，结果却被 Go 编译器无情打脸。你不得不停止思考，手动去把 AI 生成的代码一行行加上 [int]、[string]……</p>
<p>这根本不是 AI 的幻觉，而是 Go 语言规范（Spec）在当年设计时，由于过于严谨，给自己留下的思维盲区。</p>
<p>在最初的 Go Spec 中，关于泛型函数实例化生效的上下文规定得极其死板（只在某些直接赋值的场景生效）。当时的 Go 团队并没有抽象出一个统一的 <strong>“赋值上下文（Assignment Context）”</strong> 概念。这导致散落在各个角落的复合字面量操作，全都成了漏网之鱼。</p>
<h2>官方的修补：一场牵一发而动全身的“规范手术”</h2>
<p>起初，Robert Griesemer 以为这只是个单纯的编译器 Bug，只要改改代码就行了。</p>
<p>但随着讨论的深入，核心成员们（如 Austin Clements）发现，这事儿没那么简单。要从根本上解决这个问题，<strong>必须对 Go 语言规范（Spec）动刀子！</strong></p>
<p>在随后的内部评审中，Go 团队做出了一个决策：</p>
<p>他们没有选择“头痛医头，脚痛医脚”地去给结构体、Map、切片分别打补丁。而是选择在 Go 语言最底层的定义——<strong>“可赋值性（Assignability）”</strong> 上做文章。</p>
<p>他们提出了一个<a href="https://go.dev/cl/751312">新的 CL</a> ，只要一个表达式符合“可赋值性”的校验（无论是等号赋值、结构体初始化、还是 Channel 发送），Go 编译器就必须启动泛型函数的自动类型推断。</p>
<p>这就好比给整个 Go 语言的类型推断系统，<strong>彻底打通了奇经八脉</strong>。</p>
<h2>小结</h2>
<p>到这里，可能有开发者会问：“不就是少写几个 [int] 吗？至于这么大惊小怪吗？”</p>
<p>在几行代码的 Demo 里，这确实不是事。</p>
<p>但在大厂动辄十几万或几十万行的微服务源码中，当我们使用泛型去实现高阶的“工厂模式”、“回调注册”、“依赖注入”时，代码中会充斥着大量的结构体初始化和泛型函数传递。</p>
<p>如果没有统一的类型推断，原本极其优雅的代码，就会变成被各种中括号 [T, K, V] 塞满的“乱码”。</p>
<p><strong>更少的手动类型标记，意味着更低的人类认知负荷（Cognitive Load），以及对 AI 代码生成工具更友好的兼容性。</strong></p>
<p>Go 语言之所以能在一众花里胡哨的新语言中稳坐云原生霸主的交椅，靠的绝不仅是并发，更是这种对“代码清爽度”和“心智负担”极其克制、甚至有些偏执的追求。</p>
<p>好消息是，这个被开发者诟病已久的痛点，已经被 Go 官方提案评审委员会 <strong>“正式接受（Accepted）”</strong>。</p>
<p>我们极有可能在即将到来的后续版本(比如Go 1.27)中，看到这段啰嗦的泛型代码彻底消失。</p>
<p>资料链接：</p>
<ul>
<li>https://github.com/golang/go/issues/77245</li>
<li>https://go.dev/cl/751312</li>
</ul>
<hr />
<p><strong>今日互动探讨：</strong></p>
<p>在日常写 Go 泛型的时候，你还遇到过哪些让你觉得“Go 编译器简直是个智障”的奇葩场景？或者在对比 Rust/TS 时，你觉得 Go 的类型系统最需要补齐哪个短板？</p>
<p>欢迎在评论区疯狂吐槽与分享!</p>
<hr />
<p>还在为“复制粘贴喂AI”而烦恼？我的新专栏 <strong>《<a href="http://gk.link/a/12EPd">AI原生开发工作流实战</a>》</strong> 将带你：</p>
<ul>
<li>告别低效，重塑开发范式</li>
<li>驾驭AI Agent(Claude Code)，实现工作流自动化</li>
<li>从“AI使用者”进化为规范驱动开发的“工作流指挥家”</li>
</ul>
<p>扫描下方二维码，开启你的AI原生开发之旅。</p>
<p><img src="https://tonybai.com/wp-content/uploads/2025/ai-native-dev-workflow-qr.png" alt="" /></p>
<hr />
<p><strong>原「Gopher部落」已重装升级为「Go &amp; AI 精进营」知识星球，快来加入星球，开启你的技术跃迁之旅吧！</strong></p>
<p>我们致力于打造一个高品质的 <strong>Go 语言深度学习</strong> 与 <strong>AI 应用探索</strong> 平台。在这里，你将获得：</p>
<ul>
<li><strong>体系化 Go 核心进阶内容:</strong> 深入「Go原理课」、「Go进阶课」、「Go避坑课」等独家深度专栏，夯实你的 Go 内功。</li>
<li><strong>前沿 Go+AI 实战赋能:</strong> 紧跟时代步伐，学习「Go+AI应用实战」、「Agent开发实战课」、「Agentic软件工程课」、「Claude Code开发工作流实战课」、「OpenClaw实战分享」等，掌握 AI 时代新技能。 </li>
<li><strong>星主 Tony Bai 亲自答疑:</strong> 遇到难题？星主第一时间为你深度解析，扫清学习障碍。</li>
<li><strong>高活跃 Gopher 交流圈:</strong> 与众多优秀 Gopher 分享心得、讨论技术，碰撞思想火花。</li>
<li><strong>独家资源与内容首发:</strong> 技术文章、课程更新、精选资源，第一时间触达。</li>
</ul>
<p>衷心希望「Go &amp; AI 精进营」能成为你学习、进步、交流的港湾。让我们在此相聚，享受技术精进的快乐！欢迎你的加入！</p>
<p><img src="http://image.tonybai.com/img/tonybai/gopher-and-ai-tribe-zsxq-small-card.jpg" alt="img{512x368}" /></p>
<hr />
<p>商务合作方式：撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。如有需求，请扫描下方公众号二维码，与我私信联系。</p>
<p><img src="http://image.tonybai.com/img/tonybai/iamtonybai-wechat-qr.png" alt="" /></p>
<p style='text-align:left'>&copy; 2026, <a href='https://tonybai.com'>bigwhite</a>. 版权所有. </p>
]]></content:encoded>
			<wfw:commentRss>https://tonybai.com/2026/03/27/function-type-inference-should-work-in-all-assignment-contexts/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
