小叶用AI做了一个课程作业清单工具。每次收齐一个文件夹里的作业,选择文件夹,工具就把符合要求的文件列成一张清单。老师和同学不必再对着文件夹逐个抄名称。第一门课只收PDF,工具用了一段时间,小叶觉得这件事已经完成,可以放下了。
新学期开始,事情又找了回来。有一份名为“小叶.PDF”的文件没有出现在清单里,原来某处只认小写后缀。另一门课除了PDF还接收DOCX,同学希望继续用这套工具。与此同时,小叶想调整清单上的课程名称,却发现相同文字散在好几处,每改一次都要反复寻找。AI很快给出了新代码,真正费时间的却是确认这次改动有没有遗漏、两门课是否都还能正常用。
这就是软件交付以后经常面对的工作。已有问题需要修正,使用条件可能变化,新的使用者希望借用现成能力,过去的组织方式也未必继续适合。维护和演进关心怎样接住这些变化;复用关心怎样利用已有成果,又不把原有负担一起无条件复制过去。
本章的工具、课程、人员安排和工时均为教学设定。少量Python代码只演示一个筛选规则的整理,配套文件记录了有限运行结果,不表示完整作业工具已经实际交付。我们要学会的是:面对一项已经有人使用的成果,怎样决定接下来该修哪里、整理哪里、共用什么,以及什么时候可以停止继续投入。
一、已经能用,为什么还需要维护
软件维护,是围绕已经交付的软件继续修正问题、适应变化和改善使用或修改条件的工作。我们不必先背熟各种分类,先看小叶遇到的三个具体请求,就能理解维护为何不会随着第一次交付自动结束。
第一件事是大写后缀漏收。小叶当初承诺接收PDF文件,不区分扩展名大小写,现有程序却没有完全做到。因此,这属于已有要求没有被满足的问题。修好以后,用户得到的仍然是原先约定的能力,只是某些过去失败的输入现在可以正常处理。
第二件事是另一门课要收DOCX。它不在最初只收PDF的约定内。工具此前没有支持它,并不说明原版本一定有缺陷;新用途改变了需要处理的范围。小叶可以决定支持,也可以说明当前不支持,还可以为另一门课选择不同工具。先分清这一点,才不会把所有新愿望都当成必须立即修复的错误。
第三件事是课程名称散落多处。工具对使用者可能仍然表现正常,但小叶每次修改都要查找和核对。这是内部组织给后续工作带来的困难。改善它的目的,是让下一次变化更容易落实,而不是为了让文件看起来符合某套漂亮结构。
还有一些变化来自软件外部。原先可以读取的一种导出格式变了,运行环境升级后旧依赖不再适配,使用者把输入放到了不同位置,都可能使既有做法失效。软件源代码一行未动,任务照样可能做不成,因为真正参与工作的还有输入、环境、外部服务和人的操作。
因此,“上学期跑过一次”是一条有用的历史信息,却不能回答本学期所有条件下是否仍然可用。小叶需要知道现在继续完成的是哪项任务、哪些条件还和过去相同、哪些已经变化。维护从这里开始,而不是一听到“旧系统”就默认全面推倒重来。
这也解释了为什么维护不能只按修改的代码行数估量。一行规则可能决定大量文件是否进入清单;一次看起来很大的界面整理,也可能没有改变原来数据的含义。判断工作分量,需要看行为、依赖和使用范围怎样变化,而不只是看AI生成了多少行。
二、先把问题还原成可以处理的变化
收到“清单不对”这样的反馈,小叶首先需要把它还原成一个具体差异。使用者选了哪个目录,里面有什么文件,本来希望清单包含哪些项,实际缺了什么,所用版本和设置是什么?这些信息使问题从一种不满,变成可以复现、解释和检查的对象。
假设清单漏了“小叶.PDF”,而同一目录里的另一份作业“补充作业.pdf”可以进入。小叶检查后确认,出问题的分支直接比较文件名是否以小写.pdf结尾,没有先处理大小写。这时,修复的目标很清楚:使后缀大小写不同的PDF都按原约定进入清单,保留其他已有规则。不能为了让这个文件进入,就把所有文件无条件加入,那会改变另一项原本正确的行为。
还要检查这个差异影响到哪里。漏收只是出现在一个界面入口,还是生成清单的所有路径都用了同样规则?已经生成过的哪些清单可能受影响?这些问题决定是否需要重新生成相关结果。修复未来运行中的程序,与处理过去留下的错误清单,是两项有关联的工作。只完成前者,不能自动宣布过去的遗漏已经消失。
为了便于后面的讨论,我们从这里起假设大小写问题已经修复并经过对应检查。后续展示的整理代码,以这份已修正的行为为起点。这样,“修正原有行为”和“整理内部表达”就不会在例子中混成一件事。
另一门课提出DOCX时,小叶则需要问清新使用情景。这门课是否同时接收PDF和DOCX?旧课是否仍只接收PDF?清单的列和命名方式是否相同?如果只是听到“再支持一种格式”,就把整个工具的允许范围统一扩大,可能使旧课也开始接收原来不应进入的文件。
可以把已确认的两个使用范围放在一起。
| 使用范围 | 允许进入清单的后缀 | 当前需要保护的行为 |
|---|---|---|
| 原来的课程 | PDF,不区分大小写 | DOCX等其他后缀仍不进入这门课的清单 |
| 后来接入的课程 | PDF和DOCX,均不区分大小写 | 两种允许格式都进入,并保留原文件名称 |
这张表没有解决怎样写代码,但已经避免了一类维护失误:用新使用者的要求覆盖旧使用者的约定。后面的结构和复用选择,都应当支持这两个范围共同存在。只有一项明确规则时,简单写在程序里可能足够;出现两项同时有效的规则时,就要让程序和使用入口能够分辨它们。
处理反馈的顺序也有轻重。影响当前交付的漏收,通常值得先定位;尚未决定何时使用的新需求,可以先记录其范围;只觉得代码“不够先进”的改造,则需要说明它妨碍了哪件实际工作。把这些事混成一张没有区别的待办表,很容易让最显眼、最好演示的改造挤掉最该处理的问题。
三、技术债说的是后续成本,不是对旧代码的道德评价
小叶最初赶着给一门课试用,把课程名称直接写在几个输出位置。这样做当时容易理解,也很快完成了任务。后来名称要改、另一门课要接入,他才发现每次都得检查多个位置是否一致。软件并没有因此立刻不能用,但修改同一项规则需要付出额外工作。
技术债这个比喻,常被用来讨论已有设计给后续开发带来的附加成本。可以把当初省掉的整理理解为暂时少付了一部分投入,之后每次绕过同一个困难,又像在持续付出成本。但它不是一笔真有固定利率的借款,也不意味着每个不完美的地方都应该马上重写。
Fowler讨论技术债时强调,这个比喻的价值在于帮助人评价设计问题;债可能来自有意识的取舍,也可能在逐渐理解项目后才被发现,是否值得处理仍取决于后续代价。Fowler:技术债的不同处境。
如果这门课只需要临时用一次,之后不再改名称也不再接入别的课,几个位置的文字未必构成值得专门整理的大问题。反过来,若每次新增课程都要找同样几处、常有漏改,额外成本就开始反复出现。我们关心的是它与未来工作发生了什么关系,而不是用“欠债”两个字制造必须立刻清理的压力。
有意识的取舍也应留下适当记录。例如:“本周先完成单课试用,课程名称暂时写在三处;新增课程前集中整理这项配置。”这让下一次接手的人知道临时安排在哪里、为什么存在、什么变化会让它值得处理。若只写“以后优化”,下一位接手者既不知道问题的位置,也不知道什么时候需要行动。
不过,所有后续问题都叫技术债,反而会失去判断力。另一门课首次需要DOCX,是用途增加;某份输入文件损坏,是数据状态;漏收原本应该接收的PDF,是行为缺陷。它们可能和设计困难相互影响,但处理方法不完全相同。把它们都装进“还债”,会让使用者听不懂到底修了什么。
评估整理是否值得,可以用一个小的工时比较建立直觉。假设小叶估计,集中课程配置连同相关核对需要三小时;整理后,每次调整课程信息可以少花半小时。若未来实际只发生四次这类调整,累计省下的时间是两小时,仅靠这一项节省还不足以覆盖三小时投入。这里需要比较的是一段使用期内反复省下的工作,不能只说“以后每次都更快”就默认一定划算。
这些数值是教学估计,三小时已包含整理与对应检查,半小时是每次查找、修改和核对合计的预计减少量。未来调整次数也不是已发生事实。若实际修改更频繁,或漏改经常造成重要清单返工,评价会不同;如果工具很快就停用,投入又可能收不回来。也不要把消除严重漏收问题的必要性,简单折成这几小时比较,行为要求与内部便利还需分开判断。
技术债因而提供了一种观察习惯:哪些地方正在反复拖慢下一步,拖慢的具体工作是什么,处理以后能少付什么代价。它帮助小叶选择有意义的整理范围,而不是给整个旧项目贴上“落后”的标签。
四、重构先保持行为,再让修改变得容易
重构是对既有程序内部结构的调整,目标是在保持可观察行为的同时,使它更容易理解或修改。这里的可观察行为,可以包括哪些输入被接收、输出什么内容、顺序怎样、失败时怎样表现。它需要结合正在整理的范围确定,不能只看最后界面是否大致相似。Refactoring:重构的定义与方法。
对小叶来说,可以先把“是否属于PDF文件名”这项判断提取成一个有名字的函数,再让生成清单的部分调用它。下面只接收文件名字符串列表,不读取真实目录,也不检查文件内容是否真是有效PDF。它演示的是后缀筛选这一小段行为。
整理前,这项判断直接写在筛选过程里:
def list_before(names):
return [name for name in names if name.lower().endswith('.pdf')]
整理后,把判断单独表达出来:
def is_pdf(name):
return name.lower().endswith('.pdf')
def list_after(names):
return [name for name in names if is_pdf(name)]
这里的lower()得到用于比较的小写文本,endswith('.pdf')检查末尾是否为指定后缀;列表中保留的仍是原来的name,因此“小叶.PDF”不会被改名成“小叶.pdf”。相关字符串方法可查Python官方说明。理解本例不需要重新学习全部字符串方法,重点是判断的位置变了,判断本身及保留的名称没有变。
给定“小叶.pdf”和“说明.txt”,两段程序都只保留前者;给定“小叶.PDF”和“记录.PdF”,两项都应保留;“小叶.pdf.bak”虽然中间出现.pdf,末尾却是.bak,因此不进入结果。空列表仍得到空列表。若输入列表含两次相同名称,这一小段筛选也保留两次,它没有承担去重的任务。
配套小实验实际对普通后缀、大小写、末尾不匹配、原顺序、重复项和空列表六组情况,比较了提取前、提取后与独立列出的预期结果,三者相符。本地运行记录只覆盖这段字符串筛选。它没有验证扫描目录、文件大小、清单保存或真实PDF内容,也不因为六组通过就证明任意改造都保持行为。
这个提取给以后修改带来的便利,是规则有了明确位置。准备增加别的格式时,小叶能够找到负责后缀判断的地方,不用先穿过输出文字和文件保存过程。但“多了一个函数”本身不是成功标准。若原项目只有一行永远不再变的代码,提取可能收益很小;当规则要被几处调用或需要独立检查时,这个名字和位置才更有价值。
如果AI在这次提取时顺便加入DOCX、排序和去重,就已经改变了原来的可观察行为。新的功能可能值得做,但应当作为新的变化说明、分别核对。否则,结果有差异时,小叶难以判断是整理过程出错,还是自己顺手接受的新规则在起作用。
小步重构的意义正在这里:先保留已知行为,把内部组织改到便于继续工作的位置;确认这一段仍然成立,再引入需要改变的行为。它不要求每个项目都经过大型重构,也不承诺整理越多越好。实际尺度应当是能解释这次改了什么、保留了什么,并有相应证据支持。
五、复用要找到共同规则,也要给真实差异留位置
软件复用,是在新的工作中继续利用已有的代码、组件、资料或方法。小叶已经有了扫描文件、保留名称、生成清单等能力,另一门课可以借用其中一部分,减少从头建立的工作。但“看起来相似”只说明值得比较,不能直接证明全部规则都应该合并。
原课只收PDF,新课收PDF与DOCX,这是同时存在的差异。如果小叶把第二门课的规则写成全局唯一规则,旧课就被改变了;如果复制整个程序再到处改,眼前容易完成,但以后修同一个扫描问题,可能需要给两个副本各修一次。复用的选择,就是在共用能力与独立变化之间找合适的安排。
一种直接做法,是把允许的后缀作为课程配置,而把读取名称、按配置筛选和生成清单的通用过程保留下来。配置指供程序使用的明确取值,例如原课对应“PDF”,新课对应“PDF、DOCX”。规则的差别仍然存在,只是不再分散藏在整套程序的不同位置。
这项安排成立有一个条件:两门课的差异确实主要在允许后缀上,而筛选以外的过程可以共用。若另一门课还要求按学号判断是否重复提交,甚至要根据提交时间选择最后一份,那就涉及不同的信息和判断,不能靠再填一个后缀列表解决。小叶应当继续辨认哪一段真相同、哪一段需要另处理。
复用常常是局部的。两个流程都需要读取一个目录,可以共享读取能力;一个生成文件清单,另一个判断每个人是否已交,可以分别组织后续逻辑。即使它们处理相同的文件,也可能回答不同问题。按处理对象相同就合并全部流程,容易把互不相干的分支塞进一个越来越难懂的函数。
选择配置也不意味着把所有东西都变成选项。若工具出现几十个开关,使用者不知道该怎样搭配,开发者又无法判断哪些组合需要检查,原先节省的重复代码可能变成更大的组合负担。配置应该承载已经需要区分、且有清楚含义的变化,而不是把每个内部动作都暴露出去。
在本例中,一个简单的课程选择入口就能对应两组已经确认的允许后缀。使用者先选课程,再看到该课程接收什么;清单上保留课程名称,便于核查所用规则。这样,差异不仅存在于代码中,也能被操作工具的人辨认。若选错课程仍然可能得到一张形式正常的清单,这个入口和结果标识就属于复用方案需要处理的实际问题。
小叶也可以暂时保留两个独立版本。如果第二门课只是一次试验,后续规则很可能大幅改变,先用独立副本探索有时更容易理解。但应知道共同修复需要怎样传递、两版各自由谁负责。独立并不自动错误,共享也不自动高级,关键是后续变化能否被明确承接。
因此,复用的收益不是“代码重复率越低越好”,而是下一项工作能借助现成能力少走一段路,同时仍然保留需要独立变化的地方。共性和差异都说清以后,学生才有依据决定提取函数、设置配置,还是暂时维持两条路径。
六、不要为尚未出现的使用者造一整套平台
两门课接通之后,AI可能很容易继续生成一套更大的方案:支持所有文件类型、自定义审批流程、跨学院账户、多级权限、自动评分、可视化报表。每个功能都能说出潜在用途,放在一起却会把小叶原本的清单工具变成一个庞大平台。
问题不是未来绝不会有人需要这些功能,而是现在对需要的理解有多具体。是否真有人准备使用,完成标准是什么,谁会维护,接入它会让当前任务多承担什么?如果这些问题还没有答案,提前写出的通用结构可能只是把猜测固化进了代码。
YAGNI通常用来提醒开发者,不要仅因为猜测以后需要,就提前加入尚未使用的能力。Fowler对这一原则的解释,也区分了未来功能的额外复杂度与让当前代码容易修改的必要工作。Fowler:YAGNI及其边界。
可以从小叶的日常工作看它的影响。原本调整课程规则,只需核对两门课;加入许多尚未用到的模式后,他每次改动都要先判断会不会碰到那些模式。即使AI生成它们很快,阅读、理解、检查和维护仍会发生。一个功能尚未带来使用收益,却已经进入后续每次修改的考虑范围。
提前做还有另一种成本:当前更需要的事情被推后。比如本周真正阻碍使用的是清单保存失败后的提示不清楚,小叶却花时间设计将来可能出现的学院管理员权限。就算管理员功能以后确实有用,也不能用未来用途自动证明现在先做它比先解决保存问题更合适。
但这不要求小叶故意把代码写死。给后缀规则起一个明确名字,避免把课程名称散落各处,保留相关检查,这些工作直接服务当前理解和修改,也使后来增加能力容易一些。没有必要为了反对过度设计,再反过来取消这些低负担的准备。
可以做一个很具体的思想试验:如果半年后真的需要新课程规则,现在的哪一处会挡住它?若只要增加一项清楚配置,再补对应检查就能完成,就没有充分理由现在建全套规则编辑器。若已经确认下一周两门课会采用不同后缀规则,差异就在眼前,应当现在给它位置。两种情况的区别是需求证据和实际改变成本,不是是否提到了未来。
随着使用经验增加,小叶也可能发现最初想到的共同点并不是真正稳定的共同点。两门课都叫“检查作业”,一门关心文件格式,另一门关心是否按时提交;后来才看清,通用部分是文件信息读取,后续判断需要分开。先从真实用途学到这些差异,再选择抽象范围,通常比在开头凭名称建立万能框架更有根据。
这项原则最终让复用更贴近实际:保留已经观察到的共性,为已经确认的差异提供位置,对尚未确认的想象保留改变余地。它支持尽早行动和不断学习,不要求学生等未来全部清楚才开始,也不鼓励把当前必要的整理一直拖下去。
七、共用以后,一次修改会影响更多人
把后缀规则集中以后,小叶只需维护一份共用筛选过程。以后发现共同问题,改一处就有机会让两门课都受益。这是复用的重要收益。但同一个变化也可能同时影响两门课,所以检查范围需要跟着共用范围改变。
假设AI改进了后缀判断,新课的DOCX能够进入,原课的DOCX却也开始进入。这说明新课路径成功了,旧课约定却失去了保护。只用新课示例验收,就会漏掉这一点。小叶应同时拿两门课各自允许和不允许的文件核对,确认共享实现仍能遵守不同配置。
除了后缀,清单的列名和顺序也可能有人依赖。原课同学把清单导入另一张表,约定第一列是文件名;小叶为了让新课更方便,把课程名称放到第一列,却没有同步原课的导入过程。清单内容看起来都在,后续工作仍可能因此失败。兼容性关心的,就是使用者或其他部分依赖的这些行为,在变化后能否继续成立。
如果确实需要更改格式,可以明确旧格式与新格式的差别,让相应使用者或工具一起调整;也可以在一段过渡期提供旧格式输出。选择取决于还有谁在使用、能否同时迁移以及维护两种格式的负担。不能只看新清单更好看,就推断原流程已经完成升级。
共用成果还需要能够辨认版本。再设想后来的一次共同修复:原课仍在使用这次修复前的共享模块,新课已经换成修复后的版本,界面又没有留下区别,后续反馈就容易混在一起。项目可以用自己实际采用的版本标识或交付记录说明这件事,不必先建立复杂发布系统。要点是:发现问题时,能够确定是哪套程序和配置产生的结果。
哪门课先更新、哪门课暂缓,需要根据各自使用时间和配套情况安排。更新后的功能已经存在于某份代码中,不代表所有使用者已经拿到了它;一次共同修复,也可能需要逐个确认哪些正在用的版本已受到影响并得到处理。
复用的对象也可以是文档、示例和检查方法。两门课共享起步步骤,就可以共用相应说明;允许后缀不同,则应让示例与课程配置对应。把原课的整份指南复制给新课,却忘了修改接收范围,与复制代码后漏改常量属于相似的接续问题。
所以,评价共用方案要同时看两个方向:共同变化能否更容易传递,真实差异能否继续被保护。只看“改一次就全都改了”,还没有完成评价。越多人依赖一项共用能力,越需要知道谁受影响、用什么条件检查,以及怎样让他们完成必要的切换。
八、环境和模型变了,旧成果也要重新接上条件
小叶给另一位同学换电脑安装工具,发现程序启动失败。此时未必需要改动筛选逻辑。可能是缺少运行所需依赖,可能是启动入口没有找到配置,也可能是某项外部组件更新后用法发生变化。维护首先要定位变化在哪一层,避免把环境问题误当成整个程序需要重写。
运行环境包括让程序工作的解释器、库、系统条件及外部服务等。记录一个曾经可用的组合,可以帮助小叶重建和比较;但把环境永远冻结也有代价,可能逐渐难以获取支持或与新的使用条件配合。更新与暂缓更新,都应针对实际影响判断,而不是机械追求最新或一概不动。
假设工具依赖的读取组件发布了新版本。小叶可以先看官方变更说明,确定是否涉及自己的用法,再在保留现有工作版本的条件下,用当前输入和任务验证候选环境。若新版本改变了返回的信息结构,就需要检查接收这份信息的代码;若实际使用部分没有变化,也不必仅因为版本号变了就改写所有模块。
在这个过程里,“新版本安装成功”和“当前任务继续完成”仍然是不同的判断。前者只说明安装这一步完成;后者还包括打开工具、读取输入、应用对应课程规则、保存清单,以及原有接续流程能够读懂清单。核对范围应沿当前使用路径展开。
如果以后给这个工具接入AI,例如让AI根据作业文本生成供学生自查的建议,维护范围会再增加一项。这里是另设的新功能情景,不是前面后缀清单已经具有的能力。模型或提示内容变化以后,程序接口仍可能正常返回文字,但建议的准确性、遗漏和语气可能变化。
对此,小叶需要保留当前评价任务和有代表性的输入,比较新旧组合在这些任务中的表现。不能只检查“返回了文本”,也不能只用一条看起来不错的回答宣布全面改善。如果模型、输入材料和提示同时变了,差异的来源又更难判断;可以在实际可控制的范围内分开比较,并如实说明仍未覆盖的条件。
还要记录哪些因素是自己能固定的。自己保存的提示和任务样例可以明确对应版本;外部服务是否允许取得某个旧模型、某种行为能否精确重现,则要看实际提供的条件。不能因为文档记住了模型名称,就默认过去的完整运行环境永远能找回来。
维护的重点因此仍然是把成果与当前条件接起来。发现变化后,确认影响、作有限调整、验证当前任务,再更新配套记录。AI能够帮助阅读变更说明和修改代码,但判断“新组合是否仍完成我们的工作”,需要围绕自己的使用目标作出。
九、局部整理、逐步替换和重写,各自需要什么理由
当程序越来越难改,小叶可能想让AI从头写一个新的。新代码看起来整齐,生成速度也快,这种选择很有吸引力。但重写的成本不能只按新代码生成时间衡量。旧程序里还承载着已有使用规则、特殊输入处理、清单格式以及用户已经习惯的操作。新实现要接住这些东西,仍然需要辨认、验证和切换。
如果问题集中在课程配置散落,局部集中配置可能已经足够;若扫描部分过于复杂,可以在保留其他部分的前提下替换扫描模块;若整个工具的基本组织方式都无法支持已经确认的新用途,重写才可能成为值得认真比较的方案。选择范围应与造成困难的原因相配。
逐步替换是一种常见的做法:先为要替换的部分明确输入输出和当前必要行为,做出候选实现,用有代表性的材料比较,再在合适范围内切换。对于只生成清单、不修改原始作业的本例,可以让新旧版本从同一份保留的输入材料分别生成结果,比较文件是否应当进入、名称与列是否对应。
比较时又要记住,旧结果不一定全对。如果旧版存在已经确认的漏收,新版修复后清单自然不同;若仅是内部整理,差异则需要解释。应该先写清哪些行为要保持、哪些要改变,再判断差异是否符合目标。要求新旧输出永远完全相同,会把旧错误也保护下来;看到新旧不同就叫升级成功,同样没有依据。
真正切换时,还要考虑原来的资料怎样继续使用。新版本按课程组织旧资料时,原清单中已有的课程名称可以帮助确认归属;若发现某份旧清单没有标明课程来源,小叶就不能凭空补出确切归属。他可以利用已有交付记录确认能确认的部分,对无法确定的旧资料保留原状态,或者让相关使用者核实。数据迁移是把旧信息带到新组织方式中,不能因为新表格要求某一列,就虚构旧数据中没有的事实。
回退也应考虑同样的问题。保留旧程序可以帮助恢复旧行为,但如果新版本已经改写了旧资料格式,只有旧程序未必够用。切换前保留必要输入和配置,确认失败时怎样回到可用状态,才能让退路与实际变化相配。本例的清单输出可以另存,正好有利于比较和保留旧结果;不能把这个便利直接推广到会修改共享数据的系统。
也有重写更合适的时候。假设工具后来必须处理的工作,已经与最初单课清单差别很大,核心逻辑几乎处处纠缠,局部改动一再牵动全部流程;如果新的设计能更清楚地组织这些已确认需要,而且有能力完成行为核对和资料切换,重写就可能减少后续负担。理由应落在具体阻碍与新安排上,而不是“AI现在可以一口气写完”。
重写同样可能带来新的问题,因此需要比较完整后果:旧能力如何承接、新能力怎样验证、使用者怎样切换,以及未来由谁维护。过去投入很多,不要求永远保留原实现;新代码生成很快,也不要求马上抛弃原实现。决定依据应当是从现在往后,哪条路径更有把握完成实际工作。
十、工具的寿命,也需要有人作出判断
最后,有些工具值得长期维护,有些完成一段时期的工作后可以停下来。假设学校后来提供的统一平台已经能生成所需清单,两门课也都决定转用它。小叶再继续维护原工具,未必还带来足够价值。已经投入的精力可以成为学习成果,却不必变成未来每学期继续投入的义务。
但停止维护不等于突然让正在使用的人无从接续。小叶需要确认还有谁依赖它、哪些旧清单或配置要保留、使用者准备怎样完成下一次任务。可以安排最后一个明确可用的版本,写清停止新增或修复的范围,帮助使用者迁到新的安排,并保留他们仍需查阅的资料。退出同样是一次交接。
如果只有一门课仍然需要旧工具,也可以缩小维护范围。例如继续保留已经稳定使用的PDF清单能力,暂不增加新格式或大平台功能。范围缩小以后,所需投入可能可以承担;如果连必要修复也无法持续,则应明确说明支持结束。使用者需要知道实际能获得什么,不能依赖一句模糊的“有问题再找我”。
现在回到本章开头的新学期。按前文已经明确的阶段,大小写漏收已修复,接下来两门课都有确定用途,允许后缀不同。小叶可以把两组已确认规则放到清楚配置中,保留共用筛选与清单能力,并用两门课各自的允许和不允许输入检查。课程名称散落的部分,可以随这次接入整理到对应配置里,让它直接服务眼前的变化。
他暂时不建设多学院平台,也不因一处规则分散就重写全部程序。新课的接入需要检查课程选择、输出标识和既有清单使用方式;候选版本验证后,再与对应说明一起交给使用者。过去可能受漏收影响的清单则另行确认,不能因为新版本已经修好就当作历史结果已经得到处理。
如果之后输入格式、依赖环境或真正接入的AI能力变化,再围绕受影响任务安排维护。若使用需要消失,就评价继续、缩小或结束支持。这样的后续安排既承认成果会变化,也不把变化变成无休止重做的理由。
软件工程在这里与最初的任务选择重新接上了。会让AI生成代码,只解决了建设能力的一部分;知道哪些行为需要保护、哪些结构值得整理、哪些差异应该独立、哪些未来想象可以暂缓,才更容易把已经做出来的成果持续用在有价值的工作上。学习这些知识的过程,也可以直接发生在一个小工具的下一次实际修改中。
练习与参考分析
练习一:三项请求都应该叫“修复”吗
小叶的工具承诺接收PDF,不区分后缀大小写。现在收到三项请求:大写PDF被漏掉,没有进入清单;另一门课希望支持DOCX;维护者希望把散落的课程名称集中起来。请分别说明每项工作要改变什么、保护什么,以及怎样判断完成。
参考分析: 第一项修复原有约定的偏离,应让大写与混合大小写PDF进入,同时保留原来的其他限制。需要重现具体遗漏、检查受影响路径,并判断是否有旧清单要重新生成。第二项是新用途,先确认哪门课需要接收哪些格式,避免用新课规则覆盖旧课;完成依据是对应课程可按明确规则生成清单。第三项属于改善内部修改条件,若只集中名称而保持输出,便应核对名称内容及相应行为没有变化,并观察今后修改是否确实有了清楚位置。三项可能在同一轮完成,但各自的目标与验收依据应分开,不能统称“优化成功”。
练习二:提取函数时顺便去重,还是重构吗
原来的筛选函数保留输入列表的顺序和重复项。AI把它整理成一个独立函数,同时加入自动排序和去重,解释说:“这样更整齐,输出也更合理。”小叶只检查每个结果都以PDF后缀结尾,便准备接受。请评价这次改动和检查方式。
参考分析: 是否保留顺序与重复项,也是这段程序原来的可观察行为。提取判断可以保持行为,但排序和去重改变了结果,不能只用“重构”说明整个改动。它们也许符合新的需要,却要说明为什么需要,以及是否会影响后续按原顺序对应输入的流程。只检查结果都是PDF,既不能确认原顺序仍在,也不能发现某些合法项被删,更不能确认本该进入的全部文件都保留。应先决定哪些行为保持、哪些有意改变,再用对应输入和预期检查。例子里重复名称可能只是输入列表特征,不能未经了解便把它们一律当作应消除的错误。
练习三:三小时的整理一定能省回来吗
小叶预计整理某个重复配置需要三小时,已包含修改和相关检查。之后每次调整该配置,预计能少花半小时。有人说只要以后还会改,就应立刻整理。请用未来只有四次调整的情景评价这个说法,再指出还有哪些因素可能改变决定。
参考分析: 按题给估计,四次累计省两小时,单靠这项节省尚不能覆盖三小时投入。“以后会更快”只说明单次有收益,没有说明在剩余使用期内收益能积累多少。修改次数更频繁、每次实际节省更大,或现有做法经常导致重要错误返工,可能增加整理价值;工具很快停用、未来规则将完全改变,则可能降低价值。还要分别核清一次整理要做哪些工作、以后每次调整能减少哪些工作,避免漏算或重复计算。题目中的三小时已包括相关检查;半小时是每次查找、修改和核对的预计减少量,要按剩余调整次数累计,不能把两种时间当作同一项工作直接比较。若当前问题直接违反必须满足的行为要求,还需要单独修复,不能用这个内部效率算例代替全部质量判断。
练习四:同一段代码,能直接推广给所有课程吗
原课只收PDF,新课收PDF与DOCX。小叶把允许后缀做成课程配置,并共用筛选过程。后来第三门课要判断每位同学是否提交了最后一版作业,依据是学号和提交时间。同学建议把第三门课也塞进同一个后缀配置。请说明哪里可以复用,哪里还缺少新的理解。
参考分析: 后缀配置能够区分允许文件类型,不能表达根据学号归组、根据提交时间选择版本的完整判断。第三门课需要哪些信息、如何解释“最后一版”、缺少学号或时间时如何处理,都要先明确。读取文件信息或输出基本清单可能共用,后续按人和时间判断则需要相应逻辑。不能因为都叫作业工具,就把不同问题当成一个参数取值。若确实形成稳定的公共步骤,再共享它;对尚未清楚的差异,可以先保留独立实现并观察实际使用,避免一开始建难以验证的万能规则系统。
练习五:新工具生成得很快,旧工具就该停了吗
AI为小叶生成了一套新的清单工具,演示输入可以运行,代码也比旧版整齐。两门课目前仍使用旧格式清单,其中一门课还把清单导入另一份表。小叶准备立即替换旧工具并删除旧资料。请评价这个计划,提出一个与当前条件相配的下一步。
参考分析: 演示运行证明的范围很有限,尚未表明新工具接住两门课的筛选规则、名称、清单格式和导入关系。代码整齐可能改善维护,但完整切换还包括行为核对、配置与资料迁移、使用者操作和退路。下一步可以先明确新旧哪些行为保持、哪些有意变化,用保留的代表性输入分别生成清单,核对两门课的结果及后续导入。对旧版已知错误要按有效要求判断,不能只要求与旧输出逐字相同。候选结果可靠、配套流程能够接续后,再安排切换,并保留仍需查阅或恢复的资料。若新工具只解决一个局部问题,也应比较局部替换是否已经足够;不必因为新代码已生成,就把删除旧资料当作必须马上完成的步骤。