1. 项目缘起与整体设计思路
1.1 为什么选宠物生命周期管理这个方向
养宠物这件事,表面上看是喂食、遛弯、看病,实际上背后是一条完整的时间线:领养或购买、日常喂养、疫苗接种、驱虫、体检、发情期管理、配种或绝育、孕期护理、生产、幼崽成长、老年照护,直到最后的临终关怀和纪念。每一个阶段都有不同的记录需求、提醒需求和数据管理需求。市面上大多数宠物类App只做了其中一小块,比如单纯记疫苗、单纯做社区、单纯卖货,真正把“生命周期”这条主线串起来的工具并不多。
我这次想做的事情,就是用AI辅助编码的方式,从零开始搭建一个覆盖宠物全生命周期的管理应用。选择这个方向有几个原因:第一,业务模型足够复杂,能真正检验AI在项目搭建中的能力边界;第二,需求场景清晰,每个阶段该做什么事情是有行业共识的,不需要凭空捏造;第三,数据关系有层次,宠物、主人、事件、提醒、健康记录之间是多对多关系,适合用来演示从数据建模到界面呈现的完整链路。
这个项目适合谁参考?如果你已经会用AI辅助写代码,但每次都是从单个文件、单个函数开始,不知道怎么让AI帮你把一整个项目从空目录搭到能跑起来,那这篇内容就是写给你的。如果你是完全零基础,也没关系,我会把每一步的操作意图和判断依据都讲清楚,你跟着做也能跑通。
1.2 技术选型与整体架构决策
在动手之前,我先确定了技术栈。这里的选择逻辑不是“哪个最流行”,而是“哪个最适合让AI参与生成,同时后期维护成本最低”。
前端我选了React Native + Expo的组合。理由很直接:宠物管理App的核心使用场景在手机端,需要推送提醒、拍照记录、定位遛弯轨迹这些能力。Expo 把原生模块的配置复杂度降到了最低,AI生成代码时不容易在原生配置环节卡住。而且 Expo 的热更新和预览机制,让我可以在手机实机上快速验证AI生成的界面效果,不用每次都走完整的打包流程。
后端我选了Node.js + Fastify + SQLite(开发阶段)/ PostgreSQL(生产阶段)。Fastify 的插件体系清晰,路由定义简洁,AI生成路由代码时出错率低。数据库方面,开发阶段用 SQLite 可以零配置启动,等数据模型稳定后再迁移到 PostgreSQL,迁移成本可控。
状态管理用Zustand,不用 Redux。原因很简单:Redux 的样板代码太多,AI生成时容易在 action、reducer、selector 之间产生不一致,而 Zustand 的 store 定义就是一个普通函数,AI理解起来更直接,生成结果也更稳定。
AI编码工具方面,我使用的是 Claude Code 的命令行交互模式。它的优势在于可以读取整个项目目录的上下文,理解文件之间的依赖关系,而不是只盯着当前打开的那个文件。这一点在搭建新项目时特别关键,因为新项目最大的问题就是“文件之间还没有建立关联”,AI如果只看单个文件,很容易生成互相不匹配的代码。
整体架构分为四层:数据层(数据库表结构与迁移脚本)、服务层(业务逻辑与API路由)、状态层(前端数据缓存与同步)、视图层(页面组件与交互)。每一层我都会让AI先给出方案,我审核调整后再让它生成具体代码。这个“先方案后代码”的顺序非常重要,后面会详细展开。
1.3 让AI参与项目搭建的正确姿势
很多人用AI写代码的方式是:打开对话框,输入“帮我写一个宠物管理App”,然后期待它直接吐出一个完整项目。这种做法几乎必然失败,因为AI不知道你的技术栈偏好、不知道你的数据模型、不知道你的界面风格,它只能按照训练数据里最常见的模式去猜,猜出来的结果往往和你的预期差很远。
我的做法是分阶段、分层次、带约束地让AI参与。具体来说,把整个项目搭建过程拆成六个阶段:需求梳理与实体识别、数据模型设计、API接口定义、前端页面结构规划、核心功能实现、联调与问题排查。每个阶段只让AI做一件事,做完之后我审核确认,再进入下一阶段。
在每个阶段给AI的指令中,我都会包含三个要素:当前阶段的明确目标、上一阶段的产出作为输入、本阶段的约束条件。比如在设计数据模型时,我会把需求梳理阶段产出的实体列表和关系描述贴给AI,同时约束它“使用 Prisma schema 语法,所有表必须包含 createdAt 和 updatedAt 字段,外键关系必须显式声明”。
这样做的好处是,AI的每次输出都是建立在我已经确认过的上下文之上,不会出现“前面说要用A方案,后面生成B方案代码”的割裂情况。而且分阶段之后,每个阶段的输出量都不大,我审核起来也快,发现问题可以立即纠正,不会等到最后才发现整体方向偏了。
2. 核心细节解析与实操要点
2.1 需求梳理阶段:让AI帮你把模糊想法变成实体清单
项目刚开始的时候,我脑子里只有“宠物生命周期管理”这个大方向,具体要管哪些东西、怎么管,其实并不清晰。这时候直接让AI写代码是灾难,因为它会按照自己的理解去补全需求,补出来的东西大概率不是我想要的。
我的做法是先自己做一轮头脑风暴,把能想到的所有和宠物相关的事件、记录、提醒都列出来,不用管顺序和分类,先写下来。比如:领养日期、品种、性别、绝育状态、疫苗记录、驱虫记录、体重变化、体检报告、用药记录、发情周期、配种记录、孕期检查、生产记录、幼崽信息、日常喂食、遛弯记录、洗护记录、纪念日、临终关怀。
然后我把这份原始清单交给AI,让它做三件事:第一,把清单中的条目归类到不同的生命周期阶段;第二,识别出哪些是实体(需要独立建表的对象),哪些是实体的属性;第三,指出清单中缺失但生命周期管理常见的关键项。
这一步AI的表现很关键。实测下来,它在“识别缺失项”上特别有价值。比如我漏掉了“宠物与主人的多对多关系”(一只宠物可能有多个主人,一个人也可能有多只宠物),AI在分析时主动提出来了。还有“事件与提醒的关联关系”,我原本把提醒当成独立功能,AI指出提醒应该挂在具体事件上,比如疫苗事件产生疫苗提醒,这样数据关系更清晰。
这个阶段的产出是一份实体关系清单,格式大概是这样的:
- 实体:宠物、主人、宠物主人关系、生命周期事件、健康记录、提醒、附件
- 宠物属性:名称、品种、性别、出生日期、领养日期、绝育状态、当前体重、头像
- 事件属性:事件类型、发生时间、备注、关联宠物、关联附件
- 提醒属性:提醒时间、提醒内容、关联事件、完成状态
注意:这个阶段千万不要让AI直接生成代码或建表语句。一旦进入代码层面,讨论就会被语法细节带偏,而需求层面的遗漏反而被忽略。先把实体和关系理清楚,后面所有工作都是在这个基础上展开的。
2.2 数据模型设计:从实体清单到可执行的建表方案
实体清单确认之后,下一步是把它转化成数据库表结构。我用的工具是 Prisma,因为它的 schema 语法接近自然语言,AI生成和人工审核都比较容易。
给AI的指令是这样的:“基于以下实体清单,生成 Prisma schema。要求:每张表包含 id(自增主键)、createdAt、updatedAt;宠物与主人通过中间表建立多对多关系;事件表通过 petId 外键关联宠物;提醒表通过 eventId 外键关联事件;所有日期字段使用 DateTime 类型;枚举类型用 Prisma enum 定义。”
AI生成的 schema 初稿基本可用,但有几个地方需要调整。第一个问题是它把“事件类型”直接写成了字符串字段,没有用 enum。我让它改成 enum,因为事件类型是有限集合(疫苗、驱虫、体检、用药、发情、配种、生产、洗护、纪念日),用 enum 可以在数据库层面做约束,避免脏数据。
第二个问题是它给“体重”字段用了 Float 类型。我改成了 Decimal,因为体重记录需要精确到小数点后两位,Float 在某些情况下会有精度丢失。这个细节AI不会主动考虑,需要根据业务特点来判断。
第三个问题是索引。AI生成的 schema 默认没有加索引,但宠物管理App的高频查询是“某只宠物的所有事件按时间倒序排列”,所以我在事件表的 petId 和发生时间上加了复合索引。这个优化在数据量小的时候看不出差别,但事件记录积累到几千条之后,查询速度差异就很明显了。
调整后的核心表结构大概是这样的:
model Pet { id Int @id @default(autoincrement()) name String breed String? gender Gender birthDate DateTime? adoptDate DateTime? neutered Boolean @default(false) currentWeight Decimal? @db.Decimal(5, 2) avatar String? owners PetOwner[] events Event[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model Event { id Int @id @default(autoincrement()) petId Int pet Pet @relation(fields: [petId], references: [id]) type EventType occurredAt DateTime note String? attachments Attachment[] reminders Reminder[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([petId, occurredAt]) } enum EventType { VACCINE DEWORM CHECKUP MEDICATION ESTRUS MATING PREGNANCY BIRTH GROOMING ANNIVERSARY } enum Gender { MALE FEMALE UNKNOWN }提示:Prisma 的 migrate 命令会根据 schema 自动生成迁移文件,但在开发阶段我建议先用
prisma db push快速同步结构,等模型稳定后再生成正式迁移文件。这样改字段的时候不用反复创建迁移记录,效率高很多。
2.3 API接口定义:先定契约再写实现
数据模型确定之后,下一步是定义API接口。这里我踩过一个坑:一开始我让AI直接写路由实现,结果它写出来的接口路径和前端调用对不上,参数格式也不一致,联调的时候改了半天。
后来我调整了策略:先让AI生成一份API契约文档,包含每个接口的路径、方法、请求参数、响应格式、错误码。这份文档确认之后,再让AI按照文档去实现路由。这样前后端就有了共同的依据,不会出现“各写各的”的情况。
接口按资源划分,核心的有这几组:
/api/pets:宠物的增删改查/api/pets/:id/events:某只宠物的事件列表与创建/api/events/:id/reminders:某个事件的提醒管理/api/pets/:id/health-stats:健康数据统计(体重趋势、疫苗完成率等)/api/owners:主人信息管理
每组接口的响应格式统一为{ code, data, message }结构,code 为 0 表示成功,非 0 表示业务错误。这个统一格式是让AI在生成每个路由时都遵守的约束,避免出现有的接口返回数组、有的返回对象、有的直接抛异常的情况。
在定义接口时,有一个细节值得展开说:分页参数的设计。事件列表可能很长,必须分页。我让AI采用 cursor-based 分页而不是 offset-based,因为事件是按时间倒序排列的,用游标分页在数据插入频繁时不会出现重复或遗漏。具体做法是请求参数带cursor(上一页最后一条的 id)和limit,响应中返回nextCursor。这个设计AI一开始没想到,是我明确提出要求后它才实现的。
2.4 前端页面结构规划:让AI先画骨架再填肉
前端部分,我同样遵循“先结构后细节”的原则。先让AI根据功能清单规划页面结构,确认后再逐个页面实现。
宠物生命周期管理App的核心页面有这些:
- 首页:宠物列表卡片,显示头像、名称、品种、下次提醒事项
- 宠物详情页:基本信息、生命周期时间线、健康数据图表
- 事件记录页:按类型筛选的事件列表,支持添加新事件
- 提醒中心:待办提醒列表,按时间排序,支持标记完成
- 统计页:体重趋势图、疫苗完成情况、各类型事件数量分布
- 设置页:主人信息、通知偏好、数据导出
页面结构确认后,我让AI为每个页面生成组件树。比如宠物详情页的组件树是:PetDetailScreen包含PetHeader、PetInfoCard、LifecycleTimeline、HealthChart、EventQuickAdd。每个组件只负责一块内容,数据通过 props 或 store 传递。
这样做的好处是,AI在实现每个组件时目标非常明确,不会在一个文件里堆砌所有逻辑。而且组件拆分之后,如果某个组件效果不好,我可以单独让它重写,不影响其他部分。
实操心得:让AI生成组件时,一定要指定“这个组件接收哪些 props、内部状态有哪些、依赖哪些 store 数据”。如果不指定,AI会按照自己的理解去组织数据流,生成出来的组件往往和你的状态管理方案不匹配,改起来很麻烦。
3. 实操过程与核心环节实现
3.1 项目初始化:从空目录到可运行骨架
第一步是创建项目。我用 Expo 的模板命令初始化前端,用 Fastify 的脚手架初始化后端。这两个命令AI可以直接给出,但要注意版本兼容性。
前端初始化:
npx create-expo-app@latest pet-lifecycle-app --template blank-typescript cd pet-lifecycle-app npx expo install expo-router expo-notifications expo-image-picker zustand后端初始化:
mkdir pet-lifecycle-api && cd pet-lifecycle-api npm init -y npm install fastify @fastify/cors @fastify/multipart prisma @prisma/client npx prisma init这里有一个细节:Expo 的版本和 React Native 的版本有对应关系,如果AI给出的版本组合不对,安装后会报错。我的做法是让AI先查一下当前 Expo SDK 的最新稳定版本,然后根据这个版本去确定其他依赖的版本。实测下来,让AI“先确认版本再给命令”比“直接给命令”的出错率低很多。
初始化完成后,我让AI生成一个最小的可运行验证:前端显示一个“宠物列表”占位页面,后端提供一个/api/health健康检查接口。两边都跑起来之后,前端调用后端接口,确认网络连通。这一步看起来简单,但它是后续所有开发的基础,如果连不通,后面写再多功能也没用。
3.2 数据库迁移与种子数据
数据库部分,我用 Prisma 管理 schema 和迁移。前面已经设计好了 schema,接下来是执行迁移和填充种子数据。
迁移命令:
npx prisma migrate dev --name init种子数据我让AI生成了一份,包含三只示例宠物和它们的事件记录。种子数据的作用不只是填充数据库,更重要的是给前端开发提供真实的测试数据。没有种子数据,前端页面只能显示空状态,很多布局问题看不出来。
种子脚本的核心逻辑:
// prisma/seed.js const { PrismaClient } = require('@prisma/client') const prisma = new PrismaClient() async function main() { const pet1 = await prisma.pet.create({ data: { name: '豆豆', breed: '柯基', gender: 'MALE', birthDate: new Date('2022-03-15'), adoptDate: new Date('2022-05-20'), neutered: true, currentWeight: 12.5, events: { create: [ { type: 'VACCINE', occurredAt: new Date('2022-06-01'), note: '狂犬疫苗第一针' }, { type: 'DEWORM', occurredAt: new Date('2022-07-10'), note: '体内驱虫' }, { type: 'CHECKUP', occurredAt: new Date('2023-01-15'), note: '年度体检' }, ], }, }, }) // 更多种子数据... } main()注意:种子数据中的日期不要用固定值,最好用相对于当前日期的偏移量,比如
new Date(Date.now() - 30 * 24 * 60 * 60 * 1000)表示30天前。这样无论什么时候运行种子脚本,数据看起来都是“最近发生的”,方便测试提醒功能。
3.3 核心功能实现:事件时间线与提醒系统
整个App最核心的功能是事件时间线和基于事件的提醒系统。这两块我让AI分步实现,每步都先确认方案再写代码。
事件时间线的实现思路是:从数据库按时间倒序取出某只宠物的所有事件,按月份分组,在界面上以时间轴形式呈现。每个事件节点显示类型图标、发生时间、备注摘要。点击节点展开详情,可以查看附件和关联提醒。
AI生成的实现代码中,数据分组逻辑一开始写在了组件内部,导致每次渲染都要重新计算。我让它把分组逻辑抽成一个独立的工具函数,并用useMemo缓存结果。这个优化在事件数量少的时候差别不大,但事件超过100条之后,滚动流畅度明显提升。
提醒系统的实现稍微复杂一些。核心逻辑是:当创建一个事件时,如果该事件类型有对应的提醒规则(比如疫苗事件默认在一年后提醒),就自动创建一条提醒记录。提醒记录包含提醒时间、提醒内容、关联事件、完成状态。
提醒的触发我用的是 Expo Notifications 的本地通知能力。在App启动时,查询所有未完成的提醒,为每个提醒注册本地通知。当用户标记提醒完成时,取消对应的通知。
这里有一个坑:本地通知的注册数量有限制。iOS 对同时注册的本地通知数量有上限(通常是64条),如果提醒很多,不能一次性全部注册。我的做法是只注册未来30天内的提醒,超过30天的等临近了再注册。这个策略需要在代码中加一个定时任务,每天检查一次并更新通知注册。
// 注册未来30天内的提醒通知 const thirtyDaysLater = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000) const upcomingReminders = await prisma.reminder.findMany({ where: { completed: false, remindAt: { lte: thirtyDaysLater, gte: new Date() }, }, }) for (const reminder of upcomingReminders) { await Notifications.scheduleNotificationAsync({ content: { title: '宠物提醒', body: reminder.content }, trigger: { date: reminder.remindAt }, }) }3.4 健康数据统计与图表呈现
统计页面是体现“生命周期管理”价值的关键页面。我让AI实现了三个统计维度:体重变化趋势、疫苗完成率、各类型事件数量分布。
体重趋势用折线图呈现,数据来源是事件表中类型为 CHECKUP 或单独记录的体重数据。这里有一个数据清洗的问题:体重记录可能来自不同来源(体检时称的、家里称的),单位可能不一致(公斤和斤)。我让AI在数据进入图表之前先做一次归一化处理,统一转成公斤并保留一位小数。
疫苗完成率用环形进度图呈现,计算逻辑是:已完成的疫苗事件数除以该宠物年龄段应完成的疫苗总数。不同年龄段的疫苗要求不同,幼犬和成年犬的疫苗计划有差异。这个规则我让AI根据常见的宠物疫苗指南整理了一份对照表,然后在代码中根据宠物的出生日期自动判断当前年龄段和应完成的疫苗数。
各类型事件数量分布用柱状图呈现,按事件类型分组统计。这个图的价值在于让主人一眼看出哪类记录偏少,比如驱虫记录明显少于疫苗记录,可能提示驱虫做得不够规律。
实操心得:图表库我选的是
react-native-chart-kit,它的API简单,AI生成配置代码不容易出错。但它的默认样式比较简陋,需要手动调整颜色、间距、字体大小。我建议让AI生成图表配置时,把样式参数单独抽成一个对象,方便后续统一调整。
4. 常见问题与排查技巧实录
4.1 AI生成代码不一致的排查与预防
在项目搭建过程中,最常见的问题就是AI生成的代码前后不一致。具体表现有:前面定义的数据字段名和后面使用的对不上、接口路径在前后端不一致、状态管理的 store 结构在不同组件中理解不同。
排查这类问题的第一步是建立单一数据源。我把 Prisma schema 作为数据字段的唯一权威来源,把 API 契约文档作为接口路径和参数格式的唯一权威来源。每次让AI生成代码时,都把这两个文件的内容作为上下文贴给它,让它基于这些内容生成,而不是凭记忆。
第二步是生成后做交叉检查。AI生成完一个模块的代码后,我会让它自己检查一遍:“请检查你生成的代码中,所有字段名是否与 Prisma schema 一致,所有接口路径是否与 API 契约文档一致。”这个自检步骤能发现大部分不一致问题。
第三步是用 TypeScript 的类型检查兜底。前后端都开启严格模式,字段名拼写错误、类型不匹配这些问题在编译阶段就会暴露,不会留到运行时。实测下来,TypeScript 的严格模式能拦截大约70%的AI生成代码中的低级错误。
4.2 数据库迁移冲突的处理
开发过程中修改 schema 是常态,但频繁迁移容易产生冲突。我遇到过一次典型情况:我在本地修改了 schema 并执行了迁移,但忘记同步到另一台开发机,结果两边数据库结构不一致,代码跑起来报字段不存在的错误。
处理这类问题的原则是:schema 变更必须走迁移文件,不能直接改数据库。每次修改 schema 后,执行prisma migrate dev生成迁移文件,把迁移文件提交到版本控制。另一台机器拉取代码后,执行prisma migrate deploy应用迁移。这样两边的数据库结构始终一致。
如果已经出现了不一致,可以用prisma migrate diff对比两个数据库的差异,然后手动生成修复迁移。这个命令的输出比较长,我通常会让AI帮忙解读差异并生成修复方案。
4.3 移动端真机调试的常见坑
Expo 的真机调试很方便,但有几个坑需要注意。
第一个是网络问题。手机和电脑必须在同一局域网内,否则 Expo Go 连不上开发服务器。如果公司网络隔离了设备,可以用 Expo 的 tunnel 模式,但 tunnel 模式下热更新会慢一些。
第二个是通知权限。iOS 和 Android 对通知权限的处理不同,iOS 需要在首次使用时请求权限,Android 13 以上也需要动态请求。如果忘记请求权限,通知不会触发,而且不会有明显报错。我的做法是在App启动时就请求通知权限,并在设置页面提供一个“重新请求权限”的入口。
第三个是图片上传的路径问题。Expo ImagePicker 返回的 URI 在 iOS 和 Android 上格式不同,iOS 是file://开头,Android 是content://开头。上传到后端时,需要先统一转成 Blob 或 FormData。这个转换逻辑我让AI写了一个工具函数,两端都调用同一个函数处理。
4.4 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决方案 |
|---|---|---|---|
| 前端调用接口返回404 | 接口路径不一致 | 对比前端请求路径和API契约文档 | 统一使用契约文档中的路径 |
| 数据库报字段不存在 | schema未同步 | 执行prisma migrate status | 运行迁移命令同步结构 |
| 通知不触发 | 权限未请求或通知未注册 | 检查权限状态和注册日志 | 启动时请求权限并注册30天内提醒 |
| 图表不显示数据 | 数据格式不匹配 | 打印图表组件的data属性 | 检查数据归一化逻辑 |
| 真机连不上开发服务器 | 网络隔离 | 检查手机和电脑是否同网段 | 切换tunnel模式或调整网络 |
| AI生成代码字段名不一致 | 上下文不足 | 对比schema和生成代码 | 生成时附带schema作为上下文 |
提示:这份速查表建议放在项目根目录的
TROUBLESHOOTING.md中,每次遇到新问题就补充一行。积累下来,它比任何官方文档都更贴合你的项目实际。
5. 项目扩展与个人经验体会
5.1 后续可以扩展的方向
这个项目的基础版本跑通之后,有几个自然的扩展方向。第一个是多宠物家庭的数据隔离与共享,现在虽然支持多主人多宠物,但界面上的切换体验还比较粗糙,可以做成顶部宠物切换栏,快速在不同宠物之间跳转。
第二个是健康数据的智能分析。现在只是展示原始数据和简单统计,后续可以加入异常检测,比如体重连续下降超过一定比例时自动提醒主人关注,或者疫苗间隔时间异常时给出提示。这部分可以结合简单的规则引擎来实现,不一定需要复杂的模型。
第三个是数据导出与分享。宠物就医时,医生往往需要了解完整的疫苗和用药历史。提供一个一键导出PDF病历摘要的功能,实用性很强。这个功能的技术难点在于PDF排版,可以用react-native-html-to-pdf或者在后端生成PDF再下载。
第四个是离线优先的数据同步。现在所有数据都依赖网络请求,如果在地下停车场、电梯里等信号不好的地方记录事件,体验会受影响。可以引入本地数据库(如 WatermelonDB 或 SQLite)做离线存储,网络恢复后再同步到服务端。这个改造的工作量不小,但能显著提升核心场景的可用性。
5.2 我用AI搭建项目的一些真实体会
回过头看整个项目从零到跑通的过程,最大的体会是:AI不是替代你思考,而是放大你的思考。如果你自己对项目结构、数据关系、技术选型没有清晰的判断,AI生成的东西只会让你更混乱。但如果你能把问题拆解清楚,把约束条件说明白,AI的执行效率确实比手动写代码高很多。
另一个体会是分阶段确认的价值。我试过一次性让AI生成整个项目,结果是一堆看起来能跑但互相不匹配的代码,改起来比自己写还累。后来改成每个阶段只做一件事,做完确认再继续,整体效率反而更高。这个道理其实不限于AI编码,任何复杂项目的推进都应该遵循类似的节奏。
还有一个细节:让AI写代码时,注释和文档要同步生成。我一开始只让AI写实现代码,后来发现过两周再看某些模块,自己都忘了当时的逻辑。后来我要求AI在生成每个模块时,同步生成一段简短的模块说明,包括这个模块解决什么问题、关键数据结构是什么、有哪些注意事项。这些说明积累起来,就是项目最好的文档。
最后分享一个小技巧:当你觉得AI生成的代码“差不多能用但总觉得哪里不对”的时候,不要急着改代码,先让AI解释一遍它的实现思路。很多时候,问题出在它对需求的理解有偏差,而不是代码本身有bug。把理解对齐了,代码自然就对了。这个习惯帮我省了很多来回修改的时间。