Thursday, October 29, 2020

Low-Code, No-Code, and why "Source Code" is a terrible place to put software

What if there were an entire layer of code simply missing from most "traditional" development projects?  What if software developers could be spending their time focusing on just a small, interesting, innovative fraction of today’s “source code,” while having the other 70-90% automatically derived directly from the Specification on their behalf, regardless of which languages or tech stack is involved?

What if the very term itself "Source Code" was in fact a deeply flawed mangling of two completely different things?   

Step 1 - Admitting that we have a problem!

As an industry, the problem starts with the very term "Source Code".  The name incorrectly implies that "Source Code" is actually the "source" for a given project ... but rarely is that actually true - which is why it belongs in quotes. 

The real source is, or rather should always be the "Specification," as determined by the ongoing, ever-changing specific needs of the business in question - i.e. the constraints, rules, inputs, user stories, features, wants, needs, etc - which are all subject to change at any point and frequently do.  Perhaps the only constant is "change" itself, right?

The problem with the traditional approach to development though, is that every time the rules change, the "source code" is immediately stale, and will tend to get more and more out of date over time, because most of the code does not automatically update itself in response to even completely predictable changes in the requirements. 

Instead, the project stakeholders typically have to wait for the python developer to get into their part of the project to update their "source code".  And for the Android team to update the java "source code".  And for the DB team to update their "source code". 

But you can't really have 3 "sources", can you?  That's just not what the word "source" means - right?

Instead, there should always be just 1 (one) source. 

A Single Source of Truth

An SSoT for an entire system/platform is one which authoritatively, in a machine readable, easily queryable format that is not code, defines as much of the final solution as possible.  i.e. A No-Code "Model"

But importantly, that's not where the story ends.

I'm a developer.  If No-code actually worked today, I'd be out of a job.  Luckily for me though - I think we're probably still at least 5-10+ years away from that reality.  In the meantime however, I still want to write code.  I still want my team of developers to be able to write code. 

But I want them to write as little code as possible in order to accomplish their objectives.  I.e. I want Low-code.  Specifically, even 5 years from now, I will want the human team members to write about 20% of the code, and for the remaining 80% to be derived from specification data (SSoT) - in whatever language/tech-stack we are working in at that point.

Redefining "Source Code"

To understand how this really can actually be possible, we need to start unfortunately, by completely redefining the term "Source Code" itself.  Specifically, we need to pull it apart into the two completely separate things it actually is. 

Source Code = Derivative Code + Hand Code

Once we've done this - it allows us to consider a slight variation from the traditional development stack:

"Traditional" Development Stack

  • Framework (node, angular, react, .net, django, etc)
  • Static Libraries (shared code, npm, internal tools, etc)
  • "Source Code" (mostly written by hand)

With a Single Source of Truth or SSoT as a machine readable specification document, we can add a whole extra layer before the human developers get involved, which can usually encode the vast majority of the business rules/logic for a given system. So essentially, by always starting with language specific, mostly derived SDKs, we can have this stack.

Development based on a Single Source of Truth

  • Framework (node, angular, react, .net, django, etc)
  • Static Libraries (shared code, npm, internal tools, etc)
  • "Source Code" =
    • Derivative Code     ~80%    (60-90%?)
      SDKs - mostly derived from the Single Source of Truth, in many cases able to encode the vast majority of the business rules/logic for the underlying system, and having little or no “hand code”.
    • Hand Code             ~20%
      i.e. the actual Source Code

The result is a completely different development environment where right from the start, human developers always get to focus on the creative, interesting bits of the project - the last 20%, rather than the other 80% which is usually rote, derivative, patternistic, completely predictable code - i.e. the platform, plumbing, scaffolding, etc. - all the "connective tissue" - regardless of language, environment or technical context.

With this model, the bottom 70-90% of the code that is typically written and maintained "by hand" in a traditional environment is instead derived - so when changes occur (as they reliably always do) as much as 8 out of every 10 lines of code can automatically update itself.  It can simply "following along".  And only the last 15-20% of the code written by hand, may still have to be updated by “real” developers. 

This results in a dramatically more dynamic, flexible, responsive code base, top-to-bottom on which to build; resilient to even substantial changes in direction, or even the more extreme pivots that projects so frequently have to address.  And it's all possible because we're talking about working with as much as 70-90% less "tech-debt" - on an ongoing basis, even years into a large scale project's life-cycle.

No-Code vs. Low-code

At the end of the day, I largely agree with Linus Lee about No-Code specifically.  For the foreseeable future, it will continue to be limited in its ability to fully address the needs of large, long lived, enterprise level systems.  So I'm pretty sure that we'll continue to need "real" developers for at least the next decade.

But in my Open Response to Linus Lee, I argue that No-Code tools are actually already really well suited to providing highly detailed, very scalable, machine readable specification data - which can then be leveraged as the source input for Low-code tools, to supply the vast majority of production ready source code for a given system.  These Tools make the Single Source of Truth...

  • Language Agnostic.
  • Platform Agnostic.  
  • Context Agnostic.  
  • Future Proof.

In this way - even when a new, never before seen language "Wombatz" comes out tomorrow (or next year), a single tool will allow us to immediately, seamlessly integrate that language into any of our projects in development for which we have a well defined Single Source of Truth

With an SSoT in hand, the newfangled Wombatz code will literally "catch up" to the rest of the languages already in the project - on day 1 - and this can all happen before you've even hired the new human Wombatz developer.

So while I would agree that No-Code tools are still definitely not yet viable on their own as a complete/final solution, they can definitely be used already today to very quickly/flexibly/predictable define the rules for even very complex and sophisticated systems - in a machine readable format - json, xml, swagger, dbml, uml, pfds, etc.  Those rules can then be used to generate production ready code, which simply "follows along" as the rules change over time. 

That process looks like this, even years into a large scale project:

  1. Changes are requested by end users (business users)

  2. The No-Code Model is updated to match the changes requested

  3. All of the SDK's derived from the No-Code model, across the entire project stack are regenerated - including APIs, UI, Back-End, Front-End, Databases, Documentation, Unit Tests, Python, Swift, Java, TypeScript, Sql, etc - which will always all tend to match each other - as a set ... because they are all derived from a common description - an SSoT, and they are are not each treated as separate silos of "Source Code".

  4. So by the time the human developers get into the source code (in virtually any technical context), 80% or more of the work is potentially already done, and they can immediately begin to focus on the important/creative/non-intuitive bits - like what the UX should be for the new feature, service, behavior, rule, etc.

Tuesday, October 27, 2020

An Open Response to Linus Lee's thoughts

 Re: When is No-Code useful?

and Conservation of Complexity

Hi Linus,

I very much enjoyed reading your articles on Conservation of Complexity and When No-Code is useful - and I agree completely with many of the specific conclusions and observations that you make. But... I’m glad it’s still in the “notes” section of your site, as I'd love a chance to convince you that when it comes to no-code, you might be missing the forest for the trees.


I haven’t seen any no-code company or product that allows source control (and I’ve seen many no-code companies, but you’re welcome to prove me wrong.)  

I would love the opportunity to try -  - and in this post I will present what my development team and I do, with the objective of hopefully finding a new perspective in response to your challenge.  

Related Article

This response uses language and a number of terms related to the general notion of Derivative Code - and more specifically, Why "Source Code" is a terrible place to put software.   If these ideas are not familiar to you, it might be helpful to look at that article first.  

So - with those ideas as background, I will also try to provide some alternative perspectives to a few of the specific points in your article about when no-code might be useful.:

1. Transitionary, ephemeral software
  

We agree that for things like brainstorming, prototyping, developing UX, etc - no-code is often great - but that the these solutions also typically include problems such as:

1) You typically can't manage it through common/essential tools like source control, ci, defect management, etc. 

2) It's often not sufficiently scalable.

3) It's usually a black box (internally), for which you typically only have selective knobs/levers to adjust.

4) You're "stuck" as soon as the no-code product doesn't do exactly what is needed. 

These are all true of most No-Code providers - but not so much for Low-code tools. Even if you use No-code tools just to simply sketch out/brainstorm an idea first, depending a little bit on precisely which tool(s) you're using, this work will almost inevitably at this point create a really well defined, machine readable description of those rules - i.e. a Single Source of Truth or SSoT - and Low-code tools can then turn those "specification" documents into production ready code (derivative code) in the language/tech stack of your choice.

With an SSoT providing a common foundation - we can now pick out the production stack, and specific tools that we want to use.

LAMP,  JAM, MEAN, WIMP, Native Java/Swift/Typescript, Windows, Web, Mac, iOS, Android, etc.  

Importantly though, these decisions can all come after the No-Code model has been already defined.  Possibly even years after it's been defined - and after 100's or even 1000's of changes have been made to it over that time.  All this is possible because the decisions are not "buried" in hand written "source code", possibly in some long forgotten language like Fortran or Cobol.

After close to 2 decades of research in this area, what I have found in practice is that most of the requirements of virtually any technology can be well defined in a database, even without knowing and ultimately completely decoupled from the specific languages or technical contexts that you're going to need in the production environment..

So we can apply Low-code tools to No-Code models - such that developers can actually start on day 1 with much/most of the code needed for the scaffolding/framework for the project already present, regardless of the tech stack involved.  As a result, literally right out of the gates, the developers can begin addressing the needs of the end users, on the actual, final production versions of the code, most of which is just as flexible/responsive as the no-code model used to describe the rules in the first place.

2. High-churn code  

Here again, if the code is a high-churn environment, I think that we both agree that No-Code might be a good option. And if the goal of No-Code is to be the final or finished solution, then I completely agree with this assessment..  

But change resiliency over time is not the focus of no-code tools 

By contrast however, Low-code tools are actually super resilient to change, and I'd even go so far as to say that they actually future proof your code in a way that is virtually impossible to replicate in a "traditional" development environment. 

Because by putting most/all of the decisions about the solution needed into a No-Code model first (rather than hand written code in a specific language)- these decisions can be abstractly leveraged even years in the future, possibly against completely unknown languages today with different operating environments, technical contexts, etc - all because the decisions were not baked into hand coded "python" or "java", as the very 1st step - back in the day.  

3. Avoiding the same mistakes  

 

After all, the world is complex. And when we build software against the complexity of the world, that complexity needs to go somewhere. Software is complex, but only as much as the world it attempts to make sense of.  

This is precisely the Crux of it imho.  The world is complex.  And that complexity needs to go somewhere. And most of it simply should not end up in "Source code" as it's first destination.  That's basically helpful to an audience of 2.  The compiler for the language in question and developers of that specific language.  This is a really expensive & brittle place to record those decisions, with a narrow audience of people who can definitively answer the question: What does this "system" actually do?

Instead, that complexity should be captured in a specification database (i.e. a No-Code model) which can be abstractly queried and reported against now, and in the future.  The human readable, English "specification" then simply becomes a report against that database.  And any time we update the specification database, we simply re-run that report - making it the first target to "follow along" as changes occur. 

Then, when we re-run, say, the "python report” - it updates the foundational python libraries and code to also reflect the new rules/changes.  With most of the "plumbing" largely maintaining itself over time, the code that we do still have to write by hand ends up being extraordinarily efficient, because we're not constantly re-inventing the wheel and calling that "source code".

Does the distinction I'm trying to draw make any sense?

The grain of abstractions

but we as a technical industry have learned how to build and evolve software systems against changing requirements and constraints that span years and decades.

We agree that changes are inevitable, but - however good our "source code" is, it still inevitably mixes multiple things and treats them as one.  Specifically, traditional "source code" mixes the description of WHAT needs to happen into the same place as the description of HOW to do the work in question in a very specific language, context or environment.

Instead, systems can be dramatically more resilient to change, if the definition for WHAT needs to happen is consciously isolated and defined separated from the description of HOW to actually do that in a particular language.  The types of information which fit comfortably in the "specification database" that I've mentioned are rules that encode what needs to happen.  Then tools can convert those details about what needs to happen into a specific language with as much specificity as is available between the Single Source of Truth and the tool which provides the final output code.