Why Does Software Rot?

Almost a year ago computer scientist Daniel Lemire wrote a post critical of a hypothesis I’ve favored, one I’ve used in Age of Em. On the “better late than never” principle, I’ll finally respond now. The hypothesis:

Systems that adapt to contexts tend to get more fragile and harder to readapt to new contexts.

In a 2012 post I said we see this tendency in human brains, in animal brains, in software, in product design, in species, and in individual cells. There is a related academic literature on design feature entrenchment (e.g., here, here, here, here).

Lemire’s 2015 response:

I am arguing back that the open source framework running the Internet, and serving as a foundation for companies like Google and Apple, is a counterexample. Apache, the most important web server software today, is an old piece of technology whose name is a play on words (“a patched server”) indicating that it has been massively patched. The Linux kernel itself runs much of the Internet, and has served as the basis for the Android kernel. It has been heavily updated… Linus Torvalds wrote the original Linux kernel as a tool to run Unix on 386 PCs… Modern-day Linux is thousands of times more flexible.

So we have evolved from writing everything from scratch (in the seventies) to massively reusing and updated pre-existing software. And yet, the software industry is the most flexible, fast-growing industry on the planet. .. If every start-up had to build its own database engine, its own web server… it would still cost millions of dollars to do anything. And that is exactly what would happen if old software grew inflexible: to apply Apache or MySQL to the need of your start-up, you would need to rewrite them first… a costly endeavour. ..

Oracle was not built from the ground up to run on thousands of servers in a cloud environment. So some companies are replacing Oracle with more recent alternatives. But they are not doing so because Oracle has gotten worse, or that Oracle engineers cannot keep up. When I program in Java, I use an API that dates back to 1998 if not earlier. It has been repeatedly updated and it has become more flexible as a result…

Newer programming languages are often interesting, but they are typically less flexible at first than older languages. Everything else being equal, older languages perform better and are faster. They improve over time. .. Just like writers of non-fiction still manage to write large volumes without ending with an incoherent mass, software programmers have learned to cope with very large and very complex endeavours. ..

Programmers, especially young programmers, often prefer to start from scratch. .. In part because it is much more fun to write code than to read code, while both are equally hard. That taste for fresh code is not an indication that starting from scratch is a good habit. Quite the opposite! ..
“Technical debt” .. is a scenario whereas the programmers have quickly adapted to new circumstances, but without solid testing, documentation and design. The software is known to be flawed and difficult, but it is not updated because it “works”. Brains do experience this same effect.

I have long relied on a distinction between architecture and content (see here, here, here, here, here). Content is the part of a system that it is easy to add to or change without changing the rest of the system; architecture is the other part. (Yes, there is a spectrum.) The more content that is fitted to an architecture, and the bigger is that architecture, the harder it becomes to change the architecture.

Lemire’s examples seem to be of systems which grow long and large because they don’t change their core architecture. When an architecture is well enough matched to a stable problem, systems build on it can last long, and grow large, because it is too much trouble to start a competing system from scratch. But when different approaches or environments need different architectures, then after a system grows large enough, one is mostly forced to start over from scratch to use a different enough approach, or to function in a different enough environment.

This is probably why “Some companies are replacing Oracle with more recent alternatives.” Oracle’s architecture isn’t well enough matched. I just can’t buy Lemire’s suggestion that the only reason people ever start new software systems from scratch today is the arrogance and self-indulgence of youth. It happens way far too often to explain that way.

GD Star Rating
Tagged as: ,
Trackback URL:
  • SpeakingOfGoogAmazAppBook

    Some people dont want to work at GoogAmazAppBook for that reason: “architecture isn’t well enough matched ” or orgs have taken combative stances to projects that mattered by such people.

    Some might even revel in such organizations burning in their on rot slowly over time 😛

    • aubreykohn

      Much like any major centuries-old city, as long as they can ingest enough energy, they can reorg their mud as required.

  • James Babcock

    It’s not always architecture, exactly. Projects often accumulate things that’re sort-of like technical debt, but tied closely to coordination problems, usually due to compatibility requirements.

    For example, the C++ programming language has lots of flaws that can’t be fixed without breaking existing C++ programs, so they won’t be fixed. But this isn’t the only type of coordination problem. No one can unilaterally improve C++, because there are many compilers and people demand that programs which compile in one compiler should compile in all of them, so adding a new feature usually means going through a slow-moving standards body and waiting for every compiler to implement the change. This is why Python (which has a single canonical implementation) has ended up being so much more featureful than Java (which has implementations by many companies, some of which are slow moving and conservative).

    Oracle is a pretty central example of this problem, because it’s closely tied to a programming language, with lots of existing software depending on it continuing to work the same way it always has. While Oracle could modify its database software to be more distributed, it would be very difficult to do so in a way that didn’t cause problems for its existing users.

  • Joe

    “Content is the part of a system that it is easy to add to or change without changing the rest of the system; architecture is the other part. (Yes, there is a spectrum.)”

    Provides some level of answer to my question on a different post from the other day – so thanks.

    But, but, but… I’m still unsure how this framework applies to AI. Take some machine learning system – perhaps the Atari-playing DeepMind. You train it by letting it play for a while. It builds up some kind of fuzzy internal structure representing what control input to make based on the state of the visual display output of the game.

    Which part of this is the content? Is it the whole trained system, with that internal structure providing the instructions to the system for how to play? Is it the data that is fed to the system in order to train it? Without knowing what you define as ‘the system’ I am struggling to really make sense of your perspective on AI.

    Would you perhaps argue instead that a system that is trained to play, say, Breakout, could be seen as being composed of content, but is too small and specific to be worth decomposing in such a way – though it might well be used as content within a larger system?

    • I think people in deep learning would say that the initial state of the DQN – a 5(?)-layer CNN taking as input a downscaled Atari greyscale screen and emitting a reward estimate for each of the possible actions, trained using a particular SGD algorithm Z on an experience replay buffer of X size, with all parameters initialized to random values between 0 and, say, sqrt(params) – is the architecture, and then all the subsequent changes in the parameters are the ‘content’. However, this ‘content’ doesn’t really ‘rot’. It mostly just gets better as it plays the Atari game more. Confusing the ‘rot’ analogy further, while it’s generally hard to repurpose software (an XML library will not easily handle Markdown files), you can quite easily use the trained model for other things, because the CNN will wind up learning much more than a few simple strategies: it’ll start learning what all the different kinds of objects are, how they move, and what moves in a game are helpful. Yes, the NN might make a lot of mistakes if you start using it on Frostbite rather than Breakout, but, well, that’s what gradient descent is for fixing, automatically. You can especially take the trained model and use it as the initialized values for training on a different game! This sort of ‘transfer learning’ is used all the time with the ImageNet trained models, because those CNNs turn out to have learned a lot beyond just distinguishing dog breeds. (Want to do tagging/multi-classification? Start with a pretrained model like VGG. Want to do image->caption work? COCO isn’t big enough, start with a pretrained model. Want to do image segmentation? Do you have that VGG handy… Want to do style transfer? Better have that ImageNet model downloaded etc.) In this sense, a deep model doesn’t ‘rot’, and a deep model pre-trained on a similar task will both train faster and better than a model trained from scratch. From the information-theoretic point of view, this is totally trivial: if task A and task B are at all similar, a program solving task A and task B will be smaller than the length of programs solving A and B separately; because the mutual information means that functionality can be shared across the tasks. (Obviously in a lot of games, it’s useful to have a sense of objectness, so two separate DQNs will both need to learn something like that, and could share it.) But it is different from regular software where the software is so brittle that it’s typically easier to junk the code outright and start over.

      • As you say at the start, learning systems have architectures. The bigger and more complex a system you want to learn about, the bigger and more complex the architecture. When these architectures are changed to adapt to new environments, that is a thing that becomes fragile over time.

      • aubreykohn

        Your second statement seems under-motivated. Cortical structure, for example, is largely homogeneous: Very little of the complexity is at higher architectural tiers. One could argue that there are dual architectural extrema, and the complexity lies in their interface, where the actual adaptation occurs. (One extremum being the apperceptive unity of consciousness, and the other, the standard model.)

      • That sounds kind of empty of content. Yes, in the standard backprop-driven deep net, the architecture is predefined. But in an evolutionary genetic neural network, the architecture is just another thing to be evolved; in a backpropagation-through-hyperparameters architecture, the architecture is just another set of parameters to backprop error through; in a recursive net, the architecture of sub or task-specific networks is just another task to learn. If ‘evolveability can evolve’, it’s not clear why architectures would be more fragile over time rather than, like the learned content, more robust and useful over time. Hence my comment about a highly generic RNN potentially being a good starting point for all tasks.

      • Humans are the best learners we know of, yet when we try to learn how to build and adapt systems, we run into this problem of increasing fragility as we adapt them. You speculate that your favorite neural networks won’t have this problem, but they haven’t yet dealt with the kind of complex systems at issue here. I’m very skeptical they will do better.

      • I’m not sure what’s speculation here. It’s a fact that neural nets have relatively minimal architectures compared to hand-coded programs and this is inherent to their power and flexibility. Human neural networks are indeed the best learners we know of, but rather than rot constantly, they improve for many decades while being given a wide diversity of task after task, and to the extent human neural networks finally do begin to ‘rot’, it’s directly traceable to the aging process, which makes all biological cells ‘rot’. (Do human muscle or liver cells ‘rot’ through aging because their ‘architecture’ is pushed too far?) You keep implying that there’s some hard and fast distinction between content and architecture and drawing these vast conclusions from this metaphor, but I’m not seeing it.

      • Yes nets can have less architecture, but they still have some. No, it is far from obvious that all human degradation is due to cell aging. Unless you think the systems that nets design are immune from the usual bit rot problems we see in systems humans design, then when nets design their own architectures they should see the same problems. And this predicts mind rot.

      • Neuronal death with age is enormous. Plaques build up. Bodily integrity and cognitive integrity predict each other. Early childhood intelligence predicts late life intelligence and also longevity, which also are due to genetic correlations. Lots of things go wrong with age. Are there any results in geriatrics which indicate that declines in cognitive performance are *not* due to aging? This is a remarkable claim I have never seen before, that cognitive decline with age is not due to the biological underpinnings. Again, do you think that muscles and liver cells and other cells whose tasks never change decline with aging because of architecture changes…? Where do you get this belief that while all sorts of cells decline in function with age, the brain is a unique special exception to all the usual rules and its simultaneous decline is actually due to an entirely different principle? And I have already explained how nets are very different from human-written software and why they do not seem to rot and why we would expect this from an information-theoretic perspective: tasks share some degree of mutual information and so reuse and adaptation of programs will be more efficient than periodically starting from scratch, and if it isn’t, that says more about the badness of the program representations / learning methods than what is possible.

      • Are there any results in geriatrics which indicate that declines in cognitive performance are *not* due to aging? This is a remarkable claim I have never seen before, that cognitive decline with age is not due to the biological underpinnings.

        There’s the observation that outdated scientific paradigms are replaced only when their users die. This is a decline in flexibility that isn’t easily explained by biological aging.

      • Why isn’t it easily explained by biological aging causing steep declines in fluid intelligence – typically briefly described as the ability to learn *new* material and paradigms, as opposed to crystallized intelligence – and, of course, ordinary incentives?

      • Did Einstein reject quantum mechanics because he lacked fluid intelligence? His argument that almost stumped Bohr indicates he retained considerable fluid prowess.

        If it were a matter of adequate fluid intelligence, the most eminent scientists would show some proclivity to change paradigms.

        There’s abundant experimental evidence that mental sets resist change, whereas I don’t think it’s been clearly established that fluid intelligence facilitates change of opinion. There’s even reason to suppose it may make people more stubborn if they’re committed to a viewpoint.

      • Given the extreme youth of many of those making QM breakthroughs and the difficulty they had transmitting their insights to others, I am sure that the sheer difficulty of understanding the new paradigm was indeed an issue for many of those whom Planck described in his famous quip (and I’ve read as much in the memoirs and materials from physicists at the time like Eugene Wigner and other historical accounts). I am not so eager as you to take what was a statistical generalization and applying it to ad hominems against individuals like Einstein. There are always both legitimate and illegitimate grounds for disagreement, and I hope that for Einstein it was more the former than the latter.

      • It’s not presented as a statistical generalization, but as an exceptionless rule.

        Anyway, the problem with the fluid-intelligence explanation is that the loss averages only 5 IQ points per decade.

      • It would be uncharitable to interpret Planck as giving an exceptionless rule. And I don’t know why ‘only 5 IQ points’ isn’t a lot, especially when you pair it with the other age-related declines in WM, energy, short-term memory, sleep quality, and general health; a top scientist only has 10 or 15 points at most over ordinary researchers, so in the QM example, the fiery young turk at age 20 has lost a great deal by the time he’s 50 or 60. About the only thing he will have gained is a great deal of experience & knowledge (long-term memory hasn’t deteriorated enough to offset the advantage of time), but that’s all in the old paradigm, giving him even further incentive to continue working in the old paradigm and ignore or attack any new ones where his cached knowledge is less valuable. Incentives matter a great deal, as does the brain, so this seems adequate to explain Planck’s observation without using any metaphors about ‘rot’.

      • Can you think of exceptions?

        Exceptions are numerous in philosophy. That’s because philosophical differences are the result of conceptual reorganization rather than a gestalt shift in perception. Scientists faced with a new paradigm say things like, ‘If that’s what physics is going to be, I’m not interested.’

  • Lord

    Early on, architectures are inflexible and brittle but readily adapt. As they gain experience, both intensive and extensive, they acquire robust flexibility to handle most problems and are less likely to need revision. Still, as the environment changes and needs change, periodic revisions are undertaken to improve them. When the differences are significant enough, it becomes reasonable to create something new, whether that new replaces, interfaces, or integrates into the existing architecture, building on all the knowledge that has been gained from it. As more flexibility is incorporated and there is a more stable environment with less change, there is less likelihood of needing to change.

    • The need to start over when environment differences are big is exactly due to an inflexibility of the system. It can’t flex that far.

      • Lord

        Starting over doesn’t mean existing product is displaced though, more that a new one is created. The way to think of it is cockroaches have been around over 100 million years, flexible in some ways, not in others, highly robust at what they do, but not trying to become everything and do everything. Cockroach bit rot is near if not at zero.

  • CommentsCommunicationMajor

    Someone should let the guy know that people who have a choice, and startuppers in particular, aren’t using Apache, MySQL or Java but rather nginx, PostgreSQL, and one of these younger languages.

    • lacker

      True for Apache and Java, but MySQL is still plenty popular among startups.

    • Pawan Dubey

      PostgreSQL came out at roughly the same time as MySQL. Java was initially released in the mid 90s. So were the languages of choice today like Python and Ruby. The only new language that has managed to make a dent is Go, and there is still no replacement for Java when it comes to scalability.

  • I side with you over Daniel Lemire that systems tend to ossify with age. But “update less” seems like too big a concession. I’ve been working on more intermediate approaches that make software more rewrite-friendly: http://akkartik.name/about.

    Your hypothesis is valid today, but it’s not clear that it’s fundamental or immutable.

  • brent_tubbs

    I think it depends a lot on how you adapt to the context. If you do it by adding new special cases and weird appendages, then yeah you’ve made it harder to adapt in the future.

    If on the other hand you adapt to context with a good abstraction, you are probably making it easier to adapt to new contexts.

    Sometimes we only know in hindsight whether our abstractions are good.

    The long-lived systems you describe (particularly the Linux kernel) have been refactored many times to create good abstractions.

    The “Big Ball of Mud” essay is the best analysis I know on the topic of software rot. http://www.laputan.org/mud/

  • aubreykohn

    Arrogance and self-indulgence yes, but also incompetence and penny-wisdom/pound-folly. Together these explain a vast swath of behaviour. Perhaps not all, but perhaps enough for the residue to be negligible.

  • lacker

    I agree with this article except for the speculation at the end that “Oracle’s architecture isn’t well enough matched”. Oracle’s architecture is basically the same as MySQL or Postgres – they are each databases you interact with via SQL, and developers using it don’t really get into the guts, so a system that uses Oracle databases has essentially the same architecture as one that uses MySQL or Postgres.

    MySQL/Postgres are better for two reasons. One is that they are free! Oracle is quite expensive and does basically the same thing. Over time the open source solutions evolve, and there just isn’t that much more you could ask for from a SQL-based DB, so MySQL and Postgres got “good enough”.

    The other reason is that, being free, they have spawned a wider ecosystem of free tools contributed by others. If for example you are building an app with Ruby on Rails, there is far more open source middleware, connectors, helper libraries, and documentation around using MySQL rather than Oracle. So it’s easier to use MySQL, and that ecosystem is an ongoing advantage.

    But overall the point is a good one. Complex systems become brittle over time – extending Windows 95 to mobile didn’t work that well. Systems built from many modular components can become stronger over time, and that’s how many modern open source systems work.

    • How one prices, funds and partners a systems is part of its larger social architecture.

  • Silent Cal

    I think we’re failing to distinguish two phenomena:

    1) Architecture compromising its flexibility to support specific content
    2) Architecture not being flexible enough in the first place

    1) happens frequently but not inevitably; it depends on social/political relations between content creators and architecture maintainers. This sort of ‘bit rot’ happens a lot within companies, but independently-maintained programming languages are much more able to resist it (admittedly, my only citation for this is intuition).

    2) eventually happens to any architecture if the world changes enough.

    A system fighting 2) can look like one suffering from 1), but the causes are different. Programming generically in C is ugly in a big-ball-of-mud-ish way, but it isn’t that way because C designers made ugly hacks to support non-generic programming; it’s because it just wasn’t designed for generics.

    When you say “Oracle’s architecture isn’t well enough matched”, that sounds like a case of 2), not of 1).

  • Pingback: Overcoming Bias : Entrenchit Happens()