Claude能够从项目布局中推断出大量信息,前提是你需要给它一个清晰的结构。在项目初期就建立好cmd/、pkg/、internal/、api/和scripts/等标准目录,这样Claude就知道架构的各个部分应该放在哪里,而不需要自己发明结构。

在软件开发领域,大语言模型正在改变我们编写代码的方式。作为一名有着丰富实践经验的开发者,我发现与Claude这样的AI工具协作时,关键不在于让AI完全接管开发工作,而在于建立合适的约束和工作流程。本文将分享我在使用Claude进行Go语言开发时总结的最佳实践,包括项目结构设计、代码质量控制、智能体协作以及如何构建一个可靠的AI结对编程工作流。

项目基础建设

早期确立目录结构

Claude能够从项目布局中推断出大量信息,前提是你需要给它一个清晰的结构。在项目初期就建立好cmd/、pkg/、internal/、api/和scripts/等标准目录,这样Claude就知道架构的各个部分应该放在哪里,而不需要自己发明结构。

良好的目录树就像GPS导航一样,Claude看到它就知道该往哪里去。更进一步,你可以在提示词中直接引用目录结构。比如说"在internal/handlers/中创建一个处理器,使用pkg/user中的接口",Claude就能准确理解并执行。

复制

// 标准Go项目结构示例
myproject/
├── cmd/
│   └── server/
│       └── main.go
├── internal/
│   ├── handlers/
│   ├── service/
│   └── repository/
├── pkg/
│   └── user/
│       └── interface.go
├── api/
│   └── openapi.yaml
└── scripts/
    └── build.sh
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
立即定义.gitignore

不要等到第一次意外提交了10MB的coverage.out文件后才想起来设置.gitignore。在项目开始时就定义好这个文件,Claude可以生成一个基础版本,或者你可以使用标准的Go模板并加入自己的定制。这样做可以避免diff中的噪音、仓库膨胀,以及意外将秘密信息提交到源码控制中。

复制

# 二进制文件
*.exe
*.exe~
*.dll
*.so
*.dylib

# 测试相关
*.test
*.out
coverage.out
coverage.html

# 依赖目录
vendor/

# 构建输出
dist/
build/

# IDE文件
.vscode/
.idea/
*.swp
*.swo

# 环境配置
.env
.env.local
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
定义接口而非实现

如果你想从Claude那里获得干净的代码,就要给它干净的契约。先编写定义所需行为的接口,然后Claude可以干净地实现这些接口,保持职责聚焦并减少耦合。不要丢给它一堆实现代码然后求助,而是展示边界让它填充中间的部分。

Go语言的接口驱动设计不仅是良好实践,也是让Claude产生惯用、模块化代码的方法。

复制

// 先定义清晰的接口
type UserService interface {
    CreateUser(ctx context.Context, req CreateUserRequest) (*User, error)
    GetUser(ctx context.Context, id string) (*User, error)
    UpdateUser(ctx context.Context, id string, req UpdateUserRequest) (*User, error)
    DeleteUser(ctx context.Context, id string) error
}

type UserRepository interface {
    Save(ctx context.Context, user *User) error
    FindByID(ctx context.Context, id string) (*User, error)
    Update(ctx context.Context, user *User) error
    Delete(ctx context.Context, id string) error
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
始终从计划开始

在没有计划的情况下直接跳入代码,等于是让Claude胡乱发挥。相反,每次会话开始时都要求Claude"制定实现X的步骤计划"。你会得到一个包含组件、职责和关系的要点列表。在开始编码之前确认或编辑这个计划。

你也可以开启规划模式(Shift+Tab键)。规划模式建立了一致性,它相当于在实现前编写验收标准的AI版本,更快、更清晰、更少意外。

API开发从OpenAPI开始

Claude对OpenAPI/Swagger规范的理解极其出色。给它你的规范文档,它可以生成:处理器、验证器、数据传输对象、测试脚手架、客户端SDK。

通过规范驱动的方法,你可以放心地重新生成代码,保持行为与契约一致,避免你认为API应该做什么与它实际做什么之间的逐渐偏离。

复制

# openapi.yaml 示例
openapi: 3.0.0
info:
  title: User Management API
  version: 1.0.0
paths:
  /users:
    post:
      summary: Create a new user
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateUserRequest'
      responses:
        '201':
          description: User created successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
components:
  schemas:
    User:
      type: object
      properties:
        id:
          type: string
        name:
          type: string
        email:
          type: string
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.

代码生成最佳实践

使用子智能体进行任务隔离

大语言模型喜欢一次只做一件事,所以给它们每个都分配一个任务。将开发工作流程分解为子智能体:一个构建处理器,一个生成测试,一个创建文档,一个编写基准测试。

这样缩小了提示范围并提高了输出质量。就像真正的工程师一样,大语言模型在不需要多任务处理时工作得更好。

复制

// 处理器生成示例
type UserHandler struct {
    service UserService
    logger  *slog.Logger
}

func NewUserHandler(service UserService, logger *slog.Logger) *UserHandler {
    return &UserHandler{
        service: service,
        logger:  logger,
    }
}

func (h *UserHandler) CreateUser(w http.ResponseWriter, r *http.Request) {
    var req CreateUserRequest
    if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
        h.logger.Error("failed to decode request", "error", err)
        http.Error(w, "invalid request body", http.StatusBadRequest)
        return
    }

    user, err := h.service.CreateUser(r.Context(), req)
    if err != nil {
        h.logger.Error("failed to create user", "error", err)
        http.Error(w, "internal server error", http.StatusInternalServerError)
        return
    }

    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(http.StatusCreated)
    json.NewEncoder(w).Encode(user)
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
并行使用子智能体

如果一个智能体很好用,多个并行智能体会更好。Claude不会疲劳,你可以启动多个子智能体并行处理代码库的不同部分——服务、模型、路由——然后稍后合并它们的输出。

你需要检查重叠或命名冲突,但速度和并发性的收益是值得的。

让Claude构建Makefile

一个好的Makefile是项目的入口点,Claude在构建这些方面很出色。让它生成包含标准命令的Makefile:make build、make test、make lint、make cover、make run。

标准化命令简化了入职流程并在不同机器和CI系统中强制执行一致行为。

复制

.PHONY: build test lint cover run clean

# 构建应用程序
build:
 go build -o bin/server cmd/server/main.go

# 运行测试
test:
 go test -v ./...

# 运行代码检查
lint:
 golangci-lint run

# 生成测试覆盖率报告
cover:
 go test -coverprofile=coverage.out ./...
 go tool cover -html=coverage.out -o coverage.html

# 运行应用程序
run:
 go run cmd/server/main.go

# 清理构建文件
clean:
 rm -rf bin/
 rm -f coverage.out coverage.html

# 安装依赖
deps:
 go mod download
 go mod tidy

# 格式化代码
fmt:
 go fmt ./...
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.

质量控制和代码卫生

使用严格的.golangci.yml进行代码检查

Claude会适应规则,如果你给它任何规则的话。从严格的.golangci.yml开始,强制执行以下内容:未使用变量检查、圈复杂度限制、导入顺序、错误检查。

然后在提示中引用这些规则。例如:"这个函数违反了gocyclo规则——重写它以通过检查。" 当给予明确反馈时,Claude学习得很快。

复制

# .golangci.yml
run:
  timeout: 5m
  issues-exit-code: 1

linters-settings:
  gocyclo:
    min-complexity: 10
  goconst:
    min-len: 3
    min-occurrences: 2
  goimports:
    local-prefixes: github.com/yourorg/yourproject
  misspell:
    locale: US

linters:
  enable:
    - errcheck
    - gosimple
    - govet
    - ineffassign
    - staticcheck
    - typecheck
    - unused
    - gocyclo
    - goconst
    - goimports
    - misspell
    - revive
  disable:
    - deadcode
    - varcheck

issues:
  exclude-rules:
    - path: _test\.go
      linters:
        - gocyclo
        - errcheck
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
添加Git预提交钩子进行检查和测试强制执行

不要依赖记忆——自动化强制执行。Claude可以生成运行代码检查、格式检查、单元测试、覆盖率阈值的预提交钩子。如果提交未能通过检查就会被阻止,这避免了"推送并祈祷"的工作流程,确保在代码审查前的代码卫生。

复制

#!/bin/sh
# .git/hooks/pre-commit

# 运行格式化
echo "Running go fmt..."
gofmt -w .

# 运行代码检查
echo "Running linter..."
golangci-lint run
if [ $? -ne 0 ]; then
    echo "Linting failed. Please fix the issues before committing."
    exit 1
fi

# 运行测试
echo "Running tests..."
go test ./...
if [ $? -ne 0 ]; then
    echo "Tests failed. Please fix the issues before committing."
    exit 1
fi

# 检查测试覆盖率
echo "Checking test coverage..."
go test -coverprofile=coverage.out ./...
coverage=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | sed 's/%//')
if [ $(echo "$coverage < 80" | bc -l) -eq 1 ]; then
    echo "Test coverage is below 80%. Current coverage: ${coverage}%"
    exit 1
fi

echo "All checks passed!"
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
频繁提交

Claude可能会过于热情。有时它优雅地解决问题,有时却无缘无故地重写整个文件。频繁提交让你能够跟踪变更、轻松回滚、了解何时发生了什么变化。

如果你懒得写提交信息,可以让Claude总结差异。"用一行git提交信息总结最后3个变更"效果出人意料地好。

代码审查和安全网

使用其他大语言模型审查代码

永远不要相信单一来源,特别是大语言模型。这时second-opinion工具就派上用场了。它使用第二个大语言模型在合并前审查你的代码。输入一个提交哈希,它会返回评论、危险信号和建议。

两个模型比一个好,特别是当一个负责编写,另一个负责批评时。

复制

// 代码审查示例:检查潜在问题
func (s *UserService) ProcessUsers(users []User) error {
    // 潜在问题:没有检查空切片
    for _, user := range users {
        // 潜在问题:没有错误处理
        s.repository.Save(context.Background(), &user)
    }
    return nil
}

// 改进版本
func (s *UserService) ProcessUsers(ctx context.Context, users []User) error {
    if len(users) == 0 {
        return nil
    }
    
    for _, user := range users {
        if err := s.repository.Save(ctx, &user); err != nil {
            s.logger.Error("failed to save user", "user_id", user.ID, "error", err)
            return fmt.Errorf("failed to save user %s: %w", user.ID, err)
        }
    }
    return nil
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.

测试和反馈循环

简化测试输出

Claude喜欢冗长输出,这对头脑风暴很好,但对测试输出很糟糕。要求Claude使用静默标志和覆盖率摘要运行测试。去掉绿色对勾的垃圾信息,专注于重要内容:哪些测试失败了、覆盖率是多少、在哪里修复。

你甚至可以要求Claude"以可读格式总结失败的测试输出",获得用于分类的人类友好摘要。

复制

// 完整的测试示例
func TestUserService_CreateUser(t *testing.T) {
    tests := []struct {
        name    string
        req     CreateUserRequest
        mockFn  func(*mock.Repository)
        want    *User
        wantErr bool
    }{
        {
            name: "successful creation",
            req: CreateUserRequest{
                Name:  "John Doe",
                Email: "john@example.com",
            },
            mockFn: func(repo *mock.Repository) {
                repo.EXPECT().Save(gomock.Any(), gomock.Any()).Return(nil)
            },
            want: &User{
                ID:    "123",
                Name:  "John Doe",
                Email: "john@example.com",
            },
            wantErr: false,
        },
        {
            name: "repository error",
            req: CreateUserRequest{
                Name:  "Jane Doe",
                Email: "jane@example.com",
            },
            mockFn: func(repo *mock.Repository) {
                repo.EXPECT().Save(gomock.Any(), gomock.Any()).Return(errors.New("db error"))
            },
            want:    nil,
            wantErr: true,
        },
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            ctrl := gomock.NewController(t)
            defer ctrl.Finish()

            mockRepo := mock.NewRepository(ctrl)
            tt.mockFn(mockRepo)

            service := NewUserService(mockRepo, slog.Default())
            got, err := service.CreateUser(context.Background(), tt.req)

            if (err != nil) != tt.wantErr {
                t.Errorf("CreateUser() error = %v, wantErr %v", err, tt.wantErr)
                return
            }
            if !reflect.DeepEqual(got, tt.want) {
                t.Errorf("CreateUser() got = %v, want %v", got, tt.want)
            }
        })
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.

实战工作流程

在实际开发中,我建议采用以下工作流程:

首先,使用Claude规划整个功能的实现步骤。然后将任务分解给不同的子智能体,一个负责数据层,一个负责业务逻辑,一个负责API层,最后一个负责测试。每个子智能体完成任务后,使用严格的代码检查规则进行验证,通过预提交钩子确保质量。

在代码合并前,使用第二个大语言模型进行代码审查,检查潜在问题。整个过程中保持频繁提交,确保可以追踪每个变更。通过这种结构化的方法,Claude从一个不可预测的工具变成了可靠的编程伙伴。

总结

Claude很快,但也不一致。关键不在于盲目信任,而在于工作流程纪律。如果你像对待团队成员一样对待大语言模型——给它们结构、强制执行规则、审查它们的工作——它们将成为团队中最有生产力的部分。

遵循这个蓝图,你将能够更快地编写更好的Go代码,减少头痛问题。在AI辅助开发的时代,成功的关键在于建立合适的约束和流程,让人工智能成为你的得力助手,而不是不可控的变数。

记住,最好的AI结对编程不是让AI完成所有工作,而是建立一个人机协作的高效工作流程。通过明确的结构、严格的质量控制和合理的任务分工,你可以充分发挥Claude在Go开发中的潜力,同时保持代码质量和项目的可维护性。

一、全套AGI大模型学习路线

AI大模型时代的学习之旅:从基础到前沿,掌握人工智能的核心技能!

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获取

二、640套AI大模型报告合集

这套包含640份报告的合集,涵盖了AI大模型的理论研究、技术实现、行业应用等多个方面。无论您是科研人员、工程师,还是对AI大模型感兴趣的爱好者,这套报告合集都将为您提供宝贵的信息和启示。

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获

三、AI大模型经典PDF籍

随着人工智能技术的飞速发展,AI大模型已经成为了当今科技领域的一大热点。这些大型预训练模型,如GPT-3、BERT、XLNet等,以其强大的语言理解和生成能力,正在改变我们对人工智能的认识。 那以下这些PDF籍就是非常不错的学习资源。


因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获

四、AI大模型商业化落地方案

因篇幅有限,仅展示部分资料,需要点击文章最下方名片即可前往获

作为普通人,入局大模型时代需要持续学习和实践,不断提高自己的技能和认知水平,同时也需要有责任感和伦理意识,为人工智能的健康发展贡献力量。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐