The Kollected Kode Vicious

Kode Vicious - @kode_vicious

  下载本文的PDF版本 PDF

Kode Vicious 持续战斗

一个态度强硬的程序员,KV 回答你的问题。他可不是礼仪小姐。

Kode Vicious 又来了,把你从代码的泥潭中拖出来,与常见的常识敌人作斗争。在战壕里,在黑暗的代码洞穴和虚假的逻辑中穿梭,有时会变得很丑陋,但是,嘿,总得有人去做。

亲爱的 KV,

我正在维护一些 C 代码,这工作快把我逼疯了。似乎我在任何文件中都无法超过三行,就会遇到一段条件编译的代码(即,用 #ifdef/#endif 宏括起来)。所有这些代码块都使代码难以阅读,调试几乎不可能,而且代码有很多错误。你以前遇到过这种情况吗?我很想重写所有代码,但我没有时间——当然,我赶着截止日期呢。

真诚的,

在我的 ifs 的尽头

 

亲爱的 Iffy,

KV 可以,唉,同情你的处境。虽然明智地使用 #ifdef/#endif 代码块有助于控制最终二进制文件中包含哪些代码,但过度使用这些宏会使代码几乎无法阅读,我讨厌无法阅读的代码。

在大多数情况下,你问题的真正根源是抽象的失败。在 C 语言中,以及在许多语言中,我们有称为函数的东西,拥有这些东西的原因是为了在程序的任何级别,必要的细节,不多也不少,都是显而易见的。这种平衡不容易实现,但在一堆代码中散布 #ifdef/#endif 子句绝对无济于事。

那些喜欢条件编译而不是使用函数调用或适当抽象的人给出了三个主要原因。

1. 具有条件编译块的代码速度更快,因为它不会产生函数调用的开销。曾经有一段时间这可能是真的,但那个时代早已过去。编译器比你聪明得多,并且比任何摆弄条件编译的工程师都更了解如何优化代码。与其摆弄条件编译,不如专注于使代码可读。

2. 条件编译的代码更小,因为它允许你挑选最终可执行文件中包含哪些代码位。这是另一种完全不必要的优化,而不是因为摩尔定律或 RAM 的成本。世界上已经有足够的臃肿软件了,KV 不想鼓励更多,谢谢。你看,构建程序不仅涉及编译器;还有其他组件,称为链接器和加载器。链接器的工作,正如其令人难以置信的透明名称所暗示的那样,是将程序从所有必要的位链接在一起,形成最终的可执行文件。自从大约 50 年前发明了库以来,链接器对于使使用多个文件编写的程序实际运行是必要的。

链接器有一个同伴,即加载器。虽然链接器完成了为程序查找所有必要的函数调用和库例程的工作,但加载器的工作实际上是将所有这些加载到内存中。所以,太好了,你说,现在我可以抽象我的所有软件并摆脱那些 ifdefs,但我的代码现在完全臃肿了。不完全是。通过现代计算机科学研究的奇迹,我们最近得到了动态链接和加载库的伟大礼物。

另一个透明命名的概念,动态链接器/加载器,正如其名称所暗示的那样。它在运行时,就在你眼前,动态地链接和加载代码。借助一组动态链接库,你的可执行文件将只是系统的一个小组件,如果正确抽象——又是那个讨厌的词——那么任何时候只有绝对必要的代码集才会驻留在内存中。当然,你必须运送相同数量的代码,但你不能抱怨你必须在启动时将所有代码都加载到内存中。

3. 我们使用条件编译来管理我们的构建系统,以包含和排除功能。KV 曾在这样的系统上工作过。最终可执行文件中的功能由一个头文件控制,该头文件包含大量的 #define/#undef 子句,用于打开和关闭功能。起初它看起来很聪明,直到你意识到使用该系统所需的知识量对于大多数人来说太大了,无法掌握。

这个系统的一个问题是,使用 #ifdef/#endif 隐藏了模块之间的相互依赖关系。当然,你可以通过取消定义 FOO_FEATURE 来删除它,但由于 BAR_FEATURE,你可能无法构建系统,而且由于整个系统是手工编写的,因此有必要自己记住这一点。随着系统扩展到包含更多功能,组合变得失控,以至于必须编写一个工具来管理 #ifdef。问题是该工具永远不够智能,无法正确完成工作,并且总是会遗漏或错误的部分,这导致难以诊断的错误。

最终,有必要编写一个新系统,该系统使用链接器来查找相互依赖关系,并将其表达给配置系统的人员。

另一个有趣的问题是,当然,人们在添加代码时添加了隐藏的假设,因为他们从未在最小配置下测试过该系统。许多功能的开发都假设整个可移除的子系统恰好在构建中。然后,现场的某人会尝试配置一个更小的系统,结果发现两个大型子系统——例如,网络代码和 Java 虚拟机——是紧密相连的。这导致了不愉快的会议,需要发布点版本并浪费工程精力。

现在我已经把一些东西从我的系统中排出来了,我仍然可以感觉到一些胆汁试图挣脱,但让我回到一个更具体的答案给你。查看代码,看看哪些条件编译的子句实际上可以变成函数调用,然后进行适当的抽象。我知道完全重写会花费太长时间——它们总是这样——但是重构代码,这只是一种委婉的、政治上正确的说法,可以称之为小规模的“重写”,可能会让你的生活更轻松。

KV

 

亲爱的 KV,

我们正在构建一个新的 Web 服务,我们的用户将能够在他们的 Web 帐户中存储和检索音乐,以便他们可以在任何他们喜欢的地方收听音乐,而无需购买便携式音乐播放器。他们可以在家中使用连接到互联网的计算机或在旅途中使用笔记本电脑收听音乐。他们也可以下载音乐,如果他们因为计算机问题而丢失了音乐,他们总是可以找回它。很棒,对吧?

现在是我的问题。在关于此的设计会议上,我建议我们只加密用户到 Web 服务的所有连接,因为这将为他们和我们提供最大的保护。一位资深人士只是对我投来厌恶的目光,我以为她真的要责骂我。她说我应该查阅一下身份验证和加密之间的区别。然后会议中的其他几个人笑了,我们继续讨论系统的其他部分。我没有构建系统的安全框架,但我仍然想知道她为什么这么说?我查看过的所有安全协议都具有身份验证和加密,所以这有什么大不了的?

真诚且真实的

亲爱的 Authentic,

嗯,我很高兴他们笑了;当不是我在尖叫时,尖叫声会伤到我的耳朵。我不确定你一直在阅读关于密码学的什么内容,但我敢打赌这是一些复杂的数学书,用于研究生算法分析课程。NP 完全性很迷人,而且确实很迷人,但这类书籍通常在抽象数学上花费太多时间,而在将理论应用于创建安全服务的具体现实上花费的时间不够。

简而言之,身份验证是验证实体(例如人、计算机或程序)是否是他们声称的那样或那样的能力。当你写支票时,银行会兑现它,因为你已在支票上签名。签名是该张纸上真实性的标志。如果稍后对你是否真的给我开了一张 100 万美元的支票有疑问——比如说如果我决定将其存入我的银行帐户——那么银行将检查签名。

加密是使用算法(无论它们是否在计算机程序中实现)来获取消息并对其进行加扰,以便只有拥有正确密钥来解锁消息的人才能检索原始消息。

从你的描述中可以清楚地看出,身份验证对你的 Web 服务比目前的加密更重要。这是为什么呢?嗯,你在这种情况下最关心的是用户可以收听他们在服务器上购买或存储的音乐。音乐不需要保密,因为不太可能有人会通过从网络嗅探来窃取音乐。更有可能的是,有人会尝试登录你用户的帐户以收听他们的音乐。用户将通过向你的服务进行身份验证来证明自己的身份,最有可能通过用户名和密码对。当用户想收听他们最近购买的商品时,他们会向系统提供他们的用户名和密码以获得访问权限。有很多不同的方法来实现这一点,但基本思想——用户必须向系统提供一些识别他们身份的信息才能获得服务——这就是使它成为身份验证而不是加密的原因。

密码不需要加密,只需在发送到服务器之前进行哈希处理即可。哈希是一个单向函数,它获取一组数据并将其唯一地转换为另一段数据,任何人都无法从中检索到原始数据,包括哈希函数的作者。重要的是哈希函数为每个输入生成唯一的数据,因为冲突会使两个不同的密码具有相同的哈希数据,这将使区分用户更加困难。

有很多关于这方面的东西的书籍和论文,但尽量避免不切实际的东西,除非你正在研究新算法,因为你真的不需要它,而且它只会让你头疼。

KV

KODE VICIOUS,凡人称为 George V. Neville-Neil,为了乐趣和利润而从事网络和操作系统代码工作。他还教授有关编程相关主题的课程。他的兴趣领域是代码探险、操作系统和重写你的糟糕代码(好吧,也许不是最后一个)。他获得了马萨诸塞州波士顿东北大学的计算机科学学士学位,并且是 、Usenix Association 和 IEEE 的成员。他是一位狂热的自行车爱好者和旅行者,自 1990 年以来一直以旧金山为家。

© 2005 1542-7730/05/0400 $5.00

acmqueue

最初发表于 Queue vol. 3, no. 3
数字图书馆 中评论本文





更多相关文章

Catherine Hayes, David Malone - 质疑评估非加密哈希函数的标准
尽管加密和非加密哈希函数无处不在,但在它们的设计方式上似乎存在差距。出于各种安全要求,存在许多用于加密哈希的标准,但在非加密方面,存在一定的民间传说,尽管哈希函数历史悠久,但尚未得到充分探索。虽然针对真实世界数据集的均匀分布很有意义,但在面对具有特定模式的数据集时,这可能是一个挑战。


Nicole Forsgren, Eirini Kalliamvakou, Abi Noda, Michaela Greiler, Brian Houck, Margaret-Anne Storey - DevEx 行动
随着领导者寻求在财政紧缩和人工智能等变革性技术的背景下优化软件交付,DevEx(开发者体验)在许多软件组织中越来越受到关注。技术领导者凭直觉接受,良好的开发者体验能够实现更有效的软件交付和开发者幸福感。然而,在许多组织中,旨在改善 DevEx 的拟议倡议和投资难以获得支持,因为业务利益相关者质疑改进的价值主张。


João Varajão, António Trigo, Miguel Almeida - 低代码开发生产力
本文旨在通过展示使用基于代码、低代码和极限低代码技术进行的实验室实验结果来研究生产力差异,从而为该主题提供新的见解。低代码技术已清楚地显示出更高的生产力水平,为低代码在短期/中期内主导软件开发主流提供了强有力的论据。本文报告了程序和协议、结果、局限性和未来研究机会。


Ivar Jacobson, Alistair Cockburn - 用例至关重要
虽然软件行业是一个快节奏且令人兴奋的世界,其中不断开发新的工具、技术和技巧来服务于商业和社会,但它也很健忘。在其快速前进的匆忙中,它容易受到时尚的突发奇想的影响,并且可能会忘记或忽略针对其面临的一些永恒问题的成熟解决方案。用例于 1986 年首次引入,并在后来普及,就是这些成熟的解决方案之一。





© 保留所有权利。

© . All rights reserved.