“Just like a cut diamond, code that does not accept any change won’t easily modify its shape”
Carlo Pescio, a programmer who has been breathing software for over 35 years, wrote a paper titled Decisions, Assumptions, and Overfitting or why most “clever” code ain’t so clever after all in which he claimed that “clever” code is actually fragile. We talked about how “clever” code can break under change and what can be done to prevent that from happening.
Carlo Pescio revealed in a recent paper that “there is a deluge of “clever” code constantly pushed down from gurus to hipsters to innocent readers. These days, clever code usually comes under the form of functional programming snippets. Unfortunately, people tend to assume that the style of such (supposedly) clever code is representative of “good” functional programming. Yet that style, albeit extremely popular, leads to fragile code, incapable of accepting even small changes in requirements without major changes in the overall structure and strategy. It doesn’t have to be so, but someone has to play the boogeyman and show that it’s not clever, it’s fragile.”
JAXenter.com spoke to him about how “clever” code can break under change and what can be done to prevent that from happening.
JAXenter: In your paper you claim that “clever” code is actually fragile. Why is that?
Carlo Pescio: As humans, we love symmetries and regularities. We find them beautiful and elegant: we cut rough gemstones in highly symmetric shapes because we’re (visually and intellectually) attracted by those shapes.
“Clever” code tends to exploit perceived regularities in the problem space, responding with strongly symmetrical solutions, often based on math-inspired language or library support. Regularities allow for minimalism of expression, and we recognize the symmetric shape of the final artifact as beautiful. We tend to consider minimalistic and beautiful as “clever”. Unfortunately, the real world is not regular and symmetric. It will constantly push back with corner cases, custom behaviors, absurd regulations that you still have to comply with, hardware issues you have to fix at the software level, etc. Code that does not allow irregularities to happen might be beautiful and clever, but just like a cut diamond it won’t easily change its shape. Highly regular structures cannot be adapted and evolved without disrupting their delicate balance; their minimalism of expression gives no affordances for growth and adaptation. You have to take down and rethink your solution from scratch, instead of evolving it as needed. That’s absolutely ok if you’re only concerned with solving puzzles and show your prowess, less ok if you’re part of a team working on real code.
JAXenter: Why do you think the most interesting properties revolve around ease of change?
Carlo Pescio: High-value software is always surrounded by uncertainty. Uncertainty may come from technological challenges, from a changing world, from fluctuating market opportunities, but it’s always there. If there is no uncertainty, there is a high chance that the problem has already been solved and commoditized. Now, you can deal with uncertainty in many ways. Some changes can be somewhat planned, that is, you don’t know the exact change you will face, but you know there is a growth model for part of the problem / product and you can engineer for that. Most changes cannot be predicted; it’s simply not reasonable to design everything for accretive growth. Yet change will come; and in some cases, a significant deal will be on the line. So the code must accept change gracefully, especially the nasty, irregular changes that come from the real world. I pointed to the notion of habitable software from Richard Gabriel in my paper, and I warmly suggest everyone to read his paper on that subject.
JAXenter: You also say that “clever” code can break under change. How can we make sure this doesn’t happen? Do you have any personal experiences —any battle scars or lessons learned?
Carlo Pescio: The honest answer is that we don’t have any real method to ensure that our code won’t break under change. Like many real-world issues, it has been largely ignored by computer science and only dealt with through “principles” in software engineering. Still, we do have some pragmatic ideas on what to aim for and what to avoid. Just to restate two points from my paper:
- We need to stay aware of the assumptions we’re making, and how pervasive those assumptions are becoming, and make sure that we can locally break those assumptions if the nasty real world calls for that.
- We better stay away from structures that are inherently incapable of dealing with irregularities.
There are many other ingredients in the recipe for flexible software, of course, and while many are gravitating around software engineering, a good understanding of the problem domain is also extremely important, as it will reveal irregularities way sooner.
High-value software is always surrounded by uncertainty.
JAXenter: Why do you believe that this paper will be the most unpopular piece you’ve ever written? Why did you choose this code?
Carlo Pescio: Software development requires a strong dedication to learning. We make large intellectual investments in learning languages, paradigms, methods, etc. For a number of people, that translates into an equally large emotional investment; they round up as tribes around their totems. Some communities maintain a sense of self-irony and proportion, some don’t. Some are actually built around the idea that their way is the superior way. When people find flaws around the concepts preached by those communities, they usually keep quiet because nobody wants to kick the hornet’s nest. If you do, you know what is going to happen. I did it anyway.
I chose to base the discussion around Haskell code because, had I chosen any other language, people would have said “yeah but in Haskell…” Interestingly, even though I didn’t say a single thing against Haskell itself, and even though I repeatedly said that my concerns were with a specific (albeit popular) style of functional programming, not with FP as a paradigm, I’ve been accused of “picking on Haskell” and “picking on FP”. But that too was expected.
JAXenter: What conclusions can be drawn after analyzing this code?
Carlo Pescio: The highly regular structure didn’t save us from a bug, even in 20 lines of code solving a clear, algorithmic, well-defined problem. That same structure cannot be locally adapted to accept a very reasonable change (given the problem domain) without a complete overhaul. It has been assembled from highly reusable library functions, but the result has almost no intrinsic flexibility, and very little room for change.
JAXenter: You also emphasize the following message: “If you write your code as a strict chain of library functions (assuming uniform behavior like libraries do), operating on library types (uniform again by necessity), replacing all control flow with uniform collection- oriented library functions, you’re giving up all your chances to accommodate non- uniform behavior / broken symmetry, and by and large any real-world change.” What do you mean by that?
Carlo Pescio: As I said, the real world is full of nasty exceptions to the rule. It doesn’t want to fit into highly regular structures. Part of it may fit well there – the fact that we have asymmetries doesn’t mean we never have symmetries. But if your code is a long chain of functions all assuming uniform behavior over uniform data, mostly reusing functions and types from math-inspired libraries full of symmetries, well, you can only end up with end-to-end uniform behavior. Even worse: when a chain of functions gets too tight, you can’t find a place where irregularities can be handled and you can’t even introduce new symmetries as they arise. It will not gracefully accept any change, and will actually fight against them. It might well be a beautiful diamond, but as such it won’t change its shape when needed.
The code must accept change gracefully, especially the nasty, irregular changes that come from the real world.
JAXenter: Have you received any feedback after your paper was published? Do people agree with your view?
Carlo Pescio: On Twitter, I would say the feedback was mostly good. People “got” the message, and I suppose many had already come to similar conclusions and welcomed a paper that didn’t shy away from stating them. Then, someone shared a link to the paper on Hacker News and Reddit (I assume in good faith) and yeah, that was a slaughterhouse as expected. To be fair, many comments there are more interesting from the perspective of social sciences than from that of computer science. It’s ok though. I wrote the paper because it was a small truth worth saying, but nobody felt like saying it, so I did. Even if just a handful of people will find it useful, I’ll be happy with it.
Thank you very much!