编程与软件工程yosefk.com
为什么糟糕的科研代码胜过遵循“最佳实践”的代码
Why bad scientific code beats code following “best practices” (2014)
2014 — 2024,它一次次回到首页
黑点是上首页(≥ 50 分)的那次投稿,空心点是没冲上去的投稿,点越大分数越高。
导读
这是程序员兼科研软件开发者 Yosef 的博客文章,讨论为什么科研人员写的"丑陋"代码往往比严格遵循软件工程最佳实践的代码更有效。作者认为,科研代码的目标是快速探索、得出可验证的结果,而很多最佳实践(模块化、抽象、单元测试、文档)在探索性、短周期、单人使用的场景下反而是负担。文章以随笔和吐槽的笔调写成,属于经验之谈而非严谨论证。
为什么经久不衰:它点破了一个长期存在的张力:软件工程的"最佳实践"有适用边界,在探索性科研代码里可能适得其反——这个争论十几年后仍在反复被提起。
HN 评论精选
业界正出现对教条式最佳实践的反弹,并举出若干资深开发者的例子。
我觉得现在有一股越来越强的反弹,针对的正是那种会导致文章里所说问题的软件开发"最佳实践"。我看到游戏行业的资深开发者公开反对诸如面向对象、函数长度限制这类神圣原则。举几个例子:Casey Muratori 的"Compression Oriented Programming"、John Carmack 关于内联代码的文章、Mike Acton 的"Data-Oriented Design and C++"演讲、Jonathan Blow 关于软件质量的演讲。
modeless查看英文原文
I think there is a growing rebellion against the kind of software development "best practices" that result in the kind of problems noted in the article. I see senior developers in the game industry coming out against sacred principles like object orientation and function size limits. A few examples: Casey Muratori on "Compression Oriented Programming": https://mollyrocket.com/casey/stream_0019.html John Carmack on inlined code: http://number-none.com/blow/john_carmack_on_inlined_code.html Mike Acton on "Data-Oriented Design and C++" [video]: https://www.youtube.com/watch?v=rX0ItVEVjHc Jonathan Blow on Software Quality [video]: https://www.youtube.com/watch?v=k56wra39lwA
杂乱代码只在少数人短用时可行;要长期演进的项目仍需软件工程,但反对乱套设计模式。
这篇文章是轶事性的、带情绪的,但我还是要回应一下。我过去 15 年一直在做清理科研代码库的项目。如果只有极少数人使用,杂乱未工程的代码没问题;但如果代码库要随时间演进,你就需要良好的软件工程,否则它会变得脆弱、难以维护。话虽如此,很多"程序员"不加思考地乱套设计概念,反而把东西搞得更乱。高质量的软件工程是一门需要长期学习的技艺。文章说程序员因为不做科研这种"真正的工作"所以闲得发慌,这显然很荒谬——任何称职的程序员都忙得要命,并且花很多心思优化自己的时间。结论是:对于会长大的项目,科学家应该和软件工程师合作,并且要雇那些有可维护软件交付记录的人。
jcoffland查看英文原文
This article is anecdotal and ranty but I will respond anyway. I've spent the last 15 years working on various projects involving cleaning up scientific code bases. Messy unengineered code is fine if only a very few people ever use it. However, if the code base is meant to evolve over time you need good software engineering or it will become fragile and unmaintainable. That said, there are many "programmers" who apply design concepts willy nilly with out really understanding why. They often make a bigger mess of things. There is an art to quality software engineering which takes time to learn and is a skill which must be continually improved. The claim in the article that programmers have too much free time on their hands because they aren't doing real work, like a scientist does, is obviously ridiculous. Any programmer worth their salt is busy as hell and spends a lot of thought on optimizing their time. Conclusion, scientists should work with software engineers for projects that are meant to grow into something larger but hire programmers with a proven track record of creating maintainable software.
最佳实践取决于项目规模与性质,探索性项目过早定架构反而有害。
大多数人似乎忘了"最佳实践"并非普适:取决于项目的规模和范围,有些最佳实践其实是最差实践,会拖慢你。比如单元测试和详尽文档对短期项目/原型可能无关紧要,但对需要被别人理解使用的代码则不可或缺。另外,对于探索性项目(科研项目往往如此),一开始就定义完整的代码架构通常没用,因为随着你对问题理解的加深,关于代码该如何工作、如何组织的假设多半会变。此时强行套用某个范式(比如 OOP 或 MVC)甚至会造成"架构引发的损害"。项目规模也是重要因素:从我自己的经验看,多数软件工程方法要到超过 5000–10000 行代码时才有正的投资回报……
ThePhysicist查看英文原文
What most people seem to forget is that "best practices" are not universal: Depending on the size and scope of the software project, some best practices are actually worst practices and can slow you down. For example, unit testing and extensive documentation might be irrelevant for a short term project / prototype while they will be indispensable for code that should be understood and used by other people. Also, for software projects that have an exploratory nature (which is often the case for scientific projects) it's usually no use trying to define a complete code architecture at the start of the project, as the assumptions about how the code should work and how to structure it will probably change during the project as you get a better understanding of the problem that you try to solve. Trying to follow a given paradigm here (e.g. OOP or MVC) can even lead to architecture-induced damage. The size of the project is also a very important factor. From my own experience, most software engineering methods start to have a positive return-on-investment only as you go beyond 5.000-10.000 lines of code, as at this point the code base is usually too large to be understandable by a single person (depending on the complexity of course), so making changes will be much easier with a good suite of unit tests that makes sure you don't break anything when you change code (this is especially true for dynamically typed languages). So I'd say that instead of memorizing best practices you need to develop a good feeling for how code bases behave at different sizes and complexities (including how they react to changes), as this will allow you to make a good decision on which "best practices" to adopt. Also, scientists are -from my own experience- not always the worst software developers as they are less hindered by most of the paradigms / cargo cults that the modern programmer has to put up with (being test-driven, agile, always separating concerns, doing MVP, using OOP [or not], being scalable, ...). They therefore tend to approach projects in a more naive and playful way, which is not always a bad thing.
科学家的代码结构往往映射数学抽象,而非软件架构抽象,所以"丑陋"但可信。
利益声明:我是刚毕业的天文系学生,专攻计算天体物理,肯定有偏见。问题在于,至少对许多科学家和数学家来说,数学抽象和代码抽象往往是相互正交的两件事。数学抽象(积分、数学术语等)有数百年历史,领域极其精确、严谨、定义明确,用以以数学方式管理复杂度;代码抽象则出现得晚、灵活、定义模糊,用以以架构方式管理复杂度。科学家往往已经用数学抽象解决了问题,比如 Runge-Kutta 方法的每一步,每步的积分和函数值都定义明确,于是他们想把每一步一一映射到代码里,结果写出一堆散布着 if/else 的代码块。这在软件工程标准看来很糟糕,但在科学家眼里,代码只是遵循了数学本身给出的抽象。这也是为什么来自意大利面式代码的结果往往仍可信任——代码实现的方法本身通常已经过验证。
whorleater查看英文原文
Disclosure: I'm a recent astronomy grad who specialized in computational astrophysics. Definitely biased. The issue is that at least for many scientists and mathematicians, mathematical abstraction and code abstraction are topics that oftentimes run orthogonal to each other. Mathematical abstractions (integration, mathematical vernacular, etc) are abstractions hundreds of years old, with an extremely precise, austere, and well defined domain, meant to manage complexity in a mathematical manner. Code abstractions are recent, flexible, and much more prone to wiggly definitions, meant to manage complexity in an architectural manner. Scientists often times have already solved a problem using mathematical abstractions, e.g. each step of the Runge-Kutta [1] method. The integrations and function values for each step is well defined, and results in scientists wanting to map these steps one-to-one with their code, oftentimes resulting in blobs of code with if/else statements strewn about. This is awful by software engineering standards, but in the view of the scientist, the code simply follows the abstraction laid out by the mathematics themselves. This is also why it's often times correct to trust results derived from spaghetti code, since the methods that the code implements themselves are often times verified. Software engineers see this complexity as something that's malleable, something that should be able to handle future changes. This is why it code abstractions play bumper cars with mathematical abstractions, simply because mathematical abstractions are meant to be unchanging by default, which makes tools like inheritance, templates, and even naming standards poorly suited for scientific applications. It's extremely unlikely I'll ever rewrite a step of symplectic integrators [2], meaning that I won't need to worry about whether this code is future proof against architectural changes or not. Functions, by and large in mathematics, are meant to be immutable. Tl; dr: Scientists want to play with Hot Wheels tracks while software engineers want to play with Lego blocks. [1]: https://en.wikipedia.org/wiki/Runge–Kutta_methods [2]: https://en.wikipedia.org/wiki/Symplectic_integrator
历次讨论
同类还值得读
开源应用架构
The Architecture of Open Source Applications
《开源软件架构》(AOSA)是一本在线免费书,邀请知名开源项目的作者亲自剖析其内部设计,涵盖 SQLAlchemy、LLVM、Audacity、Apache、Bash 等系统。
编程与软件工程上首页 9 次 · 2011–2024aosabook.org编辑精选编程语言简史:简短、不完整且多半错误
A Brief, Incomplete, and Mostly Wrong History of Programming Languages
一篇以戏谑、故意不准确的方式回顾编程语言史的博客文章,用夸张轶事和讽刺定义串起 Lisp、C、C++、Java、JavaScript、PHP 等语言。
编程与软件工程上首页 8 次 · 2009–2021james-iry.blogspot.comSQLite 是如何测试的
How SQLite is tested
SQLite 官方文档页,系统介绍 SQLite 的测试体系:多种测试方法(TCL 测试、模糊测试、回归测试、静态分析等)和海量测试用例,展示了这个小型开源项目如何靠极致测试获得…
编程与软件工程上首页 8 次 · 2009–2025sqlite.org编辑精选高级编程语言(2009)
Advanced programming languages (2009)
Matt Might 的经典文章,按用途推荐“高级编程语言”:如果追求就业就选主流语言,如果追求表达力、学术研究或创业,则推荐 Haskell、OCaml、Scala 等函数式语…
编程与软件工程上首页 8 次 · 2009–2022matt.might.net我的 Forth 与栈机器经历
Yosefk - My history with Forth & stack machines
作者以亲身经历回顾了使用 Forth 语言和栈式机器的历程:既赞叹其简洁优雅、代码量小、可自举的优点,也坦率指出栈操作在实际编程中的痛苦,以及 Forth 社区文化中的问题。
编程与软件工程上首页 8 次 · 2010–2024yosefk.com编辑精选