面向切面编程的回归
摘要
一篇重新审视面向切面编程的博客文章,讨论了程序员必须管理的众多横切关注点,如正确性、日志记录和安全性。
暂无内容
查看缓存全文
缓存时间: 2026/06/29 17:06
# 面向切面编程的回归
来源:https://thomaswc.com/blog/the_return_of_aop.html
编写代码时,程序员需要跟踪的所有事项如下:
1)正确性:确保程序做正确的事,满足所有需求,维护所有重要不变量,以期望的方式执行业务逻辑等。
2)效率:程序使用最少的时间、内存和资源。这包括不在不需要时继续占用内存,以及尽可能不让释放的内存处于碎片化状态。某些程序有“实时约束”,其中某些效率目标(如在0.2秒内向用户返回响应)被视为正确性的一部分。
3)可调试性:当程序出错时,应该不太难找出问题所在以及如何修复。
4)可维护性:程序应有文档且可读。应以内部一致的风格编写,并与其所属的任何外部代码库的风格相匹配。
5)可测试性:程序的编写方式应使得单元测试和集成测试既有帮助又不过于难以创建。
6)日志记录:程序应生成通常非详尽的执行路径和变量状态追踪,以便于调试、监控效率以及收集其行为统计数据。
7)安全性:程序应只允许用户执行授权操作;通常是用户无需程序即可执行的操作,加上一小部分通过运行该程序而授予用户的明确定义的操作。
8)可扩展性:对程序进行少量的小修改应相对容易。
9)隐私:程序不应向任何其他人(可能包括程序的拥有者)泄露关于某一用户的数据,除非明确希望如此。
10)依赖管理:大多数程序使用他人或其他组织编写的代码,通常以库的形式。程序员需要确保这些库的使用合法——即不违反外部代码共享的任何许可证——并且这些库的集合是跨兼容的——例如,如果库A使用库C版本1,而库B使用库C版本2,那么编程系统要么需要支持这一点(大多数不支持),要么需要解决此情况。程序员还需要确保使用的任何库都不违反本列表中的其他考虑。
11)部署:许多程序在程序员编写代码的计算机以外的地方运行。这通常需要程序员进行额外工作,例如让程序检测并适应其运行环境,或将其容器化以在可在其他地方复制的标准环境中运行,或编写另一个程序将原始程序转换为新环境所需的格式。
12)可监控性/可观察性:并非每个程序都需要担心这一点,但长时间运行的程序会希望能在独立接口下实时获取日志记录中描述的那类信息。
13)持久性:并非每个程序都需要担心这一点,但长时间运行的程序通常需要停止和重启,而在几乎所有编程系统中,重启部分需要程序员做额外工作。
14)输入验证:并非每个程序都接收输入,但大多数程序都接收,并且当它们接收时,通常需要进行检查以确保输入符合预期或要求的格式,和/或可以转换为该格式。
15)错误处理:当出现问题时,程序应优雅降级,记录错误,向正确的用户组发出警报,并将程序恢复到可接受状态。
16)国际化和本地化:并非每个程序都需要担心在多个国家运行或向用户使用多种语言通信,但许多程序确实需要。
17)无障碍:同样,并非每个程序都需要担心这一点,但许多程序确实需要以优雅的方式适应具有不同身体或心智能力的用户。
我还可以继续列举,但我想我已经说明了这一点:这些事项非常多,甚至还不包括程序员在非编码时所需做的事情(如估算时间表或与同事沟通)。
面向切面编程(AOP(https://www.google.com/url?q=https://en.wikipedia.org/wiki/Aspect-oriented_programming&sa=D&source=editors&ust=1782273636239799&usg=AOvVaw0Q5AgQKik98rrCDU8ZD61J))是由Gregor Kiczales(https://www.google.com/url?q=https://en.wikipedia.org/wiki/Gregor_Kiczales&sa=D&source=editors&ust=1782273636240089&usg=AOvVaw1gf6_xxa8PB6ZTeNlQEK2w)和Xerox Parc的其他人在20世纪90年代中期提出的一种想法,即如果程序员能够分别专注于上述每一项,而不是在每行代码中同时处理所有事项,编程可能会更容易。
我一直很喜欢这个想法,但我一直也很讨厌AOP用来实现它的具体机制——所谓的“连接点模型”(https://www.google.com/url?q=https://livebook.manning.com/book/aspectj-in-action-second-edition/chapter-3%2312&sa=D&source=editors&ust=1782273636240954&usg=AOvVaw0oktVU61Bd9ZJO5DiCz92k),它基本上是对程序调用栈进行运行时模式匹配,并在每次匹配时运行一些代码。例如,每当调用栈中最近压入栈的是文件打开例程时,程序可能会记录即将打开的文件名。正如AOP的维基百科页面所指出的,这非常接近作为玩笑非严肃提出的“COME FROM”(https://www.google.com/url?q=https://en.wikipedia.org/wiki/COMEFROM&sa=D&source=editors&ust=1782273636241900&usg=AOvVaw31luB7tGInKLo-bargQVWs)语句,并且同样难以调试和维护。
但是,得益于LLM新获得的编码能力,我认为AOP值得重新审视。在其新形式中,程序员只需为每个关注点编写独立的文档。当然,这些文档的长度会非常不同,其中正确性文档通常最长。许多文档可以在项目间重复使用和共享;例如,组织的风格指南可用于可维护性关注点。而“织入器”,借用AOP的术语,就是根据文档生成程序的LLM。
为什么这比AOP旧的连接点模型更好呢?好吧,旧模型很脆弱:要在每次文件打开后记录日志,需要针对文件打开函数的特定字符串名称或名称集进行匹配。如果同事后来添加了一个新的文件打开函数(或者更糟,重命名了一个),那将不会被记录。而在这里,由LLM进行织入时,我们是依赖它关于“打开文件”的背景知识来进行匹配。
LLM还有一个优势,即它们织入的输出是静态的(即在程序运行时不计算)且可读的。有些AOP实现确实进行“编译时织入”,如AspectJ的ajc,但它们输出的东西是原始Java字节码,不太可读。
这也是一个有点不公平的比较,因为无论是否使用AOP,LLM都将用于生成代码。我只是想说,AOP的关注点概念为我们提供了一种有用的方式来组织我们输入给LLM的句子。(或多个LLM;也可以将每个关注点的描述输入给一个独立的智能体,其工作是从该角度对代码进行评审。)
相似文章
OpenBSD 反返回导向编程缓解措施的最终版本
本文讨论了 OpenBSD 中反返回导向编程缓解措施的最终实现。
迈向可理解的软件
本文批判了当前的编程实践和对大语言模型的依赖,反而主张通过更好的抽象、文档和软件栈来使代码更易于理解和维护。
@Pragmatic_Eng: 旧软件工程模式因编码代理而回归。Dax Raad(@thdxr),AI编码代理OpenCode的联合创始人…
Dax Raad,AI编码代理OpenCode的联合创始人,认为像领域驱动设计这样的旧软件工程模式正在重新变得相关,因为编码代理虽然高效,但需要更多的防护措施;这些模式曾因冗长而令人痛苦,而现在AI处理了这些冗长部分。
@SaitoWu: https://x.com/SaitoWu/status/2053101671035851216
The article summarizes a talk by Matt Pocock criticizing 'specs-to-code' approaches, arguing that solid software engineering fundamentals like TDD and modular design are more critical than ever for effectively using AI coding assistants like Claude Code.
我作为实践者的程序分析观
实践者 Rory Sawyer 回顾十年将程序分析用于弥合代码与人类意图之间差距的经历,强调静态分析作为超越执行的正确性沟通工具的价值。