
spec.md)为唯一真理源,驱动代码、测试、文档自动生成,实现设计先行、可测试性内建与文档永不过期。实践中发现SDD理念先进但落地门槛高、工具链不成熟、历史代码集成难,因此团队当前采用融合策略:以轻量级技术方案模板为输入 + Rules严格约束 + Agent Coding高效实现 + AI自动汇总架构文档,形成兼顾规范性、效率与可维护性的AI辅助编程最佳实践。
▐ 1.1 业务背景
▐ 1.2 AI编程工具的引入
![图片[3]-AI编码实践:从Vibe Coding到SDD-AI Express News](https://www.aiexpress.news/wp-content/uploads/2025/12/20251221210424683-1766322264-120c54e2cfa4495f64ce353b572ce535.png)
▐ 2.1 初识AI编程
// 开发者输入:public List<ItemCardVO> buildItemCards(List<ContentEntity> entities) {List<ItemCardVO> result = new ArrayList<>();// AI自动补全以下代码for (ContentEntity entity : entities) {ItemCardVO itemCard = new ItemCardVO();itemCard.setItemId(entity.getItemId());itemCard.setItemTitle(entity.getTitle());itemCard.setItemImg(entity.getPicUrl());result.add(itemCard);}return result;}
// 原始代码(冗长难读)public String getDiscountText(Long finalPrice, Long nnPrice) {if (finalPrice == null || nnPrice == null) {return "";}if (finalPrice <= nnPrice) {return "";}Long discount = finalPrice - nnPrice;if (discount <= 0) {return "";}String discountYuan = String.valueOf(discount / 100.0);return discountYuan + "元";}// AI重构后(简洁优雅)public String getDiscountText(Long finalPrice, Long nnPrice) {if (finalPrice == null || nnPrice == null || finalPrice <= nnPrice) {return "";}Money discount = Money.ofFen(finalPrice).subtract(Money.ofFen(nnPrice));if (discount.getCent() <= 0) {return "";}return String.format("%s元", discount.getYuan());}
▐ 2.2 初步收益
去年某次商详项目中,代码补全在对象构建、模型转换中减少70-80%的键盘输入。 单方法重构速度提升50%。
减少了查找API文档的时间 避免了拼写错误和语法错误 让开发者更专注于业务逻辑
▐ 2.3 遇到的问题
局限于局部优化:只能帮助完成单个方法或代码片段,无法理解整体业务逻辑 缺乏上下文理解:不了解项目的架构规范和代码风格 无法应对复杂需求:对于跨多个类、多个模块的需求无能为力
![图片[4]-AI编码实践:从Vibe Coding到SDD-AI Express News](https://www.aiexpress.news/wp-content/uploads/2025/12/20251221210424799-1766322264-c9b2c885590dd3a5a6221f90e024253f.png)
需求:实现NN页面红包模块背景:- 需要展示用户可用的红包列表- 红包按门槛从小到大排序实现要求:1. 创建数据服务类 NnRedPacketDataService,查询用户红包2. 创建模块VO NnRedPacketVO,包含红包列表、总金额等字段3. 创建模块构建器 NnRedPacketModuleBuilder,组装数据技术细节:- 数据服务需要实现 DataService<List<FundQueryDTO>> 接口- 数据服务实现类需要依赖FpProvider,并执行红包查询,参数请参考已有实现- 模块构建器需要继承 BaseModuleBuilder<NnRedPacketVO>- 使用 @Component 注解标记为Spring Bean- 遵循项目代码规范请生成完整的代码。
// 1. 数据服务public class NnRedPacketDataService implements DataService<List<FundQueryDTO>> {private FpProvider fpProvider;public List<FundQueryDTO> execute(InvocationContext context, JSONObject req) {// 从配置获取红包池IDString poolIds = req.getString("nnRedPacketPoolIds");List<Long> fundPoolIds = Arrays.stream(poolIds.split(",")).map(Long::parseLong).collect(Collectors.toList());// 查询用户红包return fpProvider.queryUserFundBuyPoolId(context,fundPoolIds,customRuleId,securityCode);}}// 2. 模块VOpublic class NnRedPacketVO {private List<RedPacketItem> redPacketList;private String totalAmount;private String expandText;}// 3. 模块构建器public class NnRedPacketModuleBuilder extends BaseModuleBuilder<NnRedPacketVO> {public String getName() {return "nnRedPacket";}protected NnRedPacketVO doBuild(InvocationContext context) {// 获取红包数据List<FundQueryDTO> funds = ContextUtils.<List<FundQueryDTO>>getBizResult(NnRedPacketDataService.class.getSimpleName(),context,500).orElse(Collections.emptyList());if (CollectionUtils.isEmpty(funds)) {return null;}// 构建VOreturn NnRedPacketVO.builder().redPacketList(buildRedPacketList(funds)).totalAmount(calculateTotalAmount(funds)).build();}private List<RedPacketItem> buildRedPacketList(List<FundQueryDTO> funds) {return funds.stream().map(this::toRedPacketItem).collect(Collectors.toList());}// ... 其他方法}
// 第一次生成(简洁风格)private String buildDiscountText(Money discount) {return String.format("省%s元", discount.getYuan());}// 第二次生成(冗长风格)private String buildDiscountText(Money discount) {BigDecimal yuan = BigDecimal.valueOf(discount.getCent()).divide(BigDecimal.valueOf(100), 2, RoundingMode.HALF_UP);String yuanStr = yuan.stripTrailingZeros().toPlainString();return "省" + yuanStr + "元";}
新手写的Prompt过于简单,AI生成的代码质量差 老手写的Prompt详细但冗长,难以复用 缺乏统一的Prompt模板和最佳实践
没有项目规范:AI不知道项目的代码风格、架构模式、命名规范 没有领域知识:AI不了解淘特导购业务的特定术语和设计模式 没有历史经验:每次都是"零基础"生成代码,无法从历史代码中学习
![图片[5]-AI编码实践:从Vibe Coding到SDD-AI Express News](https://www.aiexpress.news/wp-content/uploads/2025/12/20251221210425624-1766322265-8a5e5de252be88a7cefe68cdec11021d.png)
.aone_copilot/├── rules/│ ├── code-style.aonerule # 代码风格规范│ ├── project-structure.aonerule # 项目结构规范│ └── features.aonerule # 功能实现规范└── tech/├── xx秒杀-技术方案.md # 具体需求的技术方案└── xx红包模块-技术方案.md
# 代码风格规范## Java代码规范- 类名使用大驼峰命名法(PascalCase)- 方法名和变量名使用小驼峰命名法(camelCase)- 常量使用全大写,单词间用下划线分隔(CONSTANT_CASE)## 空值判断- 集合判空统一使用:CollectionUtils.isEmpty() 或 isNotEmpty()- 字符串判空统一使用:StringUtils.isBlank() 或 isNotBlank()- 对象判空统一使用:Objects.isNull() 或 Objects.nonNull()## 日志规范- 使用 LogUtil 工具类记录日志- 错误日志格式:LogUtil.error("类名, 方法名, 错误描述, 关键参数={}", param, exception)## 注解使用- Service类使用 @Component 注解- 数据服务实现 DataService<T> 接口- 模块构建器继承 BaseModuleBuilder<T>
# 项目结构规范## 包结构com.alibaba.aladdin.app/├── module/ # 模块构建器│ ├── nn/ # NN业务模块│ ├── seckill/ # 秒杀业务模块│ └── common/ # 通用模块├── domain/ # 领域对象│ ├── module/ # 模块VO(继承ModuleObject)│ └── [业务名]/ # 业务领域对象(BO、DTO)├── dataservice/impl/ # 数据服务实现└── provider/ # 外部服务提供者## 命名规范- 数据服务:[业务名]DataService(如 NnRedPacketDataService)- 模块构建器:[业务名]ModuleBuilder(如 NnFeedsModuleBuilder)- 模块VO:[业务名]VO(如 NnRedPacketVO)- 业务BO:[业务名]BO(如 NnRoundFeatureBO)
# 功能实现规范## 数据服务层- 必须实现 DataService<T> 接口- 使用 注解- execute方法的第一个参数是 InvocationContext- execute方法的第二个参数是 JSONObject businessReq示例:```javapublic class NnRedPacketDataService implements DataService<List<FundQueryDTO>> {public List<FundQueryDTO> execute(InvocationContext context, JSONObject businessReq) {// 实现逻辑}}```## 模块构建器- 必须继承 BaseModuleBuilder- 使用 注解- 实现 getName()、doBuild()、bottomTransform() 三个方法- 通过 ContextUtils.getBizResult() 获取数据服务结果示例:```public class NnRedPacketModuleBuilder extends BaseModuleBuilder<NnRedPacketVO> {public String getName() {return "nnRedPacket";}protected NnRedPacketVO doBuild(InvocationContext context) {List<FundQueryDTO> funds = ContextUtils.<List<FundQueryDTO>>getBizResult(NnRedPacketDataService.class.getSimpleName(),context,500).orElse(Collections.emptyList());// 构建逻辑}}```
# 业务定义NN红包模块用于展示用户在NN业务场景下可用的红包列表。# 业务领域对象无(复用 FundQueryDTO)# 模块领域对象| 对象含义 | 实现方案 | 属性及类型 ||---------|---------|-----------|| NN红包模块VO | 新增 | 1. redPacketList:List<RedPacketItem> - 红包列表<br>2. totalAmount:String - 总金额<br>3. expandText:String - 展开文案 |# 数据服务层| 数据服务定义 | 实现方案 | execute ||------------|---------|---------|| NN红包查询服务 | 新增 | 1. 从配置获取红包池ID列表<br>2. 调用FpProvider查询用户红包<br>3. 过滤可用红包(状态=2,未过期)<br>4. 返回红包列表 |# 模块构建器| 模块构建器定义 | 实现方案 | doBuild逻辑 ||--------------|---------|-------------|| NN红包模块构建器 | 新增 | 1. 获取红包数据<br>2. 过滤门槛>20元的红包<br>3. 按门槛从小到大排序<br>4. 构建VO |
所有生成的代码都遵循统一的命名规范 项目结构清晰,模块划分明确 代码风格保持一致
技术方案填写时间从2小时降低到20分钟 代码实现时间从1天降低到2小时(需要人工收尾)
技术方案成为团队共同语言 Code Review效率提升50% 新人上手时间从1周降低到2天
需求理解不够深入:AI仍然是基于技术方案"翻译"成代码,对业务语义理解有限 测试质量参差不齐:虽然能生成单测,但测试用例的通过率和覆盖度仍需人工把关 文档滞后:代码变更后,文档更新容易遗漏 依赖关系管理:对于复杂的模块依赖关系,AI处理不够优雅
![图片[6]-AI编码实践:从Vibe Coding到SDD-AI Express News](https://www.aiexpress.news/wp-content/uploads/2025/12/20251221210425133-1766322265-f3b038d598a72851c6a25b9fc4d5f86e.png)
所有的代码、测试、文档都从规格生成 规格即文档,文档永不过期
先用自然语言描述"做什么"(规格) 再让AI生成"怎么做"(代码)
规格中明确定义测试用例 自动生成完整的单元测试
iflow + qwen3 coder plus + spec kit qwen + qwen3 coder plus + spec kit
├── .specify/│ ├── memory/│ │ └── constitution.md│ ├── scripts/│ └── templates/├── specs/│ └── 001-nn-redpacket-module/│ ├── checklists/│ │ └── requirements.md│ ├── contracts/│ │ └── api-contract.md│ ├── data-model.md│ ├── plan.md│ ├── quickstart.md│ ├── research.md│ └── spec.md└── req/└── nn-redpacket.md
## 核心原则### I. 模块化服务架构所有服务必须遵循模块化设计原则,具有明确的关注点分离和定义良好的接口。每个模块应具有单一职责并可独立部署。模块必须以松耦合和高内聚的方式设计,以增强可维护性和可扩展性,遵循最小依赖原则。### II. 阿里巴巴开发标准所有代码必须遵循阿里巴巴Java开发指南(基于阿里巴巴Java编码规范)。这包括命名约定、异常处理实践、日志标准、安全最佳实践和性能优化模式。代码必须遵守样式一致性要求,以保持代码库的统一性。### III. 质量保证实践全面测试是强制性的:对所有业务逻辑进行单元测试,对服务交互进行集成测试,对API兼容性进行合同测试。代码覆盖率必须保持在80%以上,特别关注关键业务路径。代码质量工具必须集成到CI/CD管道中以执行标准,遵循阿里巴巴开发规范以确保质量和可靠性。### IV. 模块设计原则遵循单一职责原则,每个模块都有一个明确的目的。模块必须以松耦合和高内聚的方式设计,遵循关注点分离原则。模块边界应与业务能力和领域上下文对齐。所有模块都遵循最小依赖原则,仅导入必要的依赖项以减少系统复杂性。### V. 项目架构设计原则本项目采用分层架构设计,通过模块化组织代码,支持淘特投放业务的各种场景需求。架构层次包括:1. **接入层**:处理请求接入和协议转换2. **解决方案层**:业务解决方案的统一入口3. **子解决方案层**:细粒度的业务处理能力4. **模块构建层**:按业务功能划分的模块构建器5. **数据服务层**:负责各种业务数据的获取、处理和封装6. **外部服务层**:负责调用外部服务并进行模型转换7. **领域模型层**:定义核心业务对象和数据传输对象8. **基础设施层**:包含基础组件和框架封装9. **通用模块层**:公共组件和工具类### VI. 依赖管理遵循最小依赖原则:每个模块应只拥有其实际需要的依赖项。避免模块之间的循环依赖。使用依赖注入实现松耦合。定期审核和更新依赖项以最小化安全漏洞。这确保了可维护和高效的代码结构。### VII. 代码风格一致性在整个项目中保持一致的代码风格,使用标准化的格式化规则。所有代码在合并前必须通过静态分析检查。一致地遵循设计模式,并对与标准实践的任何偏差提供清晰的证明。这确保了统一的代码规范和样式,符合项目标准。### VIII. Speckit中文本地化所有speckit相关文件、文档和配置都应使用中文,以支持本地开发团队。`.specify/`和`specs/`目录中的文件和相关speckit构件必须使用中文,以便本地开发人员更好地理解和维护,同时应为可能服务国际市场面向用户的组件保留国际化支持。## 安全和合规要求所有代码必须符合阿里巴巴的安全标准,并在部署前进行强制性安全审查。必须为所有暴露的端点实现适当的身份验证和授权。敏感数据必须根据内部合规要求进行处理。必须扫描依赖项中的安全漏洞。## 开发工作流程1. 所有代码更改必须遵循标准的阿里巴巴开发工作流程:功能分支、代码审查、自动化测试和CI/CD管道验证。拉取请求必须通过所有测试并获得指定审阅者的批准后才能合并。除非明确批准进行具有迁移计划的破坏性更改,否则所有更改必须向后兼容。每次更改都必须遵循模块设计原则并保持代码风格一致性。2. 所有操作不要创建新分支,而是在当前分支下进行3. 代码生成必须遵循code-generation-prompt.aonerule文件## 治理本宪法凌驾于所有其他开发实践之上,必须在存储库中的所有工作中遵循。对本宪法的任何修改都需要正式文档、团队批准和迁移计划。所有PR和代码审查必须验证是否符合这些原则。
# NN红包模块规格说明## 功能概述NN红包模块用于在NN频道页面展示用户可用的红包列表,帮助用户了解可以使用的优惠。## 功能需求### FR-1: 红包数据获取**描述:** 系统应该能够查询用户在当前NN业务场景下可用的红包**前置条件:**- 用户已登录- 配置了红包池ID(fundPoolIds)- 配置了规则id(customRuleId)- 配置了securityCode**输入:**- userId:用户ID- fundPoolIds:红包池ID列表- customRuleId:自定义规则ID- securityCode:安全码**处理逻辑:**1. 调用FpProvider.queryUserFundBuyPoolId()查询红包2. 过滤条件:- 红包状态(payStatus)= 2(可使用)- 红包未过期(当前时间在startTime和endTime之间)- 红包门槛 <= 配置的amountThreshold(默认20元)**输出:**- 返回符合条件的红包列表**异常处理:**- 如果FpProvider调用失败,返回空列表- 如果用户未登录,返回空列表.........**处理逻辑:**1. 如果红包列表为空,不展示模块(返回null)2. 构建NnRedPacketVO:- redPacketList:转换每个红包为RedPacketItem- totalAmount:计算所有红包金额总和- expandText:从配置获取展开文案**输出:** NnRedPacketVO## 非功能需求### NFR-1: 性能要求- 红包查询超时时间:500ms- 如果超时,返回空列表,不影响页面其他模块### NFR-2: 可扩展性- 支持配置不同的红包池ID- 支持配置不同的门槛限制## 测试用例### TC-1: 正常流程 - 有可用红包**前置条件:**- 用户ID:123456- 配置的红包池ID:[1001, 1002]- FpProvider返回2个可用红包:- 红包1:金额5元,门槛15元- 红包2:金额10元,门槛25元**执行步骤:**1. 调用 doBuild(context)**预期结果:**- 返回的VO不为null- redPacketList包含2个红包- totalAmount = "15.00"(5 + 10)- 红包按门槛排序(红包1在前)### TC-2: 边界条件 - 红包门槛超限**前置条件:**- FpProvider返回1个红包,门槛25元- 配置的amountThreshold = 20元(2000分)**预期结果:**- 返回null(因为门槛超限,红包被过滤)......
public class NnRedPacketDataService implements DataService<List<FundQueryDTO>> {private FpProvider fpProvider;public List<FundQueryDTO> execute(InvocationContext context, JSONObject businessReq) {long userId = context.getUserId();if (userId <= 0) {return Collections.emptyList();}// 获取配置String poolIdsStr = businessReq.getString("nnRedPacketPoolIds");List<Long> fundPoolIds = parsePoolIds(poolIdsStr);Long customRuleId = businessReq.getLong("customRuleId");String securityCode = businessReq.getString("securityCode");// 查询红包List<FundQueryDTO> funds = fpProvider.queryUserFundBuyPoolId(context, fundPoolIds, customRuleId, securityCode);if (CollectionUtils.isEmpty(funds)) {return Collections.emptyList();}// 过滤可用红包(按规格FR-1的过滤条件)Long amountThreshold = businessReq.getLong("amountThreshold", 2000L);return funds.stream().filter(fund -> fund.getPayStatus() == 2) // 可使用状态.filter(fund -> isNotExpired(fund)) // 未过期.filter(fund -> fund.getAmountThreshold() <= amountThreshold) // 门槛限制.collect(Collectors.toList());}private boolean isNotExpired(FundQueryDTO fund) {long now = System.currentTimeMillis();return fund.getStartTime() <= now && now <= fund.getEndTime();}// ... 其他方法}
public class NnRedPacketModuleBuilder extends BaseModuleBuilder<NnRedPacketVO> {public String getName() {return "nnRedPacket";}protected NnRedPacketVO doBuild(InvocationContext context) {// 获取红包数据(FR-1)List<FundQueryDTO> funds = ContextUtils.<List<FundQueryDTO>>getBizResult(NnRedPacketDataService.class.getSimpleName(),context,500).orElse(Collections.emptyList());// 如果无可用红包,不展示模块(FR-3)if (CollectionUtils.isEmpty(funds)) {return null;}// 红包排序(FR-2)List<FundQueryDTO> sortedFunds = sortFunds(funds, context);// 构建VO(FR-3)return NnRedPacketVO.builder().redPacketList(buildRedPacketList(sortedFunds)).totalAmount(calculateTotalAmount(sortedFunds)).expandText(getExpandText(context)).build();}/*** 红包排序:NN专属红包优先,其次按门槛从小到大* 对应规格 FR-2*/private List<FundQueryDTO> sortFunds(List<FundQueryDTO> funds, InvocationContext context) {JSONObject extraParams = getExtraParams(context);String nnPoolIdsStr = extraParams.getString("nnRedPacketPoolIds");Set<Long> nnPoolIds = parsePoolIds(nnPoolIdsStr).stream().collect(Collectors.toSet());return funds.stream().sorted(Comparator.comparing((FundQueryDTO fund) ->nnPoolIds.contains(fund.getFromFundId()) ? 0 : 1).thenComparing(FundQueryDTO::getAmountThreshold)).collect(Collectors.toList());}// ... 其他方法}
public class NnRedPacketModuleBuilderTest {private InvocationContext context;private NnRedPacketDataService dataService;private NnRedPacketModuleBuilder builder;/*** 测试用例 TC-1: 正常流程 - 有可用红包*/public void testBuild_WithAvailableFunds_ShouldReturnVO() {// 准备数据List<FundQueryDTO> mockFunds = Arrays.asList(createFund(1L, 500L, 1500L), // 5元,门槛15元createFund(2L, 1000L, 2500L) // 10元,门槛25元);// Mockwhen(dataService.execute(any(), any())).thenReturn(mockFunds);mockContext(context, "nnRedPacketPoolIds", "1,2");mockBizResult(context, NnRedPacketDataService.class.getSimpleName(), mockFunds);// 执行NnRedPacketVO result = builder.doBuild(context);// 验证(按规格预期结果)assertNotNull(result);assertEquals(2, result.getRedPacketList().size());assertEquals("15.00", result.getTotalAmount());// 验证排序:门槛低的在前assertEquals(1500L, result.getRedPacketList().get(0).getAmountThreshold());}/*** 测试用例 TC-2: 边界条件 - 红包门槛超限*/public void testBuild_ThresholdExceeded_ShouldReturnNull() {// 准备数据:门槛25元,超过配置的20元List<FundQueryDTO> mockFunds = Arrays.asList(createFund(1L, 500L, 2500L));// Mock(配置amountThreshold=2000,即20元)JSONObject businessReq = new JSONObject();businessReq.put("amountThreshold", 2000L);when(dataService.execute(any(), eq(businessReq))).thenReturn(Collections.emptyList());mockBizResult(context, NnRedPacketDataService.class.getSimpleName(), Collections.emptyList());// 执行NnRedPacketVO result = builder.doBuild(context);// 验证(按规格预期结果)assertNull(result);}/*** 测试用例 TC-3: 异常场景 - FpProvider返回null*/public void testBuild_ProviderReturnsNull_ShouldReturnNull() {// Mockwhen(dataService.execute(any(), any())).thenReturn(null);mockBizResult(context, NnRedPacketDataService.class.getSimpleName(), null);// 执行NnRedPacketVO result = builder.doBuild(context);// 验证(按规格预期结果)assertNull(result);}/*** 测试用例 TC-4: 异常场景 - 用户未登录*/public void testBuild_UserNotLogin_ShouldReturnNull() {// Mock:userId = 0when(context.getUserId()).thenReturn(0L);when(dataService.execute(any(), any())).thenReturn(Collections.emptyList());mockBizResult(context, NnRedPacketDataService.class.getSimpleName(), Collections.emptyList());// 执行NnRedPacketVO result = builder.doBuild(context);// 验证(按规格预期结果)assertNull(result);}// 辅助方法private FundQueryDTO createFund(Long id, Long amount, Long threshold) {FundQueryDTO fund = new FundQueryDTO();fund.setFundId(id);fund.setAvailableAmount(amount);fund.setAmountThreshold(threshold);fund.setPayStatus(2); // 可使用fund.setStartTime(System.currentTimeMillis() - 3600000); // 1小时前开始fund.setEndTime(System.currentTimeMillis() + 3600000); // 1小时后结束return fund;}}
所有代码都严格遵循规格说明,消除了理解偏差 不同开发者实现相同规格,代码风格完全一致 代码变更时,必须先更新规格,保证文档与代码同步
产品、开发、测试对需求的理解高度一致 减少了需求理解偏差导致的返工
自动生成的测试用例覆盖了所有正常和异常流程 测试用例与规格说明一一对应,确保完整性 边界条件和异常场景都有明确的测试用例
Mock方式规范统一,符合项目最佳实践 断言准确全面,不会遗漏关键验证点 测试代码可读性好,易于维护
规格说明就是最准确的文档 任何变更都先更新规格,再同步代码 新人通过阅读规格说明就能快速理解功能
修改规格时,清晰知道影响哪些代码模块 依赖关系在规格中明确定义 重构时可以基于规格验证正确性
代码结构清晰,层次分明 注释完整准确,与规格保持一致 命名规范统一,易于理解
新人通过阅读规格说明快速上手 跨团队协作时,规格成为统一语言 历史需求回溯更容易,规格即完整记录
新手往往写不好规格,过于技术化或过于模糊 规格模板虽然有,但如何填写仍需要经验 不合格的规格对后面的代码实现影响
规格解析不准确 AI有时无法正确理解规格中的复杂逻辑 需要用非常精确的语言描述,稍有歧义就可能理解错误 代码生成质量不稳定 相同的规格,不同时间生成的代码质量差异大 有时生成的代码过于冗长,有时又过于简化 增量更新困难 规格修改后,很难做到只更新变化的部分 往往需要重新生成整个文件,导致手工修改的部分丢失
历史代码缺乏规格说明,无法纳入SDD体系 新老代码风格混杂,维护成本反而增加 团队一部分人用SDD,一部分人用传统方式,协作困难
写出合格的第一份规格说明,平均需要3-5次迭代 老员工接受度较低,认为"还不如直接写代码快"
✅ 全新的项目或模块 ✅ 核心业务逻辑,需要长期维护 ✅ 复杂度高,需要详细设计的功能 ✅ 多人协作的大型需求 ✅ 对质量要求极高的场景
❌ 简单的工具函数或配置修改 ❌ 快速验证的实验性功能 ❌ 一次性的临时需求 ❌ 对现有代码的小修改
![图片[7]-AI编码实践:从Vibe Coding到SDD-AI Express News](https://www.aiexpress.news/wp-content/uploads/2025/12/20251221210425429-1766322265-bc163e9bb40492a52b99e08de1c56fbf.png)
用Rules约束AI 用技术方案指导实现 用Agentic Coding快速迭代 用AI汇总文档保持同步
[需求名称]-技术方案# 业务定义[简要描述业务背景和目标,1-2句话]# 业务领域对象[如果需要新增/修改BO或DTO,在此说明]# 模块领域对象[需要新增/修改的VO对象]| 对象含义 | 实现方案 | 属性及类型 ||---------|---------|-----------|| [对象名] | 新增/修改 | 1. 字段1:类型 - 说明<br>2. 字段2:类型 - 说明 |# 数据服务层[需要新增/修改的数据服务]| 数据服务定义 | 实现方案 | execute逻辑 ||------------|---------|-----------|| [服务名] | 新增/复用 | 1. 步骤1<br>2. 步骤2 |# 模块构建器[需要新增/修改的模块构建器]| 模块构建器定义 | 实现方案 | doBuild逻辑 ||--------------|---------|-------------|| [构建器名] | 新增/修改 | 1. 获取数据<br>2. 处理逻辑<br>3. 构建VO |
比SDD规格更轻量,编写时间从2小时降低到30分钟 比纯Agentic Coding更规范,有明确的结构约束 聚焦于"做什么",而非"怎么做"(实现细节交给AI)
完成需求开发 → 提交AI:"将本次代码逻辑汇总到汇总文档" → AI分析代码 → AI更新文档我刚完成了NN红包模块的开发,请分析以下代码:- NnRedPacketDataService.java- NnRedPacketModuleBuilder.java- NnRedPacketVO.java然后将其业务逻辑汇总到"NN业务整体架构与逻辑文档.md"中,确保:1. 描述模块的核心功能和业务价值2. 说明数据流转过程3. 列出关键的业务规则和判断逻辑4. 保持与现有文档的风格一致
NN业务整体架构与逻辑文档# 一、业务概述[业务背景、目标、核心价值]# 二、整体架构## 2.1 技术架构[分层架构图、技术栈]## 2.2 模块组成[各个模块的功能和关系]# 三、核心模块详解## 3.1 NN Feeds模块### 3.1.1 功能说明[模块的核心功能]### 3.1.2 数据流转[数据从哪里来,经过哪些处理,最终输出什么]### 3.1.3 关键逻辑[重要的业务规则、计算逻辑、判断条件]### 3.1.4 代码位置[对应的类和方法]## 3.2 NN红包模块[类似结构]## 3.3 NN吊钩层模块[类似结构]# 四、数据服务层[各个数据服务的功能和依赖]# 五、关键流程[重要的业务流程时序图]# 六、配置说明[配置项说明]# 七、扩展点[未来可能的扩展方向]
## 3.2 NN红包模块### 3.2.1 功能说明NN红包模块用于在NN频道页面展示用户可用的红包列表,帮助用户了解可以使用的优惠,提升转化率。### 3.2.2 数据流转用户请求 → NnRedPacketDataService→ 调用FpProvider查询用户红包→ 过滤可用红包(状态=2,未过期,门槛<=20元)→ 返回红包列表↓NnRedPacketModuleBuilder→ 获取红包数据→ 红包排序(NN专属优先,门槛从小到大)→ 构建NnRedPacketVO→ 返回前端
#### 3.2.3 关键逻辑**1. 红包过滤规则**```java// 只展示满足以下条件的红包:// 1. 状态为可使用(payStatus = 2)// 2. 未过期(当前时间在startTime和endTime之间)// 3. 门槛 <= 配置的amountThreshold(默认20元)if (fund.getPayStatus() != 2) return false;if (fund.getStartTime() > now || now > fund.getEndTime()) return false;if (fund.getAmountThreshold() > amountThreshold) return false;**2. 红包排序规则**```java// 排序规则:// 1. NN专属红包(配置的nnRedPacketPoolIds)优先// 2. 其次按门槛从小到大排序funds.stream().sorted(Comparator.comparing(fund -> nnPoolIds.contains(fund.getFromFundId()) ? 0 : 1).thenComparing(FundQueryDTO::getAmountThreshold))**3. 总金额计算**```java// 计算所有可用红包的金额总和String totalAmount = funds.stream().map(FundQueryDTO::getAvailableAmount).reduce(0L, Long::sum).map(PriceUtils::getPriceFenToYuan).orElse("0.00");#### 3.2.4 代码位置- 数据服务:`NnRedPacketDataService`- 位置:`dataservice/impl/nn/NnRedPacketDataService.java`- 核心方法:`execute(InvocationContext, JSONObject)`- 模块构建器:`NnRedPacketModuleBuilder`- 位置:`module/nn/NnRedPacketModuleBuilder.java`- 核心方法:`doBuild(InvocationContext)`、`sortFunds(List<FundQueryDTO>)`- 模块VO:`NnRedPacketVO`- 位置:`domain/module/nn/NnRedPacketVO.java`#### 3.2.5 配置项```json{"nnRedPacketPoolIds": "1001,1002,1003", // NN专属红包池ID"amountThreshold": 2000, // 红包门槛上限(分)"expandText": "展开查看更多" // 展开文案}

初期探索让我们认识到AI在编码辅助方面的潜力,但也暴露了缺乏规范指导的问题; Agentic Coding提升了功能实现的完整性,但可延续性和一致性仍有不足; 基于规则的模式有效解决了代码规范和架构一致性问题,成为当前的主要实践方式; SDD尝试虽然在理念上很有价值,但在实际应用中还需要进一步完善。
完善工具链:改进Spec Kit等工具,提升自动化能力 优化流程整合:更好地将SDD模式与现有开发流程结合 降低学习成本:通过培训和实践案例帮助团队成员适应新模式 持续改进规则:根据实践经验不断完善规则定义
![图片[9]-AI编码实践:从Vibe Coding到SDD-AI Express News](https://www.aiexpress.news/wp-content/uploads/2025/12/20251221210426501-1766322266-e3401a10e2c9acb6604fa383216f9834.png)
本文作者式遂,来自淘天集团-淘特用户技术团队。团队主要负责淘宝行业&淘特C端链路的研发工作,包含:搜索推荐、互动游戏、导购、交易等基础服务及创新业务。当下我们积极拥抱AI时代,探索智能化在研发提效和业务场景中的无限可能。技术不只是工具,更是为用户创造价值的力量。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END












暂无评论内容