acm-header
登录

ACM通信

Kode恶性

软件开发的邪恶三位一体


软件开发的邪恶三位一体,插图图片

图片来源:安德烈·波波夫

回到顶部

亲爱的KV

我读您的专栏已经有几年了,您也写过几次关于测试和文档的文章,但是您没有写过这两者之间的关系。许多大型项目,包括我现在所从事的项目,都将它们的测试和文档与代码以及彼此分离开来。我已经和我的团队争论过把这两种方法放在更接近源代码的地方,甚至嵌入到源代码中,但是总是有一些工程师拒绝在源文件中除了代码和注释之外的任何东西。他们的论点是最大化用于代码上下文的屏幕空间,但这似乎更适合25行终端,而不是现代开发环境。为了让这个软件团队对我们正在开发的系统采用一种更全面的方法,您有什么理由?

系统的人

亲爱的如果

这样的问题会让人想起这样一个事实:源代码、文档和测试是软件开发的邪恶三位一体,尽管许多组织喜欢将它们视为独立的实体。有趣的是,尽管许多团队口头上支持“测试驱动开发”,但他们并不在TDD中包含文档。

我想您已经发现了许多开发人员反对将测试和文档集成到源代码中的原因之一,这些代码要么直接集成到源文件中,要么甚至在靠近的同一个目录中。反对这种集成的论点包括您提到的关于代码垂直空间的论点。让我们先解决这个问题。

软件开发人员喜欢新玩具。他们当然喜欢:他们在电脑上工作,电脑对我们来说是玩具,每个人都喜欢闪闪发光的东西。如果你参观一家现代软件公司,除了一大堆Aeron椅,你还能看到什么?大量的显示器,其中许多是4K类型的,这意味着一个文本编辑器,即使使用大字体,也会给您提供100多行代码——这比自20世纪70年代以来用于编写代码的80×25显示器增加了400%。

有一派观点认为,100行的函数或方法太长了,应该分解成更小、更容易理解的块。如果您在这样的环境中工作,那么开发人员就没有理由反对在代码本身中集成文档或测试,因为一个25行函数上面可以有10行文档,而一个合理的文档系统,如Doxygen,可以将这组“文档小文件”组合成一个更大的整体。顺便说一下,这个更大的整体需要由能够将其转化为适合他人阅读的语言的人来审查。最糟糕的代码文档是那种与代码本身不同步的文档。第二糟糕的文档类型是工程师写一些明显的东西,foo ()函数返回bar,从代码中很容易看出。

这种文档的最佳类型解释了函数的功能、可能的错误条件以及调用代码时需要什么条件。多线程应用程序确实需要在这样的文档块中描述锁定需求。对于某些产品,例如面向终端用户的系统,这些文档块通常不会出现在最终的手册中,但它们对负责编写手册的人非常有用。由其他程序员使用的库和其他系统绝对必须有这种风格的文档,以保持所有相关人员的理智。

关于将测试集成到源代码中,嗯,KV可能有点过时了,但我确实看到这有点困难,可能需要在源代码中嵌入特殊的功能,或者需要源代码编辑系统具有特殊的功能,或者两者都有。即使有超过100行的垂直空间用于编码和记录,添加任何大量的一致性测试肯定会使代码变小,并使每个源文件相当大和笨拙。


虽然许多团队口头上支持“测试驱动开发”,但他们并不在TDD中包含文档。


代码折叠是许多文本编辑器的一个常见功能,如果您真的执意要将邪恶的三位一体放在一个文件中,它可能会有所帮助。每个源文件的顶部将包括整体文档,一个描述模块及其在系统中的用途的大块。然后,将源代码放在类/方法/函数文档之间,对代码的一致性测试放在最后。

对于折叠方法,您会遇到的主要抱怨是它需要特殊字符和智能代码编辑器,尽管此时Vim也有代码折叠功能。由于在源文件中折叠通常需要特殊的标记,因此对于整个项目将这些标记标准化是有意义的,这样文档、测试和源代码就各有一个标记。

将所有这些东西结合起来的一个好处是,您使用的工具(包括编译器、编辑器、测试框架和文档提取器)都可以指向相同的目录层次结构。将测试、文档和代码分开会使各种工具的搜索路径复杂化,并导致错误,例如指向错误的位置并得到错误的测试,或类似的问题。

将这三个组件组合在一起,使它们能够轻松地协同开发,这有很多优势,但您仍然需要帮助人们克服终端的思维定式。这些争论常常让人想起尼尔·斯蒂芬森的下面一幕雪崩溃在书中,他描述了主角(名字很烦人的主人公宏)是如何写代码的:“……在那里,你在元宇宙中看到的一切,无论多么逼真、美丽和立体,都简化为一个简单的文本文件:电子页面上的一系列字母。这是人们通过原始的电传打字和IBM打孔卡为计算机编程的时代的倒退。”

下次当你的队友抱怨在测试或文档上浪费了垂直空间时,给他们一张打孔卡。

KV

亲爱的KV

在过去的10年里,我注意到我的软件可用的CPU内核的数量一直在增加,但这些内核的频率并不比我离开学校时多多少。在这种趋势刚开始时,多核软件是一个大话题,但现在它似乎没有那么多的讨论,因为系统通常有6个或更多的核心。大多数程序员似乎忽略了内核的数量,并像系统只有一个CPU时那样编写代码。这只是我的印象,还是意味着我今年选错了公司?

核心好奇

亲爱的核心

多核硬件对软件设计的主要贡献是将每个系统变成一个真正的并发系统。最近发布的一款电子表有两个核心,人们仍然认为“电子表是一个非常巧妙的想法”(如道格拉斯·亚当斯的银河系漫游指南).当当前的计算机语言被编写出来时,唯一真正的并发系统是罕见的和昂贵的野兽,用于政府研究实验室和其他类似的稀有场所。现在,任何一个小丑都可以从互联网上购买一个并发系统,将其安装在数据中心中,并向其推送一些代码。事实上,只要按一个按钮,这样的小丑就可以在云中获得这样的系统。这种系统的软件要是这么容易就能得到该多好啊!


软件的目的是处理数据,因此获取数据并改变它们或改变状态。


撇开大多数应用程序都是在多核通信服务器上实现的分布式系统这一事实不谈,我们对现代软件和硬件的并发特性又能说些什么呢?简短的回答是"都是废话"但这对我们没有帮助也没有建设性,而KV的宗旨就是提供帮助和建设性。

从我们形成计算机科学的这些年里,我们都知道在并发系统中可以同时执行两个不同的代码段,而在现代服务器上,这个数字很容易是32或64,而不是两个。随着并发性的增加,复杂性也在增加。软件被编写成一组线性步骤来执行,但是根据软件的编写方式,它可能被分解成许多可能同时运行的小部分。只要软件在并发代码之间不共享任何状态,一切都很好——就像任何其他非并发软件一样。软件的目的是处理数据,因此获取数据并改变它们或改变状态。不在并发部分之间共享状态的重要软件系统的数量是非常非常少的。

当然,专门编写的没有并发性的软件更容易管理和调试,但是它也浪费了运行它的系统的大部分处理能力,因此越来越多的软件从非并发转换为并发,或者从头开始编写并发性。对于任何重要的系统,用更新的、支持并发性的语言重写软件可能比用传统并发原语改造旧软件更容易。

现在,我相信您一定读过看起来非并发的代码——也就是说,它在其进程中没有使用线程——您可能认为这很好,但是,唉,没有什么是真正的好。使用一组程序并让它们通过(例如,文件系统或共享内存)共享数据(这是一种具有某种并发级别的常见早期方法)并不能保护系统免受死锁或其他并发错误的危害。通过在两个并发进程之间传递一组消息而导致软件死锁的可能性与使用Posix线程和互斥锁做同样的事情是一样的。这些问题都可以归结为相同的事情:数据和数据结构的幂等更新、避免死锁和避免饥饿。

这些主题在有关操作系统的书籍中都有涉及,主要是因为操作系统首先遇到了这些挑战。如果在读完这些描述之后,您仍然感到好奇,我建议您读一本这样的书,这样您至少可以了解并发系统的风险,以及在构建、调试、再调试这类系统时可能踩到的地雷。

KV

ACM队列的q戳相关文章
queue.acm.org

山胡桃、迪胡桃、医生
Kode恶性
http://queue.acm.org/detail.cfm?id=2791303

微软协议文档计划:大规模互操作性测试
尼克·基西洛夫,沃尔夫冈·格里斯坎普和鲍勃·宾德
http://queue.acm.org/detail.cfm?id=1996412

安全关键软件的验证
斯科特·安德森和乔治·罗曼斯基
http://queue.acm.org/detail.cfm?id=2024356

回到顶部

作者

乔治·v·内维尔·尼尔kv@acm.org)是Neville-Neil Consulting的东主及ACM队列编辑委员会。他从事网络和操作系统代码方面的工作,教授各种与编程相关的课程,并鼓励您的评论、俏皮话和与他相关的代码片段通信列。


版权归作者所有。

数字图书馆是由计算机协会出版的。版权所有©2017 ACM, Inc.


没有找到条目

登录全面访问
忘记密码? »创建ACM Web帐号
文章内容:
Baidu
map