Low-code and no-code

A fad or a real solution?

Posted by hossg on February 18, 2022 · 14 mins read

This post is wantonly plagiarised from Dave Farley’s excellent video which I highly recommend you watch; this is largely an edited transcript of that video with some minor editorial changes and personal comments/perspectives.

Reproduced with permission from @davefarley77

What is low-code/no-code?

Let’s start at the beginning: what is low code? ( I’m not going to keep saying low code and no code all of the time; I don’t think there’s enough difference to matter in this context so let’s just call them all low-code systems). The idea is to make programming easier and more efficient. This is a valuable goal and it can help people who couldn’t otherwise write or construct their own systems to do so, or to help people to do more things, more quickly.

The principle of making the creation of software systems easier and more widely available is a very good idea, but I just don’t think it’s as easy as it seems. The next thing to say is that there’s nothing new to this idea really. In some ways this describes the evolution of programming in general: what were the first compiled languages if not attempts to make programming easier than dealing with machine code? My bet is that machine language programmers in those days would have called Cobol programmers “low code programmers”, but even if we don’t want to include the evolution of programming languages in our discussion, it’s still not new: a spreadsheet is a low code solution; simply a user programming solution for dealing with tabular data. Tools like Excel are enormously useful, but spreadsheets haven’t replaced Java or Python and they won’t.

Every few years for the last few decades there is a heavily-promoted ‘industry’ promoting low-code solutions (4GL, CASE, low-code, no-code, RPA), and this old idea has failed multiple times in the past – expensively so for those who have tried it, despite a façade of early initial success.

What are the issues with low-code?

There’s certainly a lot of value in simplifying programming and democratizing access to tools for automation where we can, but there’s a blurry line though between what counts as software development and what is user programming or simply configuring an application. Without worrying too much about definitions, let’s consider instead the things that you should be careful of when starting out with low code solutions or in fact any software solutions, code or not, and what would it take to reduce those risks.

It may not seem that low code is an obvious target for software engineering thinking, and in fact the promise of many of these solutions is precisely the opposite – they claim that this thinking is not needed.

This is the origin of the problem with these sorts of tools. Software is complicated stuff, and it’s complicated in lots of ways and not all of them are obvious. Some of these complexities are easy to dodge if we raise the level of abstraction and we can hide all sorts of detail: for example might not need to worry about operating system differences, how stuff is stored or the details of complex things like user registration or even taking payments (say), but there’s another deeper set of problems that you can’t fix by raising the level of abstraction, problems that are fundamental and inherent to dealing with information in information systems, and so far all of the low code systems that I’ve seen ignore these problems altogether and so fall foul of these deeper complexities. There are many different kinds of programming after all, and different tools do make sense or don’t, in different contexts.

The trouble is that it’s not always easy to see when you cross the boundaries, even for experienced developers let alone for non-technical lay people who know nothing about the sneakiness of the complexities at the heart of software. And what is more, when extending or changing an existing system or automation, it can be even harder to see that you’ve crossed a complexity boundary: the original system may be simple, the change may be small, and so one assumes that the new system (=old + change) is also therefore simple. This is frequently a false assumption.

The illusion of simplicity

One problem is that these claims that low code solutions are the answer to everything are compelling at first sight because these tools nearly always look fantastic when they are demonstrated.

I recall some years ago sitting through a lengthy multi-day sales pitch for some big enterprise service bus configuration tool. The idea of this system was that you could integrate your entire enterprise by visually mapping your process and the translations of data between the systems that it represented. It looked pretty good: the demos clearly showed how easy all this was, except of course it was more complicated in reality: what happened if there wasn’t a one-to-one match of information flowing between the steps? We were told that we could create integrations as complex as we liked with their clever tools, but at that point the complexity and expertise involved would of course rise dramatically, undermining the very point of the low-code system in the first place. When asked how changes were tested, not an answer came.

This is the biggest trap of all that no low code system that I’ve ever seen so far has managed to avoid: not just testing, but a completely naive assumption that the problem is perfectly understood before we start work, and that we won’t make any mistakes at all during the course of our implementation. Even if the tools are fantastic, and hide us from the complexity, it’s highly unlikely that we will be perfect: even low code tool users are still human beings after all! None of them support version control, automated testing or even concepts like manual beta testing where you can try out real-world integrations in a non-production setting. If I make a mistake I need to recall what the system was like before I made it and then try to recreate what I remember of the working version looked like, if I want to undo the mistake.

There aren’t too many professional software developers that would make the choice to work like that these days. Imagine writing a programming language that didn’t allow you to store your code in a version control system and didn’t allow you to run it in a test environment before release.

The mistake that all low code solutions commonly make is that they don’t support real world software development they all assume that we have a problem that we perfectly understand that we will be perfectly understand the tools and their use first time and that we will implement everything perfectly they make little or no allowance for mistakes misunderstandings or crucially the activity of learning.

Proprietary lock-in

Most low-code solutions are highly proprietary in terms of implementation, and in fact they support a business model designed to ensure lock-in. It is self-evidently a huge risk to embark on such a path, adopting highly proprietary tools, thus with very limited experience available in the marketplace, for anything other than the most trivial and non-critical of automations.

The enterprise service bus integration system that I described was meant to be the glue that joined together all of the systems in my business together, and it had exactly the same problem, and even worse (common to most low-code products I’ve seen) its programming was stored in a proprietary database so you couldn’t even copy the configuration of your system, your own program, without breaking the terms of the license or without a deep understanding of the internal structure of the low-code platform itself, meaning that you couldn’t test your changes anywhere but in production, nor even ‘keep a copy’ of your code in perpetuity without licensing the product. This is simply dangerous nonsense.

Where can low-code succeed?

Where low code solutions can shine is in limited and constrained problem domains when the problem is narrowed down they can be fantastic. I use several such systems at home – for example IFTTT and related tools/plugins for home automation. Unfortunately every now and again people selling this “programming for all model” forget this. I think that maybe we’re going through one of these periods once again they start to make grandiose claims for their tools that they will replace programmers in programming altogether, and suggest that the skill/talent of programmers is in the writing of code, which is of course sort of nonsense. The skill and talent of programmers is in solving problems for people and in particular elucidating and anticipating the real, actual problems (including unspoken edge cases).

In software development we solve problems for people using software, and a fundamental skill in being able to do that is to learn enough about the problem to think of some solutions that may work and then to experiment with these ideas to see if they do in fact work. For that we need the tools, understanding and experience of software development: we need log files and error handling, version control and the ability to write tests; we need the ability to test ideas before they exist in production and we need the tools that allow us to make progress incrementally, giving us the ability to step back from mistakes and correct them without relying on our imperfect ability to hold the whole system in our heads all of the time.

We need tools to manage the complexity of the systems that we build. Low code products tend to ignore these problems completely and until it does address them then they only make sense for extremely simple common cases. The problem for professional software developers like us is that it’s not obvious even to us, let alone to non-technical people, where the boundary lies for what counts as simple.

Is 10 integrations of five pages of stuff simple? Well maybe (but even if it is, maintaining and updating those integrations may not be!) Is integrating a fleet of enterprise systems or large data sets simple? Certainly not. This is clearly beyond the competence or should be of these sorts of tools. There is a lot of grey area between these two extremes.

How we organize our work is important to doing a good job. Over decades of evolving tools and practices to support us software developers have learned some things that matter. The huge risky mistake that I see low code solutions make is not building these fundamentals and their learnings into the approach. The trouble is that if they do this, then they start to look more complex: a bit more like regular programming, and so aren’t quite as easy to sell! There’s no incentive to the suppliers to develop this sort of capability. The big danger as I see it is that many of the people that buy these things don’t know enough to realize just how thin the ice that they are skating over really is. It’s possible that certain classes of programming may be done more easily with low code tools but no one will ever write a new operating system, trading systems or a flight control system this way, and no one will write an innovative new type of website in that way either. Low code works best for problems that are already well understood and so easy to understand to be able to constrain them with automation.