332 comments

[ 2.8 ms ] story [ 265 ms ] thread
TL;DR: a counter-productive rant against software engineers, claiming that bad code from software engineers is worse than bad code from scientists.

Did you consider hiring an experienced software engineer as a lead?

TFA seems to have hit a nerve.
If it's about ranting at classes of people, I can do it too: most software is shit, that's true. But somehow users like shit, and it makes profit so software engineers get paid to write it. They get valued by writing a lot of shit, not by writing little good code. Also most software engineers are juniors; junior civil engineers would not be allowed to build a bridge, junior software engineers can do all the crap they want.

But let's be fair: most scientists do bad research. Have you ever read papers in a field you know? 99% is bullshit. Not "non-conclusive good research", no. Downright useless, non-reproducible bullshit (or paraphrasing something that already exists, often making it worse). Just like software engineers, most scientists are juniors (we call them "PhD candidates") who get valued by publishing papers (any paper) in "recognized" journals (with some definition of "recognized"), by journals who make profit by accepting papers (any paper). Again not totally their fault: they have to produce recognized stuff in the time they are given, they don't have to produce good research.

I don't have a solution to those problems, of course: that's how the system works ("make profit"). I wish we tried to solve actual problems in a good way, but we don't. I don't think scientists are better than software engineers, though: we are all part of the problem. Less of all of us would make the world a better place (or would have prevented us from spoiling it, at least).

I just don't think my rant is worth publishing on HN.

You know, 96% of businesses (and by extension codebases) have to get by software wise without high priced software engineers. They couldn't afford it. The vast majority of running code is produced by people whose understanding of computer systems and programming goes as deep as how much documentation they need to ctrl+f through to get some specific tasks done.
>The vast majority of running code is produced by people whose understanding of computer systems and programming goes as deep as how much documentation they need to ctrl+f through to get some specific tasks done.

I doubt this very much. Surely the vast majority of running code is some chunk of Chrome, Android, or the JVM ("billions of devices run Java...") or something. All those things were produced by software engineers with more than surface-level understanding.

Maybe by instances of the same codebase, yeah absolutely.

But there is certainly more codebases out there running some python or js written by designers, data analysts etc then those produced and curated by software engineers.

For every well-engineered application used by millions of users, you've got thousands of poorly-engineered, bespoke applications in use by one or two users (often internal corporate tools or expensive middleware with minimal customization besides changing the corporate branding).
Still, I wouldn't consider "Chrome" as good software.

Let's be honest: web browsers are really bad. Overly complicated machines made to print images and text on the screen. The web got sideways long ago, first because it was cool to add crap in websites, then because it made profit and allowed monopolies to make more profit by moving everything to damn webapps. And finally it allows companies to screw users by renting software on the damn cloud.

And they profit by making it as accessible as possible, such that everyone and their dog can produce a crappy webapp that will show their ads or track their users.

Webtech is part of what makes software really bad, even if it was created by good engineers. Because people don't want quality: they want cheap new crap.

Bad code written by software engineers is worse than bad code written by scientists, as the former takes more effort to fix than the latter (given the pathologies mentioned). It's naturally preferable to not have bad code, but it that choice was actually on the table, then I don't know who would choose the bad code.

As for hiring software devs, that's not going to change (in general, there are places where software devs write code used by scientists, but rarely are these codes themselves pushing research boundaries, it's code on top it that does) absent significant changes in funding structure and rules (which are typically a government/public service concern, and not up to researchers).

> as the former takes more effort to fix than the latter

Disagree. Well, maybe still acceptable if the software is small / limited to a single paper. Having worked on a code base the people writing it learned programming on that job, guessing their intention is like archeology. And each iteration tended to add some complicated interdependence. Or like when int errorCode came from other, overlapping error ranges.

A part of the "new" code base is exactly as described by TFA. Including most interfaces having only one implementation. But while annoying, I am more able to work on it without things breaking...

It's just comparing two different things: the average "bad code from scientist" is for simple tasks, whereas the average "bad code from software engineer" is for a complicated task (otherwise you shouldn't pay the software engineer in the first place).

My point about the rant being counter-productive is that the solution is to learn how to do the task better, not to blame people. Maybe the best way to do a task with a very low budget is to not do it at all.

OP may have not clicked on the rest of the blog...
Read this on mobile and the identifier longWindedNameThatYouCantReallyReadBTWProgrammersDoThatALotToo overflowed into the margins - I regard this not as a bug but a feature which helped make the author’s point :-)
That’s why I fell in love with Objective C. The libraries used a lot of those expressive descriptions for attributes and methods.

I never understood nor understand people who nest their inner loops in an entangled mess of hardly distinguishable digits, which is error prone.

Same for method names.

I try to use speaking out loud to some of my methods: What do you do? And if the answer is getValue I believe it needs renaming.

We use this technique as a guide in our company. If someone (knowledgable) would ask "What does this method call do?" and the method name does not answer that, your PR doesn't go in the master.

E.g. getString(path) for loadConnectionStringFromDisk(configFilePath), tryConnect(30) for testSqlConnection(timeoutInSec), even the reader now knows what happens here and what input is expected.

> I've been working, ... in an environment dominated by people with a background in math or physics who often have sparse knowledge of "software engineering". ... Invariably, the biggest messes are made by the minority of people who do define themselves as programmers.

Interesting switch in language here from "software engineering" to "programmers". There is of course a long history of debate on these terms, whether there is a meaningful distinction, and what qualifies as engineering versus programming.

Wherever you stand on this debate, there are a number of practices of software developers that tend to be used more towards the "engineering" side. Two of the most essential in my mind are peer code reviews and automated testing of changes (with tests, linters, type-checkers, code formatters, profilers, fuzzers, etc.).

This post doesn't talk about any of these practices or whether the so-called "programmers" messing up the scientific code are using them. I'd say if the people messing up the code are not actually advocating for using software development tools to write better code they are not actually applying software engineering practices to their code.

I would never call myself "electrical engineer" or "mechanical engineer" because I did not study that. But everyone who is paid to write some amount of code calls themselves "software engineer".

Not sure how much of a problem it is, but I am frustrated when "other" engineers try to teach me about how networking works and never once consider that my intuition may possibly have more value than theirs, because I actually studied networking. Not that I am always right of course, but if we have an electrical engineering argument, I naturally get into a stance where I assume they know better and can teach me useful stuff.

> Simple-minded, care-free near-incompetence can be better than industrial-strength good intentions paving a superhighway to hell. The "real world" outside the computer is full of such examples.

Overengineering is insidious - "It is difficult to get a man to understand something, when his salary depends upon his not understanding it". A team can sell a solution better than a single person fixing something without making a big deal out of it. You get organizational clout and inertia on your side when you make something big and expensive.

And then complex systems are by nature hard to reason about and by extension hard to critique.

So many things come down to "complexity is the enemy".

Prime Finance (at Amazon) did that.

Wrote fancy math on a PhD economist’s laptop.

Then when we added testing when developing a platform, we found out we’d been 5% off in allocating Prime revenue between organizations — and had the correct amount gone to Retail, the 2018 hiring freeze might have been avoided. (According to a very angry Wilke.)

Whoops.

Turned out we did need a team and all those guardrails, processes, code reviews, etc.

There’s a time and a place for “move fast and break things” — but real trouble can come from taking those academic practices into the real world.

Did no-one check the maths? There's a difference between having a full test suite, and someone trying some choice values, but I'd expect both would pick up something like that.
If simple checks could find all bugs we would not have so much buggy software.
The PhD economists on our team looked at it.

Economists from other teams looked at it and signed off.

There was manual testing — ie, trying some “choice values”.

We discovered their error in convexity when our test suite allowed us to randomly sample the models at scale. (Actually, I had questions before that — but unsurprisingly, when it was just me questioning a PhD economist, the lowly SDE was ignored.)

Good intentions aren’t enough; you need mechanisms.

any code base that evolves over time will have complexity. It can be either manageable or unmanageable complexity. Either sacrifice maintainability for early development velocity, or plan for medium-to-long term velocity. You CAN have both velocity and maintainability, but the engineers will be expensive. Fast, good, cheap - pick two. A tale as old as bits.
I think it's not a zero-sum game, you can win by judiciously avoiding incidental complexity.
If the non programmers commit correctness bugs and the programmers are just using patterns you don't like, maybe try to understand the patterns instead of balk at them.
The author states they are primarily a software engineer and have also been guilty of following these patterns, so the clear implication is that they understand the patterns. The author isn't making the case "I don't like it," they are making the case that these patterns actually lead to more and bigger problems in the field of scientific computing than the usually simple errors of ignorance committed by non-programmers.
They state clearly that they can't follow the call structures and often give up on understanding them.
Define "correctness bugs". Does the code leak memory (which is not ideal)? That's only an issue for the scientist if it prevents/invalidates the science. But if the pattern hides how something is expressed, or someone unfamiliar with the science tries refactoring the code, that's more likely to cause issues with the science than the memory leak.
> Access all over the place – globals/singletons, "god objects" etc. Crashes (null pointers, bounds errors), largely mitigated by valgrind/massive testing Complete lack of interest in parallelism bugs (almost fully mitigated by tools)
Best practices tend to be overkill for small codebases that have few users, which encompasses the majority of scientific code.

Sheer tenacity is typically sufficient for scientific codebases.

This is so true I don't think I ever read something so true.

It's not even scientists vs software developers. It's people who are really into software development and clean code.

They say the program needs a total rewrite and proceed to add 20 layers of inheritance and spreading out every function over 8 files.

Ever since I make sure to repeat my mantra every week to developers:

How maintainable code is is measured in how many files you have to edit to add one feature.

That's a slippery mantra. I can see putting everything in one file.
Everything in one file can be good organization for many even relatively large projects.
Working with a 300 line method is not fun, believe me. Everything is in one place and you don't have to change many files, yes, but due to the cognitive load, it's so much more effort to maintain it.
There's a happy middle path here I think. Long functions are hard to grok. Spreading the logic across 20 files also increases cognitive load. There's a balance to strike.
Right, but the article seems to imply that all code should be in a single file.

It seems the author indeed is not a SW Engineer and thus does not really grok the benefit of "modules".

This of course depends on the size of the program. Small program "fits" into a single module.

And I think that scientific programs are basically small and simple because they don't typically need to deal with user-interaction at all, they just need to calculate a result.

Further I think scientific programs rely heavily on existing libraries, and writing a program that relies heavily on calls to external libraries produces simple, short programs.

Scientists produce science, engineers produce code-libraries.

"It seems the author indeed is not a SW Engineer".

This is a pretty ridiculous notion if you just cursorily glance over the page. It is quite clear that this guy is more of a software engineer than most with that title will ever be. Hint: a blog that contains a post with a title like 'Coroutines in one page of C' is a software engineer.

Long functions are not hard to grok, if they have a logical flow and stay reasonably close to a common level of abstraction (which can be high or low, doesn't matter). You just read top to bottom and follow the story.

20 files with 20 functions each does not cause high cognitive load, if the scope of each file and each function makes sense. You easily find the file+function you need, whenever you need to look something up and the rest of the time it is as if the rest didn't exist.

Good code can come in any shape. It is not shape itself that is important, it is the "goodness" that is important.

My heuristic is that if logic is repeated at least 3 times, it's good to pull out into its own function, and even then you still need to consider liskov substitution principle.
There are some things that should be in one long function (or method).

Consider dealing with the output of a (lexical) tokeniser. It is much easier to maintain a massive switch statement (or a bunch of ifs/elseifs) to handle each token, with calls to other functions to do the actual processing, such that each case is just a token and a function call. Grouping them in some way not required by the code is an illusory "gain": it hides the complexity of the actual function in a bunch of files you don't look at, when this is not a natural abstraction of the problem at all and when those files introduce extra layers of flow control where tricky bugs can hide. Or see the "PLEASE DO NOT ATTEMPT TO SIMPLIFY THIS CODE" comment from the Kubernetes source[0]. A 300 line function that does one thing and which cannot be usefully divided into smaller units is more maintainable than any alternative. Attempting to break it up will make it worse.

That being said, I agree that nearly all 300 line functions in the wild are not like this.

[0] https://github.com/kubernetes/kubernetes/blob/ec2e767e593953...

Wrong.

How maintainable code is is measured in how well you know where to change something, and how certain you are that it did the right thing without side effects.

The fatal error of the linked article is that bad scientific code often suffers from correctness problems - not just theoretical concerns, but the "negates the main point of this paper" kind of thing.

What if a new person takes your place and they do not know it and are not certain in anything?
(comment deleted)
That's how you measure job security, which is a slightly different concept than maintainability.
When you hire a new person, there is usually some transfer of knowledge. Based on the above definition such transfer should be quick assuming that the person knows the platform and dependencies. A long time explaining the code is an indicator of needlessly complicated code
Am I missing something? Opening files is not my most intensive work as a developer.
Adding indirection makes code less maintainable.
> Adding indirection makes code less maintainable.

This is why I hated Fortran (77 in particular) as an applications language (for tasks like scientific computing people seemed to use saner portions of it). Computed go tos were the bane of my existence.

That's not correct as an unqualified statement. Sometimes indirection adds exactly the flexibility you need and that would otherwise require duplication (like generic collections/containers).

The more correct statement is that using more or less indirection than you need makes code less maintainable.

It's a decent measure of complexity: It's not that "opening files" themselves is work-intensive. But having a lot of files smells of overengineered code. One long, yet simple function has less cognitive overhead than spreading the function across multiple classes or functions or call hierarchies (themselves spread over multiple files).
> One long, yet simple function has less cognitive overhead than spreading the function across multiple classes or functions or call hierarchies

Not if you are encapsulating and naming effectively...

Why read 100 lines when you can read 20 and find concerns in one routine you are concerned with?

Function calls can be expensive. However, optimization can come whenever you need it, and if what you need is one call vs 5, it is trivial to move that code back into a single routine.

I like long simple functions because it makes them easy to reason about when debugging.

Rarely does having more functions solve “does this do what I expect.”

Maybe it boils down to how well you are able to navigate a code base.

With a full-featured language specific IDE, it is very easy to navigate through even complicated spaghetti. It makes debugging call traces simple, with a GUI.

However, many other file viewers and editors make this much more complicated, and it can be frustrating to follow code that is making heavy use of modularization.

If you are grepping your way through a deeply modular code base it can quickly become difficult to keep track of anything.

>> With a full-featured language specific IDE, it is very easy to navigate through even complicated spaghetti.

If you need a fancy IDE to navigate around code in order to understand it, that might be crappy or poorly organized code.

Not a dig at nice IDEs, just code that requires one to navigate and understand.

Yeah. This is one of those hammer cases. If you’ve got a fancy IDE then the temptation is to use it. Similar to the issue of game programmers being given top of the line gaming PCs with frequent upgrades. They then struggle to understand why the game they just released runs like crap on most people’s modest computers.
Not many people can understand a very large code base without taking notes, using an IDE, or similar tooling.

> Not a dig at nice IDEs, just code that requires one to navigate and understand

A nice IDE helps you reason about code, no matter what the underlying architecture is. That is why there is a market for them.

> Not if you are encapsulating and naming effectively...

No, and this is one of the reasons inheritance has lost popularity. Splitting some functionality across many files adds significantly to the cognitive load of figuring out what code is actually even running. After you trace that information out, you need to keep it all straight in your head while debugging whatever you’re working on. That’s even more problematic when you’re debugging, which implies you already don’t really understand what the program is doing.

And that’s in the case where things are named well. When they’re inevitably accidentally named in confusing or incorrect ways that can contribute to the bug itself and cause the code to be even more confusing.

Extreme levels of encapsulation has its own issues when, actually, the original author is wrong and you really do need some public access to some member. No one writing code is clairvoyant, so excessive encapsulation is common.

> Splitting some functionality across many files adds significantly to the cognitive load of figuring out what code is actually even running.

This is the crux, if your goal is to figure out what code is running, if you can keep the program in your head, if you have small simple programs splitting things up is harmful.

But there is this murky line, different for everyone, and even different for the same person from day to day, where even with the best intent, no matter how good you are, you can't keep the program in your head.

At that point, you need to give up the idea that you can. Then you change perspective and see things in chunks, split up, divide and conquer, treat portions as black boxes. Trust the documentation's, pre and post conditions. Debugging becomes verifying those inputs and returns; only diving into the code of that next level when those expectations are violated.

But at some point you HAVE to be able to look at the program from above. If you abandon the hope of understanding the code in the bigger scope, how can you ever meaningfully modify it? (Ie add a big feature and not just tweak some small parameters)
The rather unsatisfying answer, is it depends.

It depends on the change. It depends on the code organizational structures. It depends on the consistency of the code. It depends on the testing setup. It depends on the experience of the person changing it. It depends on the sensitivity of the functionality. It depends on the team structures.

There is however one reason that trumps them all: the actual reason the code was split.

Separating the code of your SQL server, HTTP server, Crypto Library, Framework, Standard Library, from your CRUD code is perfectly fine, and people understand this concept well, and even the most fervent anti-Clean-Code person won't complain about this separation existing.

But there is a good reason we separate those things from our CRUD codebase: it's because they can function separately fine, they're reusable, they're easy to isolate/reproduce problems, and they're at a totally different abstraction level.

The problem is separating code from the same level of abstraction, such as breaking a business logic class into many for mainly aesthetic reasons, such as method/class/module length, or to avoid having comments in the code (again as recommended by Clean Code), things that people are mentioning here in this thread.

EDIT: As someone said above, "20 files with 20 functions each does not cause high cognitive load, if the scope of each file and each function makes sense". In the end it's not the length or the number of methods/classes that matter, but how well separated they are. Having hard rules does not automatically make for good code, and it's often quite the opposite.

One last thing to consider, if you are writing little a CRUD app, it can be very simple, you can keep it in your head.

However, Can you?

You are using black box code from a web server, a sql database, the operating system, crypto libraries, and a ton more; You don't dive into that source code except in extraordinary circumstances, if you even can. In a large program, you end up treating code owned by you or your company as the same way.

In this scenario you are still making large meaningful changes by focusing on the level of abstraction you are at.

Not if you are encapsulating and naming effectively...

Encapsulation is hard and a lot of what people call encapsulation isn’t. For example, taking a global variable and moving it to a class is not encapsulation. You have to actually do the hard work of removing the dependency on global shared state. Just changing everything to mutate the new global through an accessor to a “god” object that gets passed everywhere is accomplishing nothing at all. Worse than nothing, you’re complexifying without fixing the root problem: global mutable state.

It's funny how Singletons became such a meme pattern, and how about 80% of people in interviews only know about it when asked about patterns.

A cleverly-named way of disguising global mutable state does not make it better.

> "Not if you are encapsulating and naming effectively..."

When you only have to superficially skim the code, that works.

If there are incorrect abstractions, such as logging, transaction logic or manual error handling mixed with "well named function calls", then it is already very problematic even to skim.

If you have to debug, it quickly becomes torture. Especially if state is involved and shared between multiple methods or classes.

If you have to reimplement the code: you're probably fucked.

(comment deleted)
>They say the program needs a total rewrite and proceed to add 20 layers of inheritance and spreading out every function over 8 files.

Anyone who in 2023 still thinks inheritance is a good idea for anything other than a few very specialised use-cases is not somebody who seriously cares about the craft of software development, not somebody who's put any effort to study programming theory and move beyond destructive 1990s enterprise Java practices. Widespread usage of inheritance inevitably makes code harder to reason about and refactor, as anyone who's compared code in Java to code for similar functionality in Rust or Go would see (both Rust and Go deliberately eschew support for inheritance due to the nightmares it can cause).

(Ab)use of any paradigm (I'll need a shower for using that word) can result in nightmares. Inheritance has its place and it is definitely useful in more than "few specialised cases". It can get out of hand and it can become a nightmare. Composition has its place and it is definitely not better than inheritance except in "few specialised cases". It can also result in nightmare, just wait till adoption of Rust and go is at the level of Java and C++ in enterprise environment and you will see. Writing clean and maintainable code should be the best practice and writing obfuscated code for performance and security should be reserved for "few specialised cases" but most developers and languages prefer the short and obfuscated to clear and (slightly) longer. RUst and go are perfect examples of why software development is an immature engineering discipline that favors "cool" and "terse" to clear and expressive...and no, C and C++ are not "good old times", they are old and slightly worse but not much worse, or I should clarify, go and rust and not much better because they still do not allow user (programmer) to express the intent clearly and instead force the reader of the code to sound like a person with severe speech impediment.
The problem with inheritance is that no one seems to know where to use it best. Everyone just goes by feel and feelings frequently turn out to be wrong.

Composition is nice because it’s very simple and we can understand it mathematically. If you’re trying to understand inheritance mathematically then you’re basically left with using it only for algebraic structures (groups and rings and fields and vector spaces). But then you don’t really need inheritance there if you just have plain types and operator overloading.

Operator overloading leads to less readable, maintainable code IMHO, because you have to go off and figure out if the operator means a special thing in a given context.

Certainly adds to complexity in C++.

It works well when you stick to math and follow mathematical laws. Overloading the addition operator to allow you to add two vectors is great, as long as you make sure you don’t break the laws of vector addition in your vector space.

Overloading addition to mean something else entirely? That’s a problem!

It would be great if type systems could allow us to set up these laws and enforce them at compile time, but then you go down the whole rabbit hole of automated theorem proving.

Mmm. Maybe lets stop and address the question of "what are the key properties of inheritance?". Because I haven't seen a single use for it in maybe a decade or so and I'm not sure what it is you think you're defending.

Usually what people want is an interface; ie, a somewhat generic way of saying "this thing knows how to draw itself", "this thing supports printing" or "this thing can fizzle wuzzles like all the other wuzzle fizzlers". That is essential to coding.

But Java style inheritance carries a lot of baggage in excess of that; and some of it is just bad news. In practice it is a brittle assumption that a Foo is also and always a precise superset of Bar. And usually when that is true the relationship is so shallow having a dedicated concept of inheritance is wasteful, it may as well be an interface and a shared file of code.

TLDR; Inheritance is too many ideas mixed together; most useful and a couple bad. It is a better idea to present the different facets of inheritance to be selected a la carte. Mumble mumble Rich Hickey talks.

Yep. Inheritance is 3 or 4 different features in a trenchcoat, and most of them are bad.

Interfaces are good.

Method overloading for specialization or for creating mini-DSLs (Template Method pattern) is often problematic and is better replaced by composition, or by having the "overloaded" methods in a separate class.

Implementation Inheritance is certainly the worst form of "code reuse", and there's a reason people recommend composition over it since the 90s.

Using it for hierarchies (Dog inherits from Mammal, Mammal inherits from Animal) is just terrible and a joke at this point.

>Writing clean and maintainable code should be the best practice and writing obfuscated code for performance and security should be reserved for "few specialised cases"

Except, we can (fairly objectively) reason about performance and security, while 'clean code' and 'maintainability' are arbitrary, with vague guidelines at best.

Throwing out those first characteristics in name of the latter ones is just irrational.

(Not to even mention that performant and safe code still can be 'clean')

There's probably a Someoneorother's Law or Something Fallacy about this, because it's a common problem, especially among people who fancy themselves More Rational (and thus More Intelligent) than others:

You are assuming that the only things that matter are those that can be objectively measured (and measured simply and straightforwardly, with well-known metrics today).

Developer frustration, which will increase when having to deal with messy, unmaintainable code, is a real thing, even if it's harder to measure than performance and security. Not only does it create real stress and thus harm to the developers, it also slows development in ways that are going to be much less consistent and predictable than what's needed to write clean, maintainable code in the first place.

(Also, of course, there are at least some fairly well-accepted standards of clean, maintainable code, even if some aspects of those aren't entirely agreed on by everyone, and painting them as completely arbitrary, subjective things is just wrong.)

>You are assuming that the only things that matter are those that can be objectively measured.

No. Feelings do matter. But the problem is, what do You do when You have 2 people with conficliting feelings?

>Also, of course, there are at least some fairly well-accepted standards of clean code.

Are there though?

>even if some aspects of those aren't entirely agreed on by everyone, and painting them as completely arbitrary, subjective things is just wrong

Even if I grant You that there are some guidelines that are respected by overwhelming majority, that still doesn't prevent them from being arbitrary.

> But the problem is, what do You do when You have 2 people with conficliting feelings?

Hopefully, you try to work it out like adults, rather than just declaring that your way is the only rational way, and anyone else's feelings need to pound sand.

Furthermore, this isn't primarily about "feelings" in the sense of "this hurt my feelings;" this is primarily about adding unnecessary stress to developers' lives. Stress is something that is scientifically proven to increase susceptibility to diseases and cancers, and reduce lifespans, so it seems to me that this should be enough objective and rational evidence that we should be genuinely trying to reduce it.

> Are there though?

Well, I think most people would agree that putting an entire C file on one line is a pain to work with, even if skipping the "unnecessary" whitespace does save a little space.

And naming your variables alphabetically based on the order you use them in (eg, `int alpha`, `char bravo`, `std::string charlie` makes the code hard to maintain.

"Well, but that's just obvious stuff! No one would ever do that!"

I guarantee you someone would do just about any boneheaded thing you can imagine in programming unless told not to, either out of spite or because their brain really just works that way.

Just because you've made a bunch of assumptions about how people would or should code doesn't mean that those assumptions are any less arbitrary than anything else.

> that still doesn't prevent them from being arbitrary.

...But that's the thing. They're not. Just because they're not deeply well-researched to ensure that this particular set of coding standards measurably increases performance and decreases stress while maintaining code doesn't mean that maintainability is an arbitrary thing. It just means that it hasn't been adequately studied yet.

...or maybe it just means you haven't[0] looked[1] enough[2] yet, and the research that's out there hasn't yet had time to coalesce into any kind of industry-wide action.

Furthermore, it sounds very much like you're saying that coding standards like K&R, or C++ Core Guidelines, or PSR-2, are entirely arbitrary. They're clearly specified, they're written down and easy to reference, they codify plenty of aspects of coding style—but are all coding standards, no matter how well-respected, completely arbitrary?

[0] https://www.researchgate.net/publication/299412540_Code_Read...

[1] https://www.hindawi.com/journals/sp/2020/8840389/

[2] https://www.researchgate.net/publication/303870101_Software_...

> There's probably a Someoneorother's Law or Something Fallacy about this

I once got your for a couple of hours researching the origin of that famous phrase "you can't improve what you don't measure", so I could blame it correctly.

The idea is quite old, of course, and popular to the 19th century rationalists. But the format people keep teaching around today seems to be a strawman created by Deming, at the 80's, in a speech about how stupid that idea is.

Anyway, I guess we need some Othersomeoneorother's Law about how you just can't make a good point against an idea without someone taking your point, preaching it unironically, and making a movement in support of the idea.

> Except, we can (fairly objectively) reason about performance and security, while 'clean code' and 'maintainability' are arbitrary, with vague guidelines at best.

Ok, how does one best reason about performance and security with messy unmaintainable code?

You barely need to try even shallow reasoning about a code base at all, before it's clean vs. messy, and maintainable vs. unmaintainable status will feel very objective and pertinent.

>Ok, how does one best reason about performance and security with messy unmaintainable code?

The same way one does it with 'clean' code: Using profiling tools. Security is a bit less straight forward, but still.

>will feel very objective.

Keyword: Feel. And while most people could probably agree on terrible code being terrible, the 'less terrible' the code is, the more this argument becomes a feeling. And then we hit up point where it's no longer possible to discuss things using objective arguments - how will a senior java developer, who is used to heavy OOP style coding reason with a senior C developer for whom such OOP heavy style is the oposite of 'clean'?

Ofcourse, the example is (too) simplistic, but even in this thread You have people arguing about "big functions" vs splitting things up. And unlike the performance, which You can alaways just point to the raw numbers, here You can't rely on any sorts of 'objectivity'

Certainly you can point to numbers re performance. But reasoning about performance is another thing if the code is a mess.

Messiness and unmaintainability does not scale. You can argue its not a completely objective thing to measure. That is true. And yet objectively, it really matters.

Not everything that is important comes with a clear number. Which is why experience and good judgement matter too. Two more things without numbers.

Again though: What do You do when someone thinks Your code is a mess, but You think it's good?
What kind of question is that?

It is impossible to answer without all the details of the situation. Different situations will have completely different answers. Who, what, where, how, when, why, ...?

Rust and Go both provide features to implement code in an OO-ish way: traits and interfaces. I just code in Rust as a hobby but I code in go professionally. The go codebases I work on at work are bloated messes of abstractions and duck typing, often meant to enforce some absurd standard of unit-testing. They can easily be as bad as any "enterprise Java" stereotype you wish to invoke.
I hate to say this but this attitude of "it's 2023, inheritance is so 2008" is telling. How do you know the attitudes regarding best practices today are not going to be as bad as 20 layers of inheritance?
To be honest it's mostly not their fault. Most people want to do the right thing and that's what they're taught. Doing things differently is frowned upon, and most people don't want to stick their neck out and say the emperor is naked.

Recently at work some people argued "things" (methods, classes, even files) should have a limit in size. I think that's valid thinking because you want to strive to having smaller components that you can reuse and compose, if you are able to do that. But what happened is that people started creating dozens of little files containing a function each and then importing those. To be it's obvious that this is now a lot worse because the complexity is still the same, just spread out across dozens of files. But most people were somehow convinced that they're "refactoring" and that they're doing best practices of keeping things small.

Yes, the main problem I've seen with focusing too much on length (of functions, files, or whatever else) is that people start spending tons of time rearranging the big messy drawer into n smaller messy drawers while totally avoiding the difficult work that needs to be done to actually organize the drawer(s).

All other things being equal, smaller functions and smaller files are a little bit better, but what really matters is architectural and conceptual complexity. Keeping those in check is all about using the right data structures (and doing painful refactors when you realize you've got the wrong ones). It has almost nothing to do with how files and functions are organized.

They

Who are these people, really? I mean, I was that for a rather brief period of like a year, somewhere 3-4 years into programming IIRC. I met others like it. But in the end people seem to learn and grow out of it, and rather quickly so, because it becomes clear what the issues are quickly. Really good learning by mistake though, wouldn't have wanted to miss out on it.

mantra

That's imo just another mistake to make: wrapping a rather strict and narrowly scoped principle in a paradigm-like-must-be-followed mantra hurts the right-tool-for-the-job idea, which feels vastly superior.

Firstly the idea that unmaintainable code is necessarily an issue is already wrong to start with, in my book. Obviously it's not ideal and where appropriate - meaning nearly always - should be avoided at pretty much all cost, but I have enough examples where it does not matter at all. As in: code which hasn't been touched in 20 years and probably won't ever be touched. Does it look like a nightmare? Yes. Does it work correctly? Yes. Does it need changing? No. So, is it an issue where spending time (or having spent time) on it would make anything other than the programmer's peace of mind (well, or ego perhaps) better? Clear no.

Secondly: of course I get where you're going with such definitions but it again lacks the very much needed nuancing. I can write unmaintainable code in one file but where you need to change 20 different locations. You could than claim that your mantra still applies because the code should have been split over 20 files, but yeah, that's what you get with mantras :) Likewise depending on the feature it's perfectly possible many files have to be changed but that doesn't necessariy mean the code is hard to maintain. Could try to claim that it wasn't very well architected to start with, maybe, but welcome in the real world where not everything can be thought of from the very start except in small toy applications.

Then a single file project is the most maintainable software project?
> How maintainable code is is measured in how many files you have to edit to add one feature.

Trivially false: if all of the source code is kept in one file then you only ever have to edit one file. No matter how many lines of code are in that file, any such system would be maximally maintainable by your definition.

Maintainability is not so clear-cut. It's currently an imprecise measure of organizational clarity that makes it straightforward to extend a system in ways that are needed or will be needed.

I dont trust devs that praise clean code as much as i dont trust people that say they eat clean.
Some people incorporate antipatterns into their practice & reinforce these antipatterns with years of experience. All fields have this issue. Bad professional scientists are often worse than effective amateur scientists. Having good first principles with little experience often beats plenty of experience with bad first principles.

I have learned to appreciate codebases which break some rules & yet are easier to maintain for some reason(s) Distilling the reason(s) identifies areas where I can modify my technique...or at least help identify questions & alternatives to some techniques that I regularly use.

When scientific code is not required to be published with its research literature who really knows how bad it is?
A few responses come to mind. Who is requiring? What counts as code that needs to be published?

But perhaps the most relevant response is that few people read papers, even fewer are going to look into their zip. The whole idea of papers is to condense a whole lot of work into concise digestible information.

Aren't papers also supposed to be reproducible? Having access to the original code would allow you to see why you're not getting the same results if it's caused by a bug.
Sounds like the non-programmers are good at what they are supposed to be good at (solving the actual problem, if perhaps not always in the most elegant manner) while the programmers should be producing a highly maintainable, understandable, testable and reliable code base (and potentially have problems with advanced algorithms that rely on complicated theorems), but they are not. The OP has a case of bad programmers - the techniques listed as bad can be awesome if used with prudence.

A good programmer has a very deep knowledge of the various techniques they can use and the wisdom to actually choose the right ones in a given situation.

The bad programmers learn a few techniques and apply them everywhere, no matter what they're working on, with whom they are working with. Good programmers learn from their mistakes and adapt, bad programmers blame others.

I've worked with my share of bad programmers and they really suck. A good programmer's code is a joy to work with.

Right and I think "scientists" simply are more intelligent than average Joe Coder. Intelligent people produce better software.

It is easy to learn some coding, not so easy to become a scientist.

To becomes a scientist you must write and get your PhD-thesis approved, which must already be about scientific discoveries you have made while doing that thesis. Only people with above average IQ can accomplish something like that, I think.

> Right and I think "scientists" simply are more intelligent than average Joe Coder. Intelligent people produce better software.

The vast majority of papers I read on topics I know are complete bullshit. Maybe making a PhD was more elitist before, but now it surely isn't.

If we define "scientist" as anyone who publishes papers, then they have the same problem as software engineering: it's mostly made by juniors.

In my experience getting a PhD doesn't require above average intelligence, it does require a lot of perseverance and a good amount of organisation though.

I honestly think most skilled tradespeople are more intelligent than me and my PhD holding colleagues.

(comment deleted)
Being intelligent in one domain doesn’t automatically make you good in any others. Exceptional biologists can be astoundingly bad at maths, and the other way around. Like most skills, being good at writing software requires not only intelligence, but lots of experience too. Maybe smarter people will pick it up faster, but they aren’t intrinsically better.

It’s a bit surprising you’d have to explain such a basic conclusion here.

Good code is the simplest code you can write to get the job done.

Getting too excited about techniques is a form of scope creep

It depends on what it means to be to get the job done.

Write some code and generate immediate results can be considered a done job. If you want to reuse the code a year later and found an unreadable mess though, not so much.

Is this article just two strawmen fighting?
I agree with the feelings of the author, most software is overengineered (including most of my software).

That being said, most scientific code I've encountered doesn't compile/run. It ran once at some point, it produced results, it worked for the authors and published a paper. The goal for that code was satisfied and than that code somehow rusted out (doesn't work with other compilers, hadn't properly documented how it gets build, unclear what dependencies were used, dependencies were preprocessed at some point and you can't find the preprocessed versions anywhere to reproduce the code, has hardcoded data files which are not in the published repos etc.). I wouldn't use THAT as my compass on how to write higher quality code.

Yeah somehow I suspect this author hadn't yet had to deal with colab notebooks.
Yeah, well gnome 2 also doesn't compile or run on my machine. It ran once at some point, but one is considered a "worse" class of software.
numerical code isn't like application code. the rules of application code don't always apply. for example, i think one character variable names are totally fine if they come from equations or papers where in most applications it's generally frowned upon.

this is why i'm a little skeptical of languages that blur the lines. sometimes ideas from application programming can complicate numerical code and sometimes numerical programmers don't fully understand the systems abstractions they're building on and end up reinventing wheels to avoid simpler solutions they feared or didn't know existed.

the moral of the story is to keep an open mind, to not be a zealot and to avoid dogmatic thinking.

I think we have a case of survivorship bias.

A considerable majority of the science-non-SWE crowd are de facto incapable of writing more than 100 lines of runs-in-my-notebook code.

Hence, if a change/bug is necessary, it is much likelier to fall under a SWE jurisdiction, and hence is much more likely to be industrial code.

Add to that a further confounder (tiptoeing a "no true Scotsman" here): academia is not a first choice of workplace for strong SWEs.

I'm not so sure that this claim is valid as a general observation.

Multiple times in my career, I have seen scientific code written by academics dramatically sped up by developers who used parallelisation, vectorisation using SIMD etc.

So in terms of performance, naively written scientific code is generally easy to beat in terms of performance for a reasonably adept programmer.

That said, "enterprisey" Java/.NET software engineering shops can indeed make scientific code sub-optimal sometimes. Have come across that sometimes too but I wouldn't generalize.

Meh.

Who actually works as a software dev at one of these academic institutions? The pay is beyond terrible. Presumably you have either:

- Young and keen. Young and keen are the source of all kinds of terrible things. That’s why you need old and bitter to balance it out. Old and bitter is off working for much more money in a boring corporate.

- Side hustlers/other incompetents. “I’m now a software dev!”

It’s not that proper software shops don’t struggle against “complexification” and all manner of other deviant behaviours. There are so many ways to turn software into hell - “All happy families are alike; each unhappy family is unhappy in its own way.” But if this is your problem, the problem isn’t “the software industry” or “best practice” or “devs jobs are so easy they just have to make up complexity”. The problem is incompetence. Managerial/leadership incompetence.

Two more to the scientists' tab:

1. No tests of any kind. "I know what the output should look like." Over time people who know what it should look like leave, and then it's untouchable.

2. No regard to the physical limits of hardware. "We can always get more RAM on everyone's laptops, right?". (You wouldn't need to if you just processed the JSONs one at a time, instead of first loading all of them to the memory and then processing them one at a time.)

Also the engineers' tab has a strong smell of junior in it. When you have spent some time maintaining such code, you'll learn not to make that same mess yourself. (You'll overcorrect and make another, novel kind of mess; some iterations are required to get it right.)

Agree with those two problems on the scientist side. I would also add that they often don't use version control.

I think a single semester of learning the basics of software development best practices would save a lot of time and effort in the long term if it was included in physics/maths university courses.

> I would also add that they often don't use version control.

Working for corporate R&D, I once received a repo on a flash drive. The team would merge changes manually by copy-pasting.

I should've just turned around and left.

Yes, the claim that the scientists' hacked-together code is well tested and even uses valgrind gave me pause. It's more likely there are no tests at all. They made a change, they saw that a linear graph became exponential, and they went bug hunting. But there's no way they have spotted every regression caused by every change.
1 and 2 are features. Re 1, if someone doesn’t know what the output should look like they shouldn’t be reusing the code. Re 2, just think a bit more about it and you’ll realize fretting over ram that isn’t needed until it’s needed is actually just premature optimization.
I will believe that when scientists will stop being too embarrassed to publish their code. Do people not remember mrc-ide/covid-sim?
While I think there are a couple of valid points, in general my feeling is that the author is setting up a straw man to attack.

Most of the “programmer sins” are of the type that more seasoned engineers will easily avoid, especially those with experience working with scientific code. Most of these mistakes are traps I see junior developers falling into because of inexperience.

Oh look, another tiring craftsmanship debate that other disciplines long figured out!

A, say, physicist writing bad code could equally well be building a pergola for his garden. He doesn’t really know woodworking but god be damned if he couldn’t calculate the forces acting on the beams, and then add some screws - how hard can it be! And probably, he’ll even get the thing up, and it doesn’t look too bad even. Now get a carpenter over, and they will be horrified about all the things the scientist did unusually, did not account for, or just plain wrong. ”Wall Screws you still had around?? How could you not know you’d need structural screws for that?“, he will scream. However, the thing does roughly what the scientist supposed it should do. Until the winter, that is, when the wood expands due to humidity and cracks appear, and he finally needs a professional to fix the problems.

It’s the same story, really: It is a software engineer’s job to build quality software. A scientists job is to solve problems. There’s a clear boundary here, where the latter will deliver a concept to the former, who will eventually create a production-grade implementation off of that. Neither does a scientist have to build proper software, nor does a developer have to do cutting-edge research.

And all the words wasted on how one of them might be doing something badly is on he wrong path.

The real difference here is between hobbyists and mere workers. Programming happens to be one of the disciplines which has a lot of hobbyists. But that doesn’t mean you won’t find hobbyists in other disciplines.

Look at machining for example. Long dominated by people working in machine shops making tools and parts on the clock. But in the background there’s a strong hobbyist contingent and there you’ll find endless debates over whether a beginner should buy a decades old Bridgeport milling machine or a brand new Chinese-made one.

Similarly I find endless debates about what sort of frying pan to use (nonstick, stainless, carbon steel, or cast iron) among amateur chefs, but you’ll never see people working in a restaurant waste time on that.

In other words, it’s hobbyists who really obsess over tools and craftsmanship. They do it because they love it. Programmers just happen to be among the odd sort who can get paid to practice their hobby.

I don't know about that. Pros obsess over it too, but they don't bother to endlessly talk about it; they just do it. But if a better tool comes along, they'll consider it.
This might work for CERN. But a great deal of science is done by small teams who don't have a professional programmer available. Basically all of the social sciences, for a start; a lot of genetics too.
If you cannot model using decent code is it worth writing models at all? What if bugs mean the model is simply wrong?

It has consequences too. There has been a lot of argument about how much impact the poor code quality of the Imperial college covid epidemiology model (which was the basis of British government policy during the pandemic) had on its accuracy. I do not know how bad it was, but it cannot be good the code was bad.

One problem is that it's really hard to tell when you've just written bad code, which is also a problem for people whose job title is software developer, not just people who do it as a small part of their overall work.

Some genes have been renamed because Excel interprets the old names as dates. The people who put all their genetic analysis into Excel had no reason to expect that, just as the people writing Excel itself weren't expecting the app to be used like this.

Yeah but, in your example. this is a bookkeeping issue that, while frustrating and time consuming and costly, is just that. It’s not like a gas line in Manhattan blew up because someone in Toledo hit C-v in Excel. The scientists swapped around excel files and imported stuff without checking, which then was fed into other systems. A clusterfuck but one that is a daily occurrence at, minimally, every major non-tech company. It eventually gets unfucked with human labor or it simply wasn’t important in the first place. Exact same thing happens in research and academia.

Point being, unknown unknowns are just that. But most unknowns are known and can be programmed defensively against for most serious use cases. All major fields are like this—like, you can hook up a car battery to light a menthol tank to boil two cups of water… or we can use a kettle. Perhaps for a brief point in time, due to our ignorance or just history, people lit containers of menthol on fire like it was sane, but that doesn’t mean it was, or is.

> I do not know how bad it was, but it cannot be good the code was bad.

I do know because I reviewed the code and its issue tracker extensively. I then wrote an article summarizing its problems that went viral and melted the server hosting it.

The Imperial College code wasn't merely "bad". It was unusable. It produced what were effectively random numbers distributed in a way that looked right to the people who wrote it (in epidemiology there is no actual validation of models, reinforcing the researcher's prior expectations is considered validation instead). The government accepted the resulting predictions at face value because they looked scientific.

In the private sector this behavior would have resulted in severe liability. ICL's code was similar to the Toyota engine control code.

A selection of bug types in that codebase: buffer overflows, heap corruption, race conditions, typos in PRNG constants, extreme sensitivity to what exact CPU it was run on, and so on. The results changed completely between versions for no scientific reason. The bugs mattered a lot: the variation in computed bed demand between runs was larger than the entire UK emergency hospital building program, just due to bugs.

The program was originally a 15,000 line C file where most variables had single letter names and were in global scope. The results were predictable. In one case they'd attempted to hand write a Fischer-Yates shuffle (very easy, I used to use it as an interview question), but because their coding style was so poor they got confused about what variable 'k' contained and ended up replacing the contents of an array meant to contain people's ages with random junk from the heap.

There were tests! But commented out, because you can't test a codebase that overrun with non-determinism bugs.

The biggest problem was the attitudes it revealed within academia. Institutionalized arrogance and stupidity ruled the day. Bug reports were blown off by saying that they didn't matter because the "scientists" just ran their simulation lots of times and took the average. Professional programmers who pointed out bugs were told they had no right to comment because they weren't experts. ICL administration claimed all criticism was "ideological" or was irrelevant because "epidemiology isn't a subfield of computer science". Others were told that they shouldn't raise the alarm, because otherwise scientists would just stop showing their code for peer review. Someone claimed the results must have been correct because bugs in C programs always cause crashes and the model didn't crash. One academic even argued it was the fault of the software industry, because C doesn't come with "warning labels"!

The worst was the culture of lying it exposed. The idea you can fix software bugs by just running the program several times is obviously wrong, but later it turned out that their simulation was so slow they didn't even bother doing that! It had been run once. They were simultaneously claiming determinism bugs didn't matter whilst also fixing them. They claimed the software had been peer reviewed when it never had been. The problems spanned institutions and weren't specific to ICL, as academics from other universities stood up to defend them. The coup de grace: ICL found an academic at Cambridge who issued a "code check" claiming in its abstract that in fact he'd run the model and got the same results, so there were no reproducibility problems. The BBC and others ran with it, saying the whole thing was just a storm in a teacup and actually there weren't any problems. In reality the code check report went on to admit that every single number the author had got was different to those in Report 9, including some differences of up to 25%! This was considered a "replication" by the author because the shape of the resulting graph was similar.

That's ignoring all the deep scientif...

Eek! That makes the worst code I've ever seen, seem good in comparison.
Aside from the code quality, his models have never been close to accurate on anything.
Right. That's not unique to Ferguson, epidemiology doesn't understand respiratory virus dynamics and doesn't seem particularly curious to learn anymore (I read papers from the 80s which were very different and much more curious than modern papers, not sure though it that's indicative of a trend or just small sample size).

Other models I checked didn't have the same software quality issues though. They tended to use R rather than C and be much simpler. None of them produced correct predictions either, and there were often serious issues of basic scientific validity too, but at least the code didn't contain any obvious bugs.

Wow. It's pretty unbelievable. It there a place where I can read the whole article?

The one I found the funniest/crziest is "Bug reports were blown off by saying that they didn't matter because the "scientists" just ran their simulation lots of times and took the average", because this is exactly how some scientists I know think.

This thinking is not limited to software. My father was by trade involved in building experimental apparatus ("hardware") for scientific experiments. Often they were designed by scientists themselves. He told me about absurd contraptions which never could measure what they were intended to measure, and extreme reluctance/defensiveness/arrogance he often met when trying to report it and give some feedback...

Yeah confusion between simulation and reality can be observed all over the place. Multiple runs can be needed if you're doing measurements of the natural world, but for a simulation that doesn't make sense (you can do Monte Carlo style stuff, but that's still replicable).

You could see the lines being blurred in other ways. Outputs of simulations would be referred to as "findings", for example, or referenced in ways that implied empirical observation without it being clear where they came from unless you carefully checked citations.

Here are some of the articles I wrote about what happened (under a pseudonym)

https://dailysceptic.org/2020/05/06/code-review-of-fergusons...

https://dailysceptic.org/2020/05/09/second-analysis-of-fergu...

https://dailysceptic.org/2020/06/11/how-replicable-is-the-im...

After that people started sending me non-Imperial models to look at, which had some similar problems:

https://dailysceptic.org/2020/08/08/schools-paper/

I don't write for that website anymore, by the way. Back then it was called Lockdown Sceptics and was basically the only forum that would publish any criticism of COVID science. Nowadays it's evolved to be a more general news site.

Thank you! This is very interesting.

> Outputs of simulations would be referred to as "findings"

Yeah, a recent brouhaha about creating (!) a traversable wormhole in a quantum computer comes to mind...

Given Ferguson's track record of being out by orders of magnitude on absolutely everything beforehand, it almost seems like he was chosen to give an over the top estimate.
It is possible. It is certainly common to pick the expert who says what you want them to - and to get rid of experts who say the "wrong thing" (e.g. the dismissal of UK govt drug policy advisor David Nutt).
It would be comforting to believe that because it'd mean there were other epidemiologists who were right but ignored. Go read the works by his counterparts though, and they're all out by similar orders of magnitude.
How are people supposed to do science without running statistical models?
This is asked in good faith of course, but that question really gets to the heart of what's been corrupting science.

Statistical techniques can be very useful (ChatGPT!) but they aren't by themselves science. Science is about building a theoretical understanding of the natural world, where that theory can be expressed in precise language and used to produce new and novel hypotheses.

A big part of why so much science doesn't replicate is that parts of academia have lost sight of that. Downloading government datasets and regressing them against each other isn't actually science even though it's an easy way to get published papers, because it doesn't yield a theoretical understanding of the domain. It often doesn't even let you show causality, let alone the mechanisms behind that causality.

If you look at epidemiology, part of why it's lost its way is that it's become dominated by what the media calls "mathematicians"; on HN we'd call them data scientists. Their papers are essentially devoid of theorizing beyond trivial everyday understandings of disease (people get sick and infect each other). Thousands of papers propose new models which are just a simple equation overfitted to a tiny dataset, often just a single city or country. The model's predictions never work but this doesn't invalidate any hypothesis because there weren't any to begin with.

How do you even make progress in a field if there's nothing to be refuted or refined? You can fit curves forever and get nowhere.

In psychology this problem has at least been recognized. "A problem in theory" discusses it:

https://www.nature.com/articles/s41562-018-0522-1

Right, statistical models are not sufficient for science. I agree. But they are necessary. So I recur to my original question.
Most teams at CERN don't have a professional programmer available either. In a few of larger projects (those with a few hundred active contributors) there might be one or two more tech savvy people who profile the code regularly and fix the memory leaks. But few (if any) are professional programmers: most contributors are graduate students with no background in programming.
And this is scary. At least with "high-energy experiments" (like the one that discover Higgs) in colliders, a lot depends on so-called triggers, which dismiss 99.9% of information produced in a collision "on the spot", so that this information is never recorded and analyzed.

They have to: there is way too much information produced. So the triggers try to identify "trivial" events and dismiss them immediately, relaying only the ones that are may be somewhat unusual/unexpected.

Essentially, the triggers are computers with highly specialized programs. Very smart people work on this, and supposedly they figure out problems with triggers before they affect the results of experiments...

The triggers are the most fun part of the experiments!

The composition of teams working on triggers might be a bit of an exception in the "engineer : "data scientist" ratio. Most of the talent is still from a physics background but there's more of an engineering bent where around half the team can probably write performance critical code when they need to. Elsewhere that ratio is much lower.

Determining which data to save is a mix of engineering, algorithms, physics, bits of machine learning, and (for better or worse) a bit of politics. Surprisingly we're always desperate for more talent there.

As you say, the goal is to try to stop problems before they affect the data, but it's not always perfect. Sometimes we discover sampling biases after the data comes in and need to correct for them, and in the worst case we sometimes blacklist blocks of data.

In computer science, for some reason - people struggle to distinguish between an engineer and a scientist.
I think that is, because we are still at the frontier and the lines between research and developing something new are quite blurry.

By now there are already lots of fields in IT that are quite standardized, but others not so much.

For example, what is the fastest way to draw lots of shapes on a canvas on the web?

There is no definite and fixed answer, as the field is still evolving and to find out the fastest way for your use case, you have to do research and experiments.

> as the field is still evolving and to find out the fastest way for your use case

No one in the world at large cares about the fastest way, they care about the lowest budget :)

Depends. If gaming is what you do, the better the performance, the bigger the market. As then more people can play your game.
HN is funny. I've been told on a previous discussion that AAA publishers don't optimize for potatos. Now you tell me it's a business requirement.
I told you it depends. There are AAA games for console and gaming computers and there are casual mobile games for example. Very different markets.
Oh the free to play stuff doesn't exist for me.
It is very true people should stick to the domain they know because otherwise they will have higher than average chance to f up.

But that 'clear boundary' thing is a naive bollocks! No such thing!

Both domain experts need to understand things beyond this imaginary and when precisely drawn then highly arbitrary boundary that is more like a gradient than a line normally (also not something relevant in a final good product).

Teams consisting members unwilling to wander into foreign territory and expecting to be fed and deliver over a strict boundary will do horrible things!

(we are not even trained this way btw., professions have quite a bit of overlap and we learn matters others are expected to take care of in practice, and in case of sofware engineering - apart from the most notorious ignorants no one wants to work with - it is pratically impossible avoiding to learn a big chunk of a foreign profession on the fly for delivering a good product, heavy science is no exception!)

Perhaps I phrased this badly. My point wasn’t a clear boundary between professions, because you are right, that is difficult to impossible to draw. However, there’s a clear boundary between the goals of the code written by scientists vs. software engineers. Where a scientist aims to prove something, a software engineer builds code to produce business value. Both are trained very differently towards these goals.
This probably highlights why so many software engineers in scientific R&D are "bad" in the strictest sense: they often don't understand that business value doesn't come from production-perfect solutions, but instead 100% of the business value comes from doing stuff fast, good enough, and understandable (so that researchers, not software engineers, can read it in a paper and iterate off of it).
I still disagree a bit. Their goals are the same: producing a product that fulfills the intended purpose and brings on value (financial or else or mixed). They may bring in their specialty learned beforehand (or even during) but this distribution of labour is not a goal but tool in reaching the common goal.

Also no such as a software engineer is trained to seeks business value while a scientist seeks proof with clear cut separation, not at all.

If the bad wood working would jepordize the results of his, professional salary earning, work then he should probably consider learning wood working, no?
Don’t think so, no. A physicist has other stuff to learn and spend their time on. Instead, they should partner with a carpenter to do their woodworking from a rough sketch.
If your point is that the physicist should partner with someone who is a "professional programmer" ("carpenter") to do the coding, I couldn't disagree more, speaking as a former research physicist who wrote many programs while I was in academia. A "rough sketch" is not enough for a "carpenter" to go off of for the programs a physicist using computational techniques is writing. They'd need to have a sophisticated understanding of the physics and the mathematical model involved: which almost no "carpenters" have.
Now we’re lost in metaphors. A carpenter should definitely be able to build a pergola from a rough paper sketch, and a software engineer should be able to build a machine learning system from an algorithm paper by a data scientist.
That really depends on what you mean by "machine learning system." For a business, implementing some researched algorithm and essentially using a template? Sure, it's possible. The research that goes into producing the algorithm in the first place? Probably not.

There may be some classes of scientific programming which have simple enough models for a software engineer to implement. Scientific programming that relies on deep understanding of the domain and mathematical models employed to study it don't fit in that category.

Of course it always depends on the context. But my point still stands: a software developer is someone specialising in creating and maintaining code for an application. Any domain knowledge they may need for a particular application doesn’t matter here; their core skill set is software, whereas a scientists core skill set is active research.

Just because some scientific disciplines require extensive programming doesn’t make those scientists good software engineers: Producing an algorithm is different from generating revenue from it.

It’s like saying that a scientist doesn’t need to know how to write, and they should just pair up with ghostwriters/copywriters.

Many professions have tool/skill requirements that are not related to that profession on a strict sense, but are still necessary to do the job properly.

When I learned engineering we were taught how to draw diagrams by hand and write in a technical font. Computer code, for many science fields, is like diagrams but for theories.

It depends on what you consider a core skill. One has to specialize; that means leaving secondary tasks to others.
This is only true for systems where comparative advantage applies. Academia is not one of these places (as they explicitly don't want to be a part of the economy, which I understand).
> It’s like saying that a scientist doesn’t need to know how to write, and they should just pair up with ghostwriters/copywriters.

And I'd say that illustrates my point even better! A scientist needs to know how to write a paper, but that doesn’t make them a great author. When they aim to write a book, they should get help from a professional publisher. Both tasks require writing text, but a book is very different from a paper and requires heaps of additional training and knowledge that scientists usually don’t need to have.

> but that doesn’t make them a great author

This is also widely considered a huge issue in academia. The dissemination is so bad that a lot of great research is never read by others.

Academia is not a business. They barely can sustain themselves, therefore, they need to do things themselves. It is though to be a physicist. Mostly because you, besides being a great physicist, also need to be a good programmer and a good author.

> It is a software engineer’s job to build quality software.

It’s our job to deliver value to the business at a rapid and maintainable way. Rapid changes are often worth more to the business than maintainability, even over a period of many years. In some cases you could put a non software engineer down and let them build something with ChatGPT and it would work perfectly fine for the next 5-10 years because it’s focused on something particular, doesn’t change much and lives in isolation from the greater IT landscape. In other cases all your points are extremely valid.

That being said we also work in an industry where a lot of “best practices” often turn out to be anti-patterns over a period of a decade. OOP is good in theory, and I know why we still teach it in academia, but in practice it very often lead to giant messes of complexity that nobody really knows how works. Not because the theory is wrong, but because people write code on Thursday afternoons after a week of no sleep and a day of terrible meetings.

After a few decades in the industry, what I personally prefer isn’t any particular approach. No, what I prefer is that things are build in isolated services, so that they only handle their particular business related responsibilities. This way, you can always alter things in isolation and focus on improving code that needs it. It also means that some things can be build terrible, and be just fine, because the quality of the tiny service doesn’t really get to “matter” over its life time.

I personally write code that follows most of our industry’s common best practices. Because it’s frankly faster once you get used to it, but I’ve seen really shitty spaghetti code perform its function perfectly and never need alteration in the 5-10 years it needed to live before being replaced.

"It’s the same story, really: It is a software engineer’s job to build quality software. A scientists job is to solve problems."

That's not the distinction. Good software engineers solve problems. That's what the paycheck is for. The distinction is whether code has to be maintained.

It's the scientist's job to solve a specific problem at a specific time. Who cares if the metaphorical wood rots next winter, the paper's been published.

It's _often_ the software engineer's job to build things that deliver business value over years, evolving and expanding requirements, in a development team, without grinding to a halt under the weight of accumulated complexity.

"Quality" software engineering is just heuristics for keeping the pace of change high over time without breaking things.

> It's the scientist's job to solve a specific problem at a specific time. Who cares if the metaphorical wood rots next winter, the paper's been published.

Sounds a little like cargo-culting than proper reproducible research. But this is a pest in academia definitely. Many papers do not provide all required data, all required model parameters etc. to get to the exact same result. Admittedly, they might nowadays need a software engineer to get that done.

Cargo-culting is about focusing on the process without fully understanding its purpose. Such as bureaucratic requirements for providing all data, software, parameters etc so that someone can reproduce exactly the same numbers with minimal effort.

Proper reproducible research is not like that. It's about providing sufficient details that other people in the field can extrapolate the rest. That they can use similar methods with similar data to achieve similar results.

Reproducing exactly the same result is not that valuable, as the "result" could be just an artifact of the specific data and specific methodology. Real validation depends on fully independent replications, with as little reuse of data and code as reasonably possible.

In software I have found getting the exact details and parameters very useful even if I don't intend to use them. Because when I try to do the same thing my own way and fail, then I can reference the original ones and gradually make my own version more and more similar to that, and see when it starts working. Or make their version more and more similar to mine and see when it breaks. This allows quickly easily identifying the critical difference.
If we cannot reproduce research results, due to missing the data, parameters, or code, or whatever else, is it not cargo culting, to take that research result and blindly believe it and build on top of it? If I remember correctly, Feynman stated in the same video, that one should actually reconstruct or reproduce the experimental results we rely on.
> Who cares if the metaphorical wood rots next winter, the paper's been published.

Isn't this why the replication crisis was able to be kept hidden for so long?

Not as far as I know. Much more problematic was the fact that replication is very hard to publish. That's because either you more or less confirm previous findings and therefore contribute little to the scientific record (or so reviewers seem to think), or your findings counter the original results and now it's on you to explain the discrepancy. Even if you satisfy the reviewers that you're right, they may not consider your result of sufficient caliber to accept for publication in this particular venue [1].

[1] I've seen this happen to a paper that proved that a theoretical framework for constructing proofs about RFID protocols was neither sound nor complete.

The first distinction here should be what kind of "code" are we talking about. As far as I see there are two main possibilities:

  1. code for performing a scientific simulation or analysis (a script).
  2. code for solving a specific problem generally (a program).
There are different "best practices" for the two situations above. And the article primarily talks about applying "best practices" from the 2nd scenario to the 1st. Of course they don't apply.
I'm an ex-software developer/engineer and current scientist. In my experience TFA makes a good point, even though it's quite strawmanish.

Most scientific code is horrible from any sane software developer perspective. The quality is so bad that I think a huge proportion of published results are plain wrong due to bugs in the analysis. These apply to my much of my code as well.

But a lot of "software engineering" code is horrible too. Mostly because most popular technologies and "best practices" are just plain bad. Overenginering is a pandemic and has been a long time. Much of the roots is from the gilded age of enterprise Java. Totally misunderstood OOP. Byzantine layers of pointless abstraction. Rampant premature "web scale". Counterproductive bondage and discipline (yes, including much of static typing).

These have become a cargo cult in software development, and these cosmetic features are deemed as "quality code".

And this leaks into scientific programming. Even Python, arguably the language of science nowadays, and a "quick and dirty one", forces some of this cargo cult. Modules are needlessly complicated (e.g. relative and absolute imports are quite a mess), let alone the horrible packaging system. And the current trend to push typing.

That said, scientific code is getting slowly better, largely due to switch to public/open source code, and away from specialized hacks like MATLAB and R. Especially in more technical fields.

In software engineering OTOH things are IMHO getting worse.

I'll add that "code reuse" was pushed as an idea too heavily (at my university at least). I think that leads to a fair bit of the over engineering and unnecessary complexity.

I saw a comment later saying not to aim for "code reuse", but rather to "avoid code duplication" which made more sense.

I also agree that a lot of best practices are great if you are a massive company with unlimited resources, but they are just overkill and add complexity for smaller projects and teams.

Code reuse was indeed the hype, especially of OOP and inheritance. In practice it just made real code reuse a lot worse. The class hierarchies become so tightly coupled that any "reuse" requires a lot more boilerplate than the actual code to use.

I know that the idea is not just not writing more code, but have a "single point of truth". But the boilerplate leads to a situation where it's very inpractical and leads to a tightly coupled mess that's really hard to change.

What actually increased code reuse was duck typing (i.e. implicit interfaces), made popular by Python. But that's becoming verboten nowadays. And I don't think current structural typing systems are gonna reach the same level of reuse.

I basically agree (except I will take static typing over dynamic typing any day).

I work in computational chemistry, and scientists here don’t necessarily have problems actually coding (we’ve been doing it for 70+ years). But the “other stuff” is taking more and more time.

Before, you wrote Fortran, put the files on disks or whatever, and sent them around. Now, you need to know:

C++ and Python (and maybe Fortran too)

git and github and github actions, and packaging (pypi/conda/conda-forge I guess is the standard now).

Documentation? Sphinx I guess, although mixed codebases are still a pain. And where do I host the docs again?

Also better make sure it works on all three OSs.

Wait what is docker? Suppose I better learn make images. And they have to be hosted somewhere? Got to set that up too.

Oh wait again, Python 3.12 broke something. Have to fix that.

Does all of this make “better software”?. I’m coming around to the idea that maybe it doesn’t, at least in aggregate. Either way, scientists don’t have time to really learn all this AND the science they are doing. And it all changes every few years or so.

> Either way, scientists don’t have time to really learn all this AND the science they are doing. And it all changes every few years or so.

This is how I see it as well. I'm an immunologist, and it feels impossible for me to keep on top of my field of research and just about anything else. I don't have to produce quality software, but it seems difficult to keep your research cutting edge while maintaining software. It's hard enough keeping the research up to date!

> (except I will take static typing over dynamic typing any day)

Why? What exact typesystem do you prefer over Python's dynamic typing? A lot of its idioms, and probably e.g. NumPy/SciPy infrastructure would be about impossible with current static typesystems (look at the mess that is C++ scientific/ndarray libraries). Ditto for much of the autodiff and GPU stuff like pytorch.

Julia could perhaps get there, but the implementation has too many warts for it to take over.

It's more to do with developer ergonomics. Knowing what something is or returns (and having some guarantees about it) make it much easier to reason about code. Then, knowing (with guarantees) what a variable/object is, knowing right away what I can do with it.

> What exact typesystem do you prefer over Python's dynamic typing?

I just want to know what various objects are laying around in my code so I don't have to keep it in my head.

For example, if you are using a database library like psycopg, you run a query and execute it. What kind of object is returned from the query execution function? How do you check if it was null? You have to go looking at documentation, and often what you find is examples of what you can do. But those examples often don't include absolutely everything, so you have to go looking at the code itself. But library code in python is often pretty arcane.

With Fortran/C++/Rust/etc, you get all of that basically for free in your editor's autocomplete. And the compiler will check to make sure you didn't do anything truly dumb.

Dynamic typing also encourages some frustratingly bad habits. Lots of code out there will have functions that change return type depending on what arguments are provided. And occasionally someone will forget to return something in some branch and you won't know until you hit an edge case (during runtime) and suddenly you have a None coming from somewhere.

My projects tend to be in Python now, but I recently started a side project in C++ again and found it very refreshing.

> probably e.g. NumPy/SciPy infrastructure would be about impossible

Partly true, but maybe not as true as you think. I've been using the nlohmann JSON library for C++, and it is amazing. The code almost looks pythonic, and its type conversions are done automatically (although at runtime of course).

For example,

  for(const auto &[key, value] : some_json["x"].items())
    double d = value["other_key"];
EDIT: Also, I didn't realize how much I missed function overloading until I started the C++ project. Wow is that handy.
I find that "what can I do with the value" is a lot more important than "what the object is". Especially in scientific context this is usually "can I iterate this" "can I do arithmetic with this" etc. NumPy's broadcasting and support for "any" iterables is a great example of this. And very difficult to accomplish with at least the typesystems you listed.

E.g. going from a nested list in a JSON to a Eigen matrix is quite a pain even with (awesome) libraries like nlohmann/json.

I often have to resort to C++ for performance or libraries. I make a lot more bugs than in Python. And the bugs are often really tricky and often pass the typesystem (e.g. both nlohmann and Eigen have to really hack the templates and these cause a lot of edge cases).

Also serializing stuff in C++ is a real pain even with nlohmann/json because for god's sake there's still no reflection in C++ in 2024.

Of course you can abuse the power of dynamic typing. But you can just as well abuse anything else that's remotely powerful (see e.g. Boost).

I guess the main problem is that many self-proclaimed "software engineers" are surprisingly bad "programmers" ;)
Just like most "research" is absolutely useless, when not counter-productive ;)
It's often very useful for those funding it.
Universities? Their main goal is to get better in the rankings, isn't it?
The problem is that most “professional” developers — i.e. people who write software as a career — are terrible at those things. Even (especially, sometimes) those that call themselves Software Engineers and talk endlessly about the right way to do things.

That is not to say the kind of software engineer that does what you say and tends to build quality software (or at least move it in that direction) doesn’t exist, but the demand for people who can make computers do stuff (loosely, developers) so far outstrips the supply that outside of a few bubbles (HN being one of them), they appear to be so vanishingly rare they might as well not exist.

I’m sure some scientists get to work with useful and highly valuable professional developers, but I’d be amazed if they were the majority.

>Neither does a scientist have to build proper software, nor does a developer have to do cutting-edge research.

Sounds like the mission of Research Software Engineers (https://society-rse.org/).

I work as a software engineer (with a PhD in a field that is not CS) in a research setting, and there is a give and take. 50% of my job is reading, understanding, and adapting very bad code from non-software engineers into a production system. But another 50% is binning the overwrought inflexible code written by my software engineer predecessors in order to do all that more quickly than refactoring would allow.

In a research setting, in my opinion, MVP is king. Researchers seem to usually not produce viable long-term solutions. But software engineers do as well by virtue of not being domain experts (how could they be, they would need a PhD to understand the research domain!) and being unable to test 100% of the assumptions underlying the software themselves. Which is why it can help to have someone in between who is a domain expert, but knows just enough software engineering to produce production-good-enough code.

Research software engineering is a hybrid field and fixed roles do not work well. It requires one having a grasp (at some level) of a lot of different stuff, eg software engineerin, the relevant scientific theories, statistics _and_, quite importantly, the culture of scientific practices in a field, in order to make something good. So it gathers a lot of people who, no matter where they started from, often have to sort of converge by learning stuff outside their own discipline.

The problem is not that "physicists write code". Scientists end up learning a lot of stuff and getting good at it (software engineers the same). The problem is that writing software is often left as a job for the occasional phd, postdoc or research assistant, ie people with temporary positions, and in general to people who see building software as a side duty at best, annoyance at worst. This results in no generational knowledge building, being hard to find mentors, less learning and reflecting on practices on how to build software, rediscovering the wheel constantly, too much effort put into . It is not that one graduates as "software engineer" or as a "scientist" and then they know the best practices and everything of their respective fields. People get to learn stuff. Software engineering practices should be in the culture of scientific software building, not simply carrying them from the software engineering world to science, but adapting them and taking it each own idiosyncrasies as a field.

I agree, a lot of unmaintained code is due to turnover of staff and few considering the software as an important output in its own right. But I don't think it would be that hard to find grad students/postdocs who would care about code, if that were something the field properly incentivized. Not only does software contribution not check the right boxes for career progression, it is also often looked down on.

I find this especially laughable in biology... I've seen some (faculty) PhD committee members object to the student having a thesis chapter related to software contributions, because this is not "intellectual". But they are perfectly fine with one of the chapters being a wet lab paper where the student was a 3rd author who contributed purely through helping run experiments designed by the 1st author (e.g. handling mice, pipetting shit). There are PIs that simultaneously hold these two views, which to me signals a real misunderstanding of the challenges in and importance of writing decent software.

> It is a software engineer’s job to build quality software. A scientists job is to solve problems. There’s a clear boundary here, where the latter will deliver a concept to the former, who will eventually create a production-grade implementation off of that. Neither does a scientist have to build proper software, nor does a developer have to do cutting-edge research.

Precisely! See my relevant comment from another thread here - https://news.ycombinator.com/item?id=38821679

References:

1) Why science needs more research software engineers - https://www.nature.com/articles/d41586-022-01516-2

2) Research software engineering - https://en.wikipedia.org/wiki/Research_software_engineering

(comment deleted)
>It is a software engineer’s job to build quality software.

I think that most software engineers' jobs is not to build quality software, it is to make money. When you are trying to make money, the goal is not necessarily to make the best quality software that you can. Often, it is to make acceptably good software as soon as possible. A company that writes software that is half as good and ships it twice as fast might outcompete a company that writes software that is twice as good and ships it half as fast. I sometimes wish that my job was to build the best quality software that I can, but that is not the case. What I really get paid for is to make my employers' company successful, to make them money. And it's not that my employers don't care about making high quality software, it is just that if they cared about it too much they might get outcompeted by others who care less about it.

>Multiple/virtual/high-on-crack inheritance 7 to 14 stack frames composed principally of thin wrappers, some of them function pointers/virtual functions, possibly inside interrupt handlers or what-not Files spread in umpteen directories

Scientific code? You just described 99% of "enterprise" java code above.

That's from the list of software engineer sins, yes, so that tracks with your opinion.
I've seen this:

- Multiple/virtual/high-on-crack inheritance:

  add each function/class has 7 template specialization parameters and 3 macros which expand to templates which expand to macros
  
- Lookup using dynamic structures from hell – dictionaries of names where the names are concatenated from various pieces at runtime, etc.

  think maps of maps of maps loaded from configs of configs
  
- Dynamic loading and other grep-defeating techniques

  obviously everything has to be a "plugin"
  
- A forest of near-identical names along the lines of DriverController, ControllerManager, DriverManager, ManagerController, controlDriver ad infinitum – all calling each other

  a 1000 times yes! yes!!! DriverController inherits from ControllerManager which extends ManagerController which contains a DriverManager which agregates 3 ControllerManager from diferent namespaces. I've seen a DriverController function going through 12 levels of stack passed between 3 threads to eventually call back a function from the same DriverController
  
- Templates calling overloaded functions with declarations hopefully visible where the template is defined, maybe not

  if a template technique exists, it had to be used!
  
- Decorators, metaclasses, code generation, etc. etc.

  Of course they define their own DDL with xmls parsed by a combination of Python and awk which generates C++ macros which are used in templates to dynamically load plugins which hold maps of maps of function pointers to create3 events dispatched on a pool of threads
reminds me of java spring library

and on top of it those DriverControllers and ManagerControllers keep getting depracated