AI 时代的个人开发者:从需求到上线,只需三天!

AI 时代的个人开发者:从想法到上线,只需三天!(基于 MDFriday 的私有部署功能)

AI: Cursor Claude-3.7

MDFriday:一款能将多个 Markdown 文件转换为专业站点的 SaaS 服务

所有工作, 95% 都是 AI 干的!另外 5% 是我敲的提示词!

一起来看 AI 战力:前端加后端,共修改2748行!

震惊

前端

➜  obsidian-friday-plugin git:(main) git log --pretty=tformat: --numstat 87772da6b053eb9ec4cda02bf6d2d128942588a4..43ddf3de3665e5e56b3adb4e480d50992011ac5b | 
awk '{ added += $1; removed += $2 } END { print "Added lines:", added, "\nRemoved lines:", removed, "\nTotal changes:", added + removed }'

Added lines: 468 
Removed lines: 43 
Total changes: 511

后端

➜  hugoverse git:(main) git log --pretty=tformat: --numstat b241be4d0e10bcc2bcf35a2f03a9ee8cd9c8671e..471fb64d8c452199e0fa017f8f6fd7c630c29e54 | 
awk '{ added += $1; removed += $2 } END { print "Added lines:", added, "\nRemoved lines:", removed, "\nTotal changes:", added + removed }'

Added lines: 1785 
Removed lines: 452 
Total changes: 2237

需求来自缘分:将MDFriday生成的站点源码,部署到自己的服务上。

掘金在一个月前给我推了篇文章《2024年终复盘: 1600个小时的创业之旅》。 不由得感叹这算法,真准!因为我确实对个人开发相关的事情都很感兴趣。 当我点开的那一瞬间,吸引力法则又一次生效了。

同样是开发者,看到作者 - 徐小夕这么优秀,还是掘金签约作者。

私信,加好友,一气呵成!这个时候,脸皮厚就成了优点,哈哈哈。 聊着聊着就发现,他的公司就在武汉!聊着聊着就发现,我们俩相距就1.5公里!这,就是缘分啊,兄弟姐妹们!

惺惺相惜

见面聊得很欢快,因为太多相似点:都是开发人员,都有自己的开源项目,都想着怎么让服务能帮助到更多的人。

交谈过程中,了解到他们正在准备Dooring的国际站,对MDFriday的一款主题Saasify比较感兴趣,而且还希望部署到自己的服务器上。

方案设计:AI 一出手,效率高到有点不真实

于是,我跑去找 Cursor(AI 代码助手),它一听就说:“可以用 WebSocket,也可以用 SSE(Server-Side Events)。”

我心想:这不就是单向传输的场景吗? 于是回了一句:“单向的。”

Cursor 立刻调整思路:“那 SSE 方案更合适。”

然后,不出半小时,TA 直接甩给我一套完整的后端代码和测试。抱着将信将疑的态度,我试跑了一下——居然能用!

这是让我震惊的第一个地方:AI 生成的代码,不仅能跑,还能用!

代码能跑,但结构能接受吗?

代码虽然生成了,但作为一个有追求的开发者,我当然不会满足于“能跑”这么低的标准。代码结构如果太混乱,后期维护起来就会很头疼。

因为该项目就是遵循 DDD 架构写的,那生成的代码也得按 DDD(领域驱动设计)的理念,把代码拆分得更清晰一些。

问题来了,让 AI 直接按照 DDD 进行重构,结果发现它需要大量上下文信息,比如:

  • 领域对象的关键定义是什么?
  • 这些对象在当前代码库里如何应用?
  • 他们之间的调用生命周期如何?
  • 适配层、业务层、领域层应该如何划分?

这些信息如果一个个手敲,效率就直线下降,AI 代码生成的高效性就被消耗在上下文补充上了

试了几次,我发现一个痛点:每次用 AI 拆分代码,都得重新输入上下文,费时费力!

让 AI 生成 Prompt,优化 AI 代码能力

那么,有没有办法让 AI 自己总结上下文,让下一次使用时不用再重复敲一遍?

答案是:让 AI 生成 Prompt!

文未有 AI 生成的《项目DDD架构风格指南》 Prompt 实例

我的思路是:

  1. 让 AI 分析当前代码,自动总结出 DDD 相关的代码结构,比如:
    • 领域对象(Entities、Value Objects、Aggregates)
    • 业务逻辑层(Use Cases、Services)
    • 适配层(Repository、DTO、Controller)
  2. 把这些总结存成一个 Prompt 模板。
  3. 下次遇到类似需求,直接让 AI 读取这个 Prompt,引导它按照 DDD 结构生成代码,而不是重新输入一大堆上下文。

这样一来,AI 代码生成的效率就不仅仅是“快”,而是快 + 结构清晰 + 可维护

AI + Prompt = 高效且优雅的开发体验

从这次体验来看,AI 可以快速提供基础代码,但要让它生成高质量的结构化代码,仍然需要指导

而这种指导,不应该每次都靠手动输入,而是应该让 AI 学习代码结构,并生成 Prompt,以便下次自动应用

这才是 AI 代码生成的真正价值——不仅仅是“写代码”,更是“学会怎么写好代码”! 🚀

集成前后端:Cursor 继续发力

后端通了,那就该搞前端了。

我告诉 Cursor,前后端的集成方式是 multipart/form-data,也就是用户先通过 HTTPS 发送表单数据到后端(预览成功的站点信息和用户上传的信息),后端处理并加密存储数据,同时颁发一个 session ID,之后用户再通过 EventSource 监听上传进度。

Cursor 立刻甩给我一套完整的后端API代码,不仅包含了文件处理、加密存储和 session 机制,还额外生成了一组完整的集成测试,让我可以直接验证 API 是否可用。更惊喜的是,它还附带了一个前端测试页面,让我直接试用! (这里也需要手动告诉 Cursor ,当前 API 的设计思路和结构信息)

AI 生成的代码,测试能力也很强

当后端代码写完后,Cursor 自动生成了一整套测试,这一点特别加分!

  • 后端集成测试:涵盖 multipart/form-data 的文件上传、加密存储,以及 session 机制,确保 API 行为符合预期。
  • 端到端测试:Cursor 生成了一个前端页面,模拟用户上传文件的完整流程,并通过 EventSource 实时查看进度,确保前后端联通。

SSE

我直接跑了一下测试——全通过了! 🚀 (有手动调整一些细节。有来有回的体验还是很好的!)

前端开发:4 小时内从 0 到上线

既然后端 API 已经验证可用,那前端的对接就变得非常简单。Cursor 生成了一份 JS 样例代码,封装了 multipart/form-data 上传和 EventSource 监听逻辑。我稍微调整了一下,仅用 4 个小时就完成了前端集成,最终功能顺利上线!

0.2.13

AI 让开发更快、更可靠

这次 AI 代码生成的体验,不仅仅是提高了速度,更重要的是提升了开发质量

  1. 不仅仅是写代码,还能自动生成测试,确保 API 可靠性。
  2. 不仅仅是前后端集成,还能提供完整的端到端测试,大幅减少调试成本。
  3. 不仅仅是加快开发,还能帮助优化代码结构,提高可维护性

这才是 AI 赋能开发的真正价值! 🚀

个人开发的新时代已经到来!

回顾这几天的开发过程,我得出了一个结论:个人开发者的黄金时代,真的来了

从需求确定,到 AI 生成代码,再到测试、优化、重构、上线,整个流程我只用了三天。而且,其中 95% 都是 AI 干的!另外 5% 是我敲的提示词!

可以想象,如果把 AI 用得更溜,比如预先整理上下文提前定义代码结构让 AI 少走弯路,效率还能再提升一大截。

绝了

未来开发模式:从写代码到写提示词

经过这次实践,我意识到,未来的开发模式将发生巨大变化。传统开发的核心是写代码,但未来,我的核心工作将逐渐变成写各种不同类型的 Prompt(提示词),让 AI 按照我的思路去完成任务。

这些提示词可以是:

  • DDD(领域驱动设计)要求:明确实体、聚合、领域服务的设计规范,指导 AI 生成符合架构要求的代码。
  • 当前代码库的架构和设计理念:让 AI 生成的代码能自然融入已有代码,保持风格一致。
  • API 设计标准:区分不同类型的 API,例如普通用户接口和系统管理员接口的差异,并让 AI 直接生成符合标准的代码。
  • 自动化 DevOps 流程:定义代码提交、测试、部署的标准化提示词,让 AI 生成完整的 CI/CD 配置。

如果把这些提示词模块化管理,那么未来开发新功能时,只需要随意组合已有提示词,就能大幅提升开发效率——不仅能加快开发,还能确保代码风格和架构的一致性。

MCP:用 Module Context Protocol 管理 AI 开发流程

正好,我最近研究了 MCP(Module Context Protocol),它可以帮我把不同的提示词模块化管理,形成一个可复用的 Prompt 库,让 AI 更高效地理解开发需求,并生成符合标准的代码。

MCP 让我可以:

  • 结构化管理提示词,比如将 DDD 设计理念、API 规范、代码风格等拆分成不同的模块。
  • 动态组合提示词,根据不同需求灵活选择合适的模块,避免每次从零开始编写 Prompt。
  • 跨项目复用,让 AI 适应不同的代码库,而不需要每次重新训练或调整。

接下来,我计划把这一块也自动化管理起来,让 AI 不仅仅是代码生成工具,而是一个真正理解开发需求的智能助手

所以,现在的个人开发者,不再是单打独斗,而是“人 + AI”双剑合璧!如果你还没试过让 AI 参与你的开发流程,不妨给自己一个机会,或许你会跟我一样,惊叹:

🚀 “天呐,这也太快了吧!” 🚀


AI 写的提示词示例,写得真不错

项目DDD架构风格指南 (Chain of Thought)

1. 当前项目DDD架构分析

通过Chain of Thought方法,让我们分析当前项目的领域驱动设计(DDD)架构风格,以确保新功能遵循一致的模式。

1.1 整体架构层次

项目采用了典型的分层架构,符合DDD的战略设计原则:

internal/
├── domain/         # 领域层:核心业务逻辑和规则
│   ├── content/    # 内容领域
│   ├── admin/      # 管理员领域
│   ├── host/       # 部署主机领域
│   └── ...
├── application/    # 应用层:协调领域对象,实现用例
└── interfaces/     # 接口层:与外部系统交互
    ├── api/        # API接口
    └── ...

这种分层架构确保了:

  • 领域层包含核心业务逻辑,不依赖外部系统
  • 应用层协调领域对象,实现用例
  • 接口层处理与外部系统的交互

1.2 领域层结构分析

每个领域模块(如host、content等)都遵循一致的内部结构:

domain/host/
├── type.go         # 定义领域接口和类型
├── entity/         # 实体定义和实现
│   ├── host.go     # 主实体
│   ├── netlify.go  # 具体实体实现
│   └── scp.go      # 具体实体实现
├── valueobject/    # 值对象定义
│   ├── netlify_config.go
│   └── scp_config.go
└── factory/        # 工厂方法
    └── factory.go

1.3 DDD构建块使用模式

1.3.1 接口定义 (type.go)

type.go文件用于定义领域接口和类型,作为领域契约:

// domain/host/type.go
package host

// Result 是部署结果接口
type Result interface {
    GetID() string
    GetURL() string
    GetMessage() string
    GetSize() int64
}

// Deployer 是部署器接口
type Deployer interface {
    Deploy(localPath string) (Result, error)
}

// 其他特定接口...
type SCPDeployer interface {
    Deployer
    Connect() error
    Close() error
    // ...
}

这些接口定义了领域的行为契约,而不关心具体实现。

1.3.2 实体 (entity/)

实体是具有唯一标识的领域对象,代表业务概念:

// domain/host/entity/host.go
package entity

type Host struct {
    *Netlify
    *SCPHost
}

// Deploy 实现 Deployer 接口
func (h *Host) Deploy(localPath string) (host.Result, error) {
    // 实现逻辑...
}

实体特点:

  • 具有唯一标识
  • 包含业务逻辑和行为
  • 可变状态
  • 实现领域接口

1.3.3 值对象 (valueobject/)

值对象是无标识的不可变对象,通常用于配置和参数:

// domain/host/valueobject/netlify_config.go
package valueobject

type NetlifyConfig struct {
    AccessToken string
    SiteID      string
    // ...
}

func (c *NetlifyConfig) Validate() error {
    // 验证逻辑...
}

值对象特点:

  • 无唯一标识
  • 不可变
  • 通过所有属性值判断相等性
  • 可包含验证逻辑

1.3.4 工厂 (factory/)

工厂负责创建复杂的领域对象,封装创建逻辑:

// domain/host/factory/factory.go
package factory

func NewNetlifyHost(config *valueobject.NetlifyConfig) (*entity.Host, error) {
    netlify, err := entity.NewNetlifyWithConfig(config)
    if err != nil {
        return nil, err
    }
    
    return &entity.Host{
        Netlify: netlify,
    }, nil
}

工厂特点:

  • 封装对象创建逻辑
  • 确保创建的对象处于有效状态
  • 隐藏创建细节

2. 扩展指南:添加新功能

基于上述分析,添加新功能时应遵循以下指南:

2.1 确定领域边界

首先确定新功能属于哪个领域,或是否需要创建新的领域:

internal/domain/newfeature/

2.2 定义领域接口 (type.go)

在新领域中,首先定义接口和类型:

// internal/domain/newfeature/type.go
package newfeature

// 定义核心接口
type Service interface {
    DoSomething(param string) (Result, error)
}

// 定义结果接口
type Result interface {
    GetValue() string
    // ...
}

// 定义其他必要接口...

接口定义原则:

  • 接口应该小而精确
  • 遵循单一职责原则
  • 只包含必要的方法
  • 使用领域语言命名

2.3 实现值对象

创建必要的值对象:

// internal/domain/newfeature/valueobject/config.go
package valueobject

type Config struct {
    // 不可变属性
    Parameter1 string
    Parameter2 int
}

func (c *Config) Validate() error {
    // 验证逻辑
    if c.Parameter1 == "" {
        return errors.New("parameter1 is required")
    }
    return nil
}

// 结果值对象
type OperationResult struct {
    Value string
    // 其他属性...
}

func (r *OperationResult) GetValue() string {
    return r.Value
}

值对象实现原则:

  • 保持不可变性
  • 包含验证逻辑
  • 实现相关接口
  • 不包含业务逻辑

2.4 实现实体

创建实体实现:

// internal/domain/newfeature/entity/feature.go
package entity

import (
    "github.com/mdfriday/hugoverse/internal/domain/newfeature"
    "github.com/mdfriday/hugoverse/internal/domain/newfeature/valueobject"
)

type Feature struct {
    config *valueobject.Config
    // 其他依赖和状态...
}

func NewFeature(config *valueobject.Config) (*Feature, error) {
    if err := config.Validate(); err != nil {
        return nil, err
    }
    
    return &Feature{
        config: config,
    }, nil
}

// 实现Service接口
func (f *Feature) DoSomething(param string) (newfeature.Result, error) {
    // 实现业务逻辑
    
    result := &valueobject.OperationResult{
        Value: "processed: " + param,
    }
    
    return result, nil
}

实体实现原则:

  • 验证构造参数
  • 实现领域接口
  • 包含业务逻辑
  • 保持内部状态一致性

2.5 创建工厂

实现工厂方法:

// internal/domain/newfeature/factory/factory.go
package factory

import (
    "github.com/mdfriday/hugoverse/internal/domain/newfeature/entity"
    "github.com/mdfriday/hugoverse/internal/domain/newfeature/valueobject"
)

func NewFeature(param1 string, param2 int) (*entity.Feature, error) {
    config := &valueobject.Config{
        Parameter1: param1,
        Parameter2: param2,
    }
    
    return entity.NewFeature(config)
}

工厂实现原则:

  • 简化对象创建
  • 封装创建逻辑
  • 返回接口而非具体类型(当适用时)

2.6 更新应用层

在应用层添加新功能的用例:

// internal/application/newfeature.go
package application

import (
    "github.com/mdfriday/hugoverse/internal/domain/newfeature"
    "github.com/mdfriday/hugoverse/internal/domain/newfeature/factory"
)

func (a *App) DoNewFeature(param1 string, param2 int, operationParam string) (newfeature.Result, error) {
    // 1. 创建领域对象
    feature, err := factory.NewFeature(param1, param2)
    if err != nil {
        return nil, err
    }
    
    // 2. 执行领域操作
    return feature.DoSomething(operationParam)
}

2.7 添加接口层实现

最后,在接口层添加API处理程序:

// internal/interfaces/api/handler/handlenewfeature.go
func (s *Handler) NewFeatureHandler(res http.ResponseWriter, req *http.Request) {
    // 1. 解析请求参数
    param1 := req.FormValue("param1")
    param2, _ := strconv.Atoi(req.FormValue("param2"))
    operationParam := req.FormValue("operation")
    
    // 2. 调用应用服务
    result, err := s.app.DoNewFeature(param1, param2, operationParam)
    if err != nil {
        s.res.Error(res, err)
        return
    }
    
    // 3. 返回响应
    s.res.JSON(res, map[string]string{
        "value": result.GetValue(),
    })
}

3. DDD最佳实践总结

3.1 通用原则

  1. 遵循领域语言:使用业务领域的术语命名接口、类和方法
  2. 保持领域纯净:领域层不应依赖基础设施或外部系统
  3. 接口隔离:定义小而精确的接口
  4. 单一职责:每个类只负责一个功能
  5. 封装变化:隐藏实现细节,只暴露必要的接口

3.2 文件组织约定

  • type.go:定义领域接口和类型
  • entity/xxx.go:实现具体实体
  • valueobject/xxx.go:定义值对象
  • factory/factory.go:提供工厂方法

3.3 命名约定

  • 接口名应简洁明了(如DeployerResult
  • 实体名应反映业务概念(如HostNetlify
  • 值对象名应表明其用途(如NetlifyConfig
  • 工厂方法应以New开头(如NewNetlifyHost

4. 总结

当前项目采用了清晰的DDD架构风格,通过明确的分层和领域模型组织代码。添加新功能时,应遵循以下步骤:

  1. type.go中定义领域接口
  2. valueobject/中创建配置和结果值对象
  3. entity/中实现核心业务逻辑
  4. factory/中提供工厂方法
  5. 在应用层协调领域对象
  6. 在接口层处理外部交互

遵循这些指南,可以确保新功能与现有系统保持一致的架构风格,同时保持代码的可维护性和可扩展性。