Breaking the linear flow

I sometimes see software design as a battle between various tendencies. This is probably affected by my view of myself as a battle between various tendencies, so take that with a grain of salt.

But anyway, S.D. ends up being affected by trends and fashions, which come and go. Sometimes we (a global “we”) tend towards OO or towards microservices or whatever design becomes popular and gains traction at the time. In my case, I don't really know why, but I tend to become more interested in some other aspects, maybe more fundamental or subtle. Maybe they are just more irrelevant or stupid. I never claimed it was interesting in general; I happen to find it interesting.

This one is a subject that I've seen commented a number of times lately. The “linear flow of the code”. Particularly in the context of breaking or not breaking the “linear flow of the code”.

The flow of JavaScript

The JavaScript community is, from a certain point of view, fascinating. Maybe like a herd of cats. Ignoring a lot of things while rebuilding those same things at the same time. In a much more chaotic way, which is what produces the fascination.

Lately, a bunch of those things are closely related to the flow of the code. Callbacks, Promises, Generators, async/await (which is just promises+generators)… A lot of people don't generally realize even though they sometimes get quite close when they argue these “make our code look synchronous”. But what they actually mean is that it makes the the flow of the code look sequential. It's a subtle but important detail. I'd even argue that it's important that it's subtle, because that way it gets overlooked and confused and leads me into writing all this boring and pointless wall of text.

To illustrate, one can read one of the various articles that explain the whole progression. That one is, at least, clean and clear. Others mostly repeat the idea only with more roundabouts. But, again, what all fail to mention is that the final result is making your code look sequential.

Sequentialism

I'm calling sequentialism what is actually a tendency towards imperative programming. Yes, that ugly word nobody would like to be associated with. But it's the truth; you can't deny it. It is precisely this all those things are trying to achieve. Sequential blocks of code; imperative programming.

The thing is, let's be honest, sequentialism is apparently easy to follow.

Some time ago, other trends appeared that went straight for the jugular of sequential code. Event driven programming, in particular represented well by languages/platforms like Delphi, tried to make the most of this. It was very well suited to the approach of visually defining interfaces and then weaving code into the events of said interface. But the quality of the code produced with such systems greatly varied from one programmer to another. One could find generally both sides of the spectrum: Clean, terse, well-organized code on one side, and a bunch of huge messy blocks (usually just there in the event handlers) on the other.

JavaScript, a while back, also tried to promote this event-driven idea. But, as with other ideas, it didn't enforce or even recommend it as a general paradigm. There's probably a history there of introducing ideas without really much effort to promote them.

Anyway, the problem was that. For some people the approach of a completely asynchronous event driven system was actually easy to manage and organize. I'd say some people feel comfortable with that way of reasoning. They manage to isolate smaller pieces and disconnect from the sequentialism. But some other people actually find it much harder. For them, disconnecting and separating each action and event becomes harder to reason about.

OOP and FP

Lately there's also a fair amount of discussion on “OOP vs FP”, but this doesn't actually matter here. People who could in theory be considered proponents of either camp, still fall into these sequentialist tendencies. In this particular regard, each with its own tools, both OOP and FP actually promote, if not directly avoiding sequentialism, at least breaking the flow of code. Simply by breaking it into smaller pieces.

This is not always appreciated in -now seen as not cool and trendy any more- OO code. People generally observe other aspects of OO code, not so much this particular characteristic. It is appreciated more in FP, where aspects such as being declarative or using composition, do seem to promote a more decentralized “flow”. I'm generous to OO in this respect and, without making preferences, I argue that both approaches promote to some extent breaking the linear flow.

I try not to, but I'm inclined to think that a lot of people defend OO and/or FP just a sort of name-dropping, because once you see their code you'll find these medium-to-quite-large blocks of clearly sequential code in worrying amounts.

Linear reasoning

A typical exchange on asynchronicity that I've seen a number of times on reddit illustrates the problem well. A person proposes some code similar to this:

function seriouslySynchronous() {
    var x;
    var p =  new Promise(function (resolve, reject) {
        // do some asynchronous stuff that ends up producing:
        resolve(theGoldenValue);
    };
    p.then(function (response) {
        x = response;
    });
    return x;
}

Their intention is naïve but clear. They have some process that is asynchronous. This may be some library function, an XHR, a call to WebSQL or whatever; the process is asynchronous and they cannot do a thing about that. So they wrap this call in a Promise and then (try to) wait for it to resolve to simply return that value. The goal is, of course, that if this actually worked they would have magically transformed an asynchronous process into a synchronous one without any effort at all. Simple, isn't it?

A variation some people try is just setting a global variable from the callback and setting a time interval to check for it until it is available… Or even “a while loop which is freezing my browser”. Gasp!

But of course it doesn't work. x is returned undefined and theGoldenValue is simply discarded and lost.

And so -with some luck- they get a kind and helpful explanation about how “asynchronicity is infectious” and how once you make an asynchronous call, your seriouslySynchronous function must become asynchronous too. And such is life but all is well. But then, the person insists:

But I want to use the output of the async function and return it from my function.
So seriouslySynchronous should be able to return x to me with the value of theGoldenValue, which is the value returned from the callback of the async function.

They get lucky a second time and they receive an answer that explains that what they can do is just return the Promise itself from seriouslySynchronous which won't be synchronous anymore, but such is the nature of things and life itself. Such is the nature of things, yes, but insisting again:

I was expecting to find a way to return the value of the promise once it is available.

And a new helpful soul finally offers:

Look into yield / async.

I didn't reproduce this typical exchange here to make fun of anyone. The goal is to illustrate both the struggle to fully and deeply understand the asynchronous nature of this situation and the relentless insistence in bringing it into order, of just hiding all that confusing stuff and simply getting me my value.

My hypothesis on this is that both the struggle and the insistence derive from having learned and embraced a certain way of reasoning.

Telling stories

As I conceded previously, it might well be that that way of reasoning is easier for many people. In a way I understand it. It does make some parts of the reasoning process easier. We, in our life, are much more accustomed to linear flows. Books, movies, tales, or plain conversations we have with other people, tend most of the times to be presented in a sequence. Sure, there may be flashbacks or other narrative artifacts, but those are mostly fancy artistic tools.

What is revealing is focusing on more common conversations and thinking how we tell stories to each other in a natural fashion. Most people maintain a clear linear narrative sequence. Some do this marvelous thing of pulling threads were they keep drifting through -more or less- related stories which sort of evolve into different subjects every so often. Still, their flow can be seen mostly as linear. The difference is that their sequence doesn't follow time and instead follows some relation logic. But I'd argue it's still mostly linear because they rarely travel back unless the diversion is really minimal.

Surely there exists non-linear narrative in literature and films. But if you look up the examples people will propose as non-linear, most of them turn out to be “mostly linear but messed up through some simple device”. That can be anything from using flashbacks to telling the whole thing in (mostly) reverse order. Others form trees of stories and jump from one to another as they collectively progress towards one another. It gives an appearance of breaking the linearity but each of the concurrent sub-stories still remains heavily linear.

I do remember some notable efforts. Primer comes to mind, where the story itself is so contrivedly non-linear (for obvious reasons i.e. time travel) that it sort of ends up validating the idea that most people cannot follow a non-linear story.

Imperative sequentialism

Linear reasoning is indeed easier for some people. It has some drawbacks, though. It forces short-time and long-time memory when the story is long or involves many items. But there may be, in the end, no conclusion to this rumination, other than the simple observation and acknowledgement of the battles, fashions, and waves that move software development trends.

I do, however, think that all this sequentialism is hardcore imperative, and to me it appears like a step backwards. I do acknowledge that it may well be that my own tendency and long-time habituation towards chaotic systems, event-driven designs and fragmented timelines, is not the most common and that keeping a wholistic perspective on such systems may not be an easy task for everyone.

But I feel it like a step backwards because I think event-driven design techniques promote some good fundamental qualities on the code, such as low cohesion and resilience. Maybe part of the problem is a fundamental lack in layered reasoning or in teaching people how to abstract details when reasoning from different perspectives. Or maybe it's just me and I'm the weird one or something.