为何糟糕的科研代码胜过严格遵循编程规范的代码 [译]

作者:

Proper Fixation

我刚读了一篇名为“科学代码的低质量”的文章,作者认为科学家编写的代码质量不如涉及到“软件工程师”的情况。

在过去的十多年里,我一直在一个以数学或物理背景人士为主的环境中工作,这里的人对“软件工程”的了解相对有限。

一直以来,最大的混乱往往是那些自认为是程序员的少数人造成的。我必须承认,自己也曾制造过几次大混乱,而这些混乱至今还未得到解决。还有几次其他的大混乱,幸好代码被废弃了,这意味着给我的雇主造成的损害仅限于我薪水的浪费,没有对他人的工作效率产生负面影响。

我声称自己基本上已经改过自新了。我努力保持事情的简单无聊,并且我认为在过去 5-6 年里,我没有做过什么让许多人因为处理我错误的聪明创意而奇怪地看着我。

我也知道一些程序员明确地没有改过自新。人们怪异地看着他们,而他们则认为自己是对的,是其他人疯了。

同时,那些不是程序员,但更像是数学家、物理学家、算法开发者、科学家等人,通常会犯以下几种错误:

  • 函数过长
  • 取名不佳(如 m、k、longWindedNameThatYouCantReallyReadBTWProgrammersDoThatALotToo)
  • 随处访问 – 全局变量/单例、“全能对象”等
  • 崩溃(空指针、边界错误),主要依靠 valgrind 和大量测试来减轻
  • 对并行编程错误的漠不关心(几乎完全依靠工具解决)
  • 过于轻易地使用那些由聪明的程序员编写的库,这些库中充满了重载操作符和模板等复杂内容

我觉得这些还算可以处理。如果有人需要我的帮助来调试某些东西,我通常能够理解这些人在软件方面想要做什么。在算法层面,我可能不完全理解他们。但是他们想把哪个变量传递给哪个函数,我通常都能明白。

而软件工程师的错误则完全不同:

  • 复杂的多重/虚拟继承
  • 主要由轻量包装构成的 7 到 14 层栈帧,其中包括函数指针/虚函数,可能还在中断处理程序中
  • 文件散布在无数目录中
  • 使用来自地狱的动态结构进行查询 - 如运行时拼接各种部分形成的名称的字典等
  • 动态加载和其他难以追踪的技术
  • 一系列近乎相同的名称,如 DriverController、ControllerManager、DriverManager、ManagerController、controlDriver 等,它们相互调用
  • 模板调用重载函数,希望在模板定义的地方可见声明,或许不可见
  • 使用装饰器、元类、代码生成等技术

其结果是,你不知道谁调用了什么或为什么,调试器的作用有限,集成开发环境和搜索工具几乎

无法使用。你几乎不得不放弃理解这一切,直到泪水不自觉地流出。

当然,这是一个夸张的描述,不是每个人在任何时候都是罪人,而且我主要是一名“程序员”而不是“科学家”,我真诚地认为我的工作总体上是有积极成效的 - 但你应该明白我的意思。

科学代码能从更好的“软件工程”中受益吗?也许可以,但我不相信软件工程师能带来这些益处!

简单的思维、无忧无虑的近乎无能有时可能比满怀好意却铺设了通往地狱的高速公路的工业级专业更为有益。计算机外的“真实世界”充满了这样的例子。

哦,还有一个非常尖锐的观察,我害怕这太过真实而不能忽略:懒惰是许多问题的根源。科学家忙于科学研究,因此他们没有时间无谓地增加代码的复杂度。许多程序员的工作实际上并不复杂 - 任务很简单 - 所以他们有太多的时间,他们用这些时间沉迷于“API 设计”,于是就产生了怪物。

(实际上,当工作在技术或社会层面上远非琐碎时,程序员糟糕的训练使他们的注意力偏离了直接的职责 - 这个东西是否真的运行良好、易于使用、高效/经济等 - 而是宣称自己只负责神圣的 API,并开始使其变得异常复杂。与此同时,从功能上来说,这个东西几乎无法运行。)