Development of Linear Systems
— functional programming — 2 min read
I was reading this fascinating article on Aeon the other day, and was particularly struck by this section:
...the firing range is nearly a linear system, whose overall behaviour is determined by the interaction of its constituent bits, in a one-way fashion. But you can’t pinpoint the precise position of an electron when it’s circling an atom, or say for sure if and when a hurricane will hit New York next year. That’s because the weather and atoms – like all natural processes – are not reliably determined by their initial conditions, but by the system’s own behaviour as it feeds back into the interactions of its component parts. In other words, they are complex systems.
In thinking about programming paradigms and the best way to write and structure our code, I think this idea of complex systems is something all developers should consider.
For many of us, our codebases may very well look like complex systems. You have many different parts (at varying levels of abstraction) interacting with each other, with explicit and implicit relationships interwoven amongst the constituent parts. It's difficult to pin-point what the data looks like and how it's being transformed at any given point in this sort of system.
And this ambiguity causes friction in the development process for the programmer. Each moment one runs into a bit of tangled code, there is excess mental energy being spent as one is required to trace it step-by-step.
But in contrast, I think the principles of functional programming encourage developers to create linear systems instead. Linear systems are simpler than complex ones, with processes that are more predictable and more easily traced.
When you strive to create pure functions that are guaranteed to map any given inputs with their outputs (without any side effects), you are making your program more predictable. When you compose many of these functions together to create new ones, you are creating one-way linear flows of data that can be relied on.
This isn't to say that you must write functional code to reap the benefits of this way of thinking. Consider TypeScript, C#, or other strongly-typed languages: people love these languages because they make it easier to trace the flow and transformation of data.
In C#, the code itself is almost self-documenting. You can easily drill down into class definitions to get a better idea of how a given object is structured or explore how the object's data can be mutated. Even if its methods may not be considered 'pure', C#'s method signatures do a lot to make it clear and predictable what any given method is doing.
But in spite of how helpful our languages and tools can be towards creating linear systems, I think the burden largely falls on the developer to carefully consider how their programs are designed. In the end, software is another interface between people and computers - all the more reason to make our code easier to reason with.