报名参加CloudWeGo黑客松,奖金直推双丰收! 了解详情
写点什么

代码只能说明它能做什么

  • 2020-07-25
  • 本文字数:2924 字

    阅读完需:约 10 分钟

代码只能说明它能做什么

本文最初发布于 Marc Brooker 的个人博客,遵循Creative Commons Attribution 3.0 Unported License协议,经原作者授权由 InfoQ 中文站翻译并分享。


代码只能说明它能做什么。这对计算机而言很重要,因为我们是通过代码告诉计算机做什么。对人来说,只要我们不需要修改或调试代码,这就没什么问题。不过,如果我们要修改或调试,问题就来了。从根本上说,调试是一种活动,通过修改程序使它的行为与它应该做的事情保持一致。这就需要我们知道程序应该做什么,而这是无法从代码中获得的。有时候这很简单:它崩溃了,它应该做的肯定不是崩溃。除了这种简单的情况外,发现意图就比较困难了。


当应该做什么很微妙时,比如在构建分布式系统协议时,调试就特别困难。我们在论文“数以百万计的微型数据库”中写到:


我们在代码审查、simworld 测试和设计会议时经常回顾协议的 TLA+模型,以解决 Java 代码或书面交流中的歧义。


问题在于协议的实现(在 Physalia 的例子中是 Java 代码),它既不完美,又过于具体。它过于具体是因为它需要完全确定。计算机需要这样,而协议本身也有一定的回旋余地。它过于具体还因为它必须处理诸如底层性能问题等规范未考虑的问题。


那些值存储在 ArrayList 中是因为顺序很重要,还是因为 O(1)随机查找很重要,又或者是因为其他原因?还是因为这样写最容易?如果我把它改了会发生什么?


虽然不能和分布式协议相提并论,但业务逻辑代码存在更多这类问题。代码的业务逻辑过于具体,而又不够准确。我写这篇文章是因为 @mcclure111 的一条推特,她可以说是一语中的:


由于大多数软件都没有一个形式化的规范,所以大多数软件都是“做什么就是什么”,在编辑别人的代码时,要尊重作者的意图就要承受难以置信的压力。你不知道哪些怪异的模式是真正承担负载的。

(@mcclure111),2020年6月20日


这是代码的一个大问题:你不知道哪些怪异的模式是真正承担负载的。你可能记得,或者能够猜测,或者能够从基本原理中找出答案,或者你根本不关心,但是所有这些都会降低你的速度,并且容易出错。我们能做些什么呢?

设计文档

文档一点儿都不酷。大多数软件工程师从学校出来的时候,似乎都认为文档不是他们的工作(而是技术作家的工作),或者将其视为奇怪的东西,就像听他们的 SE 教授谈论那些像 Fortran 一样古老的东西一样。这在一定程度上是可以理解的。


我自己的软件工程课程就强调,要尽力用 UML 记录实现方式,此外没有提到其他文档。基本上,用 UML 重写软件对任何人都没什么帮助。我完成了我的学位,认为文档是不必要而又耗时的工作。甚至敏捷宣言也同意我的观点:


可工作的软件胜过面面俱到的文档。


后来我发现,设计文档记录了系统开发期间的意图和决策,可以帮助团队取得短期的成功,帮助人们取得长期的成功。我不再把所有的事情都记在脑子里,我有信心以后可以重新发现被遗忘的事实,这使我变得更加大胆,我能更快地行动。这同样适用于团队。


我看到,成功的团队不仅记录他们的设计内容以及背后的原因,而且还记录他们的决策过程。当需要对系统进行更改时,无论是为了调试还是为了响应不断变化的需求,这些文档都是非常宝贵的。如果你不知道当初为什么这样写,就很难确定更改某个东西是否安全。记录下你是如何做出决定的,这很重要,因为我们不是完美的人,知道以前的决策过程,有助于了解你的决定何时会显得奇怪或令人惊讶。


文档不必太繁琐。除非你认为它们有帮助,否则不必费心绘制ER图。你可能应该完全忽略 UML。取而代之,你应该尽可能清晰和简洁地用文字来描述这个系统。你可以从为团队构建 RFC 模板开始,该模板可能受你在网上找的模板的启发。SquareSpace的模板似乎就很合理。有些设计适合 RFC 格式,有些则不适合。尽可能地平铺直述。


然后,保存这些文档。把它们放在安全的地方。同时,要确保需要维护系统的人能够找到它们。在探索历史的过程中,让他们更像一个图书馆的访客,而不是劳拉·克罗夫特(古墓丽影的主角)。


我并不提倡预先进行大量设计。关于一个项目,我们学到的许多最重要的东西都是在实施过程中学习的。其中一些最重要的事情是我们在实施完成数年后才知道的。设计文档不是一个静态的一次性提前交付,而是一个持续的过程。最重要的是,设计文档并不是要恪守坏主意。如果有错误,就纠正它,然后继续前进。文档不是与魔鬼的交易。

注释

很少有话题像注释一样能引起程序员的激烈争论。我们被告知,注释是愚蠢的,或者是幼稚的,或者难以表现出你在编写令人费解的混乱代码时的男子气概。如果它很难编写,那么它也应该很难读懂。毕竟,你是编码界的詹姆斯·乔伊斯(爱尔兰作家)。


先不说这些愚蠢的想法,让我们回到 @mcclure111 的话题:


这意味着“揭示”作者意图的注释是有价值的,而揭示“作者没有意图”的注释则更有价值。如果没有这些提示,您只能迷信地编辑,即使不知道为什么也要保留那些怪异的模式。

(@mcclure111),2020年6月20日


注释让我们可以将作者的意图编写到代码中,而编程语言本身并不总是能做到这一点。类型、特性、接口和变量名确实可以将意图置入代码中,但并不完全是这样(我看到您了,类型系统最高纲领派)。这些东西是可以传达缺失的意图——考虑一下RandomAccessArrayList——但这也是不完整的。注释良好的代码应该清晰描述作者的意图,特别是当意图在转换为代码的过程中丢失,或者实现约束隐藏了设计意图时。可以链接到设计文档的代码注释特别有用。


有些语言比其他语言更需要注释。我发现,有些语言(比如 SQL)几乎总是掩盖了实现细节背后的设计意图。

形式化规范

在“谁不画蓝图就建房子?”一文中,Leslie Lamport 写道:


对规范的需求来自两个观察结果。首先,在做之前先想好我们要做什么是个好主意,正如漫画家 Guindon 所说:“写作是一种自然的方式,让你可以知道你的想法有多草率。”

第二个是,要编写出一个好程序,我们需要考虑代码层面之上的问题。


我发现,从平铺直述的非形式化规范到 TLA+形式化规范,都能加快程序的编写速度,帮助我们减少错误。尽管我很喜欢那篇文章,但我认为 Lamport 忽略了形式化规范的一个重要价值:它是一个很好的交流工具。在开发我所构建的一些最棘手的系统时,我发现,有大量注释的形式化规范是非常有用的文档。规范说明语言都是描述意图的,有些可以很容易地将意图与实现区分开来。


下面这段话还是来自论文“数以百万计的微型数据库”:


在亚马逊,我们广泛使用了 TLA+,事实证明,它在 Physalia 的开发中非常有用。在我们的团队中,TLA+有三种用法:编写协议规范,从而检查我们是否对协议有了深入的理解;使用 TLC 模型检查器针对正确性和活跃度设计检查规范;编写带有大量注释的 TLA+代码,作为分布式协议的文档。虽然这三种方法都增加了价值,但对 TLA+而言,作为一种自动测试的(通过 TLC)、极其精确的协议文档格式,可能是最有用的。


形式化规范可以帮助我们编写优秀的文档。就像设计文档一样,它们不是不可变的工件,而是反映了我们对这个问题的了解。

总结

构建长期的、可维护的系统不仅需要与计算机通信,还需要与他人交流,并与未来的自己沟通。沟通、记录和索引设计背后的意图是这个情景的重要组成部分。请抓紧时间,否则以后可能会后悔的。


英文原文:


Code Only Says What it Does


2020-07-25 10:001682
用户头像

发布了 774 篇内容, 共 526.4 次阅读, 收获喜欢 1578 次。

关注

评论

发布
暂无评论
发现更多内容

财务团队应如何推动企业创新升级和可持续发展

智达方通

团队协作 企业管理 战略规划 全面预算管理

再创辉煌!望繁信科技斩获第十三届中国创新创业大赛四川赛区桂冠

望繁信科技

数字化转型 流程挖掘 流程资产 流程智能 望繁信科技

现在的 AI ,有多会做老师?

豆包MarsCode

Python 人工智能 程序员 AI 求职

对游戏语音软件Oopz遭遇DDoS攻击后的一些建议

网络安全服务

负载均衡 udp 语音聊天软件 DDoS 攻击 黑神话悟空

如何高效的匹配、筛选数据,避免嵌套循环

六哥是全栈

Java ts 开发技巧

代币化资产如何拯救 DeFi:让金融重回价值创造的正轨

区块链软件开发推广运营

交易所开发 dapp开发 链游开发 NFT开发 代币开发

洞悉市场脉搏,从实时监控商品信息开始 —— 淘宝API的力量

技术冰糖葫芦

API Explorer平台 api 网关 API Gateway API 测试 pinduoduo API

mac苹果电脑矢量绘图软件:Sketch for mac 中文激活版

你的猪会飞吗

sketch Mac Mac软件下载站 mac破解软件下载

电商数据分析师必备:京东商品详情API返回值解读

技术冰糖葫芦

api 网关 API Gateway API 测试 pinduoduo API

如何留住自己的团队?

秃头小帅oi

华为视频独家呈现:发布会开场舞《见非凡》AiMax 版来袭

最新动态

Python将表格文件中某些列的数据整体向上移动一行

不在线第一只蜗牛

Python 机器学习 Excel

软件测试学习笔记丨Vim编辑器的常用命令

测试人

软件测试

低代码平台与云服务技术研究白皮书

不在线第一只蜗牛

低代码 云服务

互联网大厂Java面试高手心法,在寒潮之下找到自己心仪的 offer。

码哥字节

Java 后端面试

关于粒子滤波的解析

芯动大师

粒子滤波

读书笔记:简单高效的工作方式

老张

读书笔记 团队管理 远程办公

第67期 | GPTSecurity周报

云起无垠

李飞飞团队 ReKep:空间智能机器人可整合 GPT-4o;苹果首款 AI 手机 iPhone 16 发布丨RTE 开发者日报

声网

爱回收商品详情数据接口

tbapi

爱回收API 爱回收商品详情数据接口

新闻“样板间”提升50%开发效率,20家新闻媒体应用批量鸿蒙化

最新动态

DApp开发入门指南:从概念到实践

区块链软件开发推广运营

交易所开发 dapp开发 链游开发 NFT开发 代币开发

什么是 structuredClone?如何实现深拷贝?

伤感汤姆布利柏

AI加持的云端IDE——三种方法高效开发前后端聊天交互功能

豆包MarsCode

人工智能 ide 程序员 AI 编程语言

DBeaver 24.2 发布下载,新增功能概览

sysin

数据库 sql 管理工具 Dbeaver

议程抢先看!安谋科技、英特尔、浪潮信息、蚂蚁集团等企业大咖齐聚 2024 云栖大会操作系统开源专场

OpenAnolis小助手

操作系统 云栖大会 龙蜥社区 龙蜥操作系统 AIibaba CIoud Linux

参赛心得和思路分享:2021第二届云原生编程挑战赛2: 实现一个柔性集群调度机制

阿里云天池

云原生

代码只能说明它能做什么_语言 & 开发_Marc Brooker_InfoQ精选文章