纪律不成比例

2020-10-21 09:02:19

如果程序员更有纪律,更专业,他们会写出更好的软件。他们所需要的只是一份行为准则,告诉他们如何像我们这些已经解决问题的人一样工作。

上面的说法是正确的,这对于我们中那些有兴趣改善软件状态和帮助我们的同行改进他们的技术的人来说是一件好事。然而,除了完全没有必要之外,申请它也是非常困难和低效的。用我们这个行业的通俗说法来说,“纪律不成比例”。

考虑Objective-C编程语言中对象生命周期管理的轨迹,特别是下一种方言。在1989到1995年间,处理对象生命周期的主要方法是使用+new和-free方法,它们的工作方式与C中的malloc/free或C++中的new/delete非常相似。当然,使用这种所有权模型设计复杂的对象图是可能的,它只需要纪律,仅此而已。学习专家使用的启发式方法,以及确保正确性的技术,并使其正确。

但你知道什么更好吗?不需要做对这件事。因此,大约在1994年,人们引入了新的工具,以更简单的方式完成这项工作:引用计数。有了NeXTSTEP Mach Kit的NXReference协议和OpenStep的NSObject,开发人员不再需要知道应用程序中的每个人何时都完成了销毁它的对象。它们可以指示何时接受引用和何时放弃引用,对象本身将看到它何时不再使用并释放自己。学习关于自动释放和未保留引用的启发式方法和技巧,并使其正确。

但你知道什么更好吗?不需要做对这件事。因此,还引入了其他几个工具,它们非常接近,很可能是并行开发的[*]:Objective-C2.0垃圾收集(2006)和自动引用计数(2008)。ARC在流行的采用中“赢了”,所以让我们把重点放在这一点上:开发人员不再需要确切地知道何时保留、释放或自动释放对象。它们描述关系的含义,而不是描述关系的边缘,编译器将自动负责所有权跟踪。学习关于弱引用和“弱自我”舞蹈的启发式和技巧,并使其正确。

[*]我在这里忽略了Boehm保守GC与Objective-C明显更早的集成,因为其他人也是如此。这本身就是技术采用故事的重要组成部分。

但你知道什么更好吗?你明白我的意思。您可以在其他上下文中看到类似的事情发生:例如,C++从new/delete转移到智能指针的过程在类似的时间内遵循类似的轨迹。当面对在同一台计算机上使用不同技术并遵循规则的替代方案时,依赖整个编程社区正确处理一些困难的规则是很难说服的。

这看起来很简单:计算机的存在是为了使重复的信息处理任务自动化。当计算机可以做到这一点时,要求能够访问计算机的程序员回忆和跟踪重复的信息过程是浪费的。所以把这些任务交给计算机。

然而,对一些人来说,软件的问题不是缺乏自动化,而是缺乏纪律。如果人们知道规则,遵守规则,放慢脚步,而不是偷工减料,而只是选择忽略重要的业务里程碑,软件会更好。在我那个时代,每个人都知道“在镇上没有降价”和“劳动节后不要在IDE中编写代码”,但现在孩子们想做什么就做什么。动机似乎不同,我想把它们理清。

让我们从欺凌开始吧。软件行业的很多人都在遭受“我不得不经历这些,你也应该经历这些”的困扰。例如,看看软件工程面试。我不确定是否有人真的相信“我必须小心地确保NUL终止以避免缓冲区溢出错误,所以您也应该相信”,但我偶尔仍听到有人告诉经验较少的开发人员,他们应该学习C来更多地了解他们的计算机是如何工作的。您的计算机不是快速的PDP-11,您将学到的只是C虚拟机的工作原理。

就像真正的男人不吃乳蛋饼一样,真正的程序员也不使用Pascal。真正的程序员使用FORTRAN。这种将纪律与乌合之众区分开来的动机是基于这样一种想法,即如果它不像我做这件事时那样难,那就不够难。这意味着,根据演说家的经验,球门柱是可移动的。

这通常与他们的经验有关:您不需要输入脚本来编写好的响应原生代码,只需要Javascript和一些规则即可。要编写好的前端代码,您不需要Reaction Native,只需要JQuery和一些规则即可。您不需要JQuery…。

但伴随着经验的术语,广度也随之消失。您知道,1995年学习引用计数的人认为只有手动键入自己的引用更改事件才能真正理解编程,他大概在1996年没有继续使用Java中的垃圾收集。那个认为只有在每个案例都伴随着单元测试的情况下才能真正编写正确软件的人,大概没有学过埃菲尔。认为只有使用Haskell类型的系统才能真正设计系统的人可能没有尝试过OCaml。诸若此类。

结论是,对于这类纪律人员来说,他们在职业生涯的某个特定阶段必须处理的任何事情,都应该具有适当的纪律性质和数量。可能是一个高潮:在他们克服了棘手的部分并变得富有成效之后,在你们这些孩子出现并毁了一切之后。

有时,提出这种有纪律的方法的理由本质上是昆虫学的,就像“表演者”这种真社会昆虫的例子,它虽然不是一个真正的词,但显然在旧软件中比在新软件中存在的数量更多。Performant能够使软件更快,或者使用更少的内存,或者更多的并发,或者更少地依赖I/O:Performant的特定特征在很大程度上依赖于上下文。

表演者通常不会和它通常的同伴--无关紧要的人--在同一句话里被谈论。是的,通过从自动工具切换到手动、有纪律的方法,可能会有机会将该算法的运行时间减少几个百分点,但这重要吗(目前或根本不重要)?有一些软件构建领域需要特定的性能特征,事实上,在很多软件中都是如此。但是,典型的做法是将性能增强技术集中在需要增强性能的BIT上,而不是在每个人都这样工作更好的基础上在整个系统中采用它们。编写本机软件可能会节省数百个周期,而不是将VM用于该UI方法,但是如果它要在网络请求在EDGE上完成之后运行,然后触发1/3秒动画,没有人会注意到改进。

无论从何而来,呼吁纪律的问题在于没有强烈的动机去变得更有纪律。我可以使用这些工具,我的客户非常满意,我的雇主付给我这么多钱。或者我可以从你那里学到我应该怎么做,这会减慢我的速度,对于…来说。你满意吗?所以你知道我是按照应该做的方式来做的?或者这样我就可以告诉其他人他们也做错了?听起来挺划算的。

因此,纪律是不成比例的。每当你要求一些人放慢脚步,更努力地思考他们正在做的事情时,他们中的一小部分会这样做。有些人会想知道有没有其他方法可以买到你在兜售的东西,而且可能会找到。更多的人不会在意。危险的人是那些认为他们在关注,但最终仍然没有做你要求的有纪律的事情的人:他们要么破坏了你的整个想法,要么把它变成了不做事情(参见OOP、敏捷、函数式编程)。还有更多的人,到目前为止,绝大多数人根本没有在听,你永远也无法联系到他们。

让我们把这件事翻过来。让我们看看我们需要在哪里受到约束,并询问一下在对软件工程师的工具支持方面是否存在差距。有些人希望我们总是编写失败的测试并使其在添加任何代码之前通过(或者希望我们编写通过的测试并在意外失败时恢复我们的更改):这是否意味着我们的工具不应该让我们编写没有测试的代码?验收测试也是如此吗?有些人希望我们毫不留情地重构;这是否意味着我们的设计工具应该总是提出更简约的替代方案来通过相同的测试?有些人说,我们应该养成编写总是揭示其意图的代码的纪律:这些工具是否应该尝试将代码的意图解释为散文?