[Blog] How Low-Code Platforms Changed the Course of Traditional Software Development

Low-code platforms have been a trending topic in the last few years. We even built our own internal low-code platform at PayFit!

While the underlying philosophy, giving access to a wider range of programmers to application creation tools, is not new, they are more and more present.

This article explores the specificities of this rising trend and puts it in perspective with existing approaches.

📚 A little bit of history

👉 From assembly to 4th generation languages

“History of software engineering is a rise in the levels of abstraction.” Grady Booch, ICSE 2015 (source)

Writing computer programs is complex. In 1987, Fred Brooks introduced the distinction between essential and accidental complexity as follow:

  • Essential complexity is inherent to the problem one is trying to solve. If our problem is complex, because for instance, we need to compute payroll for all employees of a company, there will be essential complexity in our program.
  • Arbitrary or accidental complexity, on the other hand, is complexity introduced by the programmers themselves.

From assembly to the current last generation of programming languages, the increase in levels of abstractions has served one need: to decrease the accidental complexity of programs by handling this complexity for the programmers.

Assembly brought a human-readable version of the programs fed to the computer by introducing instructions such as MOVE, ADD, COPY, etc. in place of zeros and ones.

In the meantime, Domain-Specific Languages (DSL) were created to abstract away all the intricacies of computer software development and focus on the domain at hand.

More business-oriented DSLs exist as well and enable less tech-savvy programmers to enjoy writing programs. JetLang, our in-house language, is an example of that: our Product Builders use the JetLang Expression Language to describe the computations involved in their country payroll logic.

💪 With great languages, come great tools!

In parallel with the evolution of languages, tools to input these programs were also developed.

Back in the day of the first digital computers, programming was a matter of flicking some (well, a lot of) switches or punching holes in paper cards which were then fed to the machine.

Of course, since then, things have evolved: software programmers have had a wide variety of simple text editors to full Integrated Development Environments (IDEs) to choose from. Emacs, Vim, Eclipse, Visual Studio… You name it.

Most of those tools, however, leave a great deal of autonomy to their users: developers. Developers need to bring their own configuration and toolchain to complete their setup. Depending on the language and its ecosystem, they may need to choose which package manager they want to use, which compiler is best suited to their needs, or how their code will be shipped to production. Dealing with all of this adds some kind of accidental complexity and may get in the way of the developers’ flow, defocusing them from their added value, tackling the essential complexity of their domain.

In some cases, those choices are important to make, and may impact performance or scalability. But most of the time, building a new application follows the same patterns, patterns that can be generalised and automated. Automation, like the rise in levels of abstraction, is part of the history of software engineering.

Initiated in the eighties, the Computer-aided software engineering (CASE) family of tools brought support and automation for the different tasks of a software lifecycle: analysis & definition, design, construction, validation, configuration…

Fast-forward two decades, the new century marked the appearance of the Model-Driven Engineering (MDE) approach. MDE is at the crossroads of the rise in levels of abstraction and the need for more automation and genericity: it is about understanding a domain, creating a domain-specific language which abstracts the concepts of this domain, and using this language to increase programmers’ productivity and reusability of the different system parts.

An example can be found in the Infrastructure-as-Code (IaC) approach, where an abstract description of infrastructure artifacts (VMs, databases…) is transformed into instructions for automatic deployment.

Writing cloud configurations with the Infrastructure-as-Code approach to ease multi-cloud deployment (illustration adapted from Terraform website)

Writing cloud configurations with the Infrastructure-as-Code approach to ease multi-cloud deployment (illustration adapted from Terraform website)

Despite the rise in level of abstraction, most of these approaches were not really aimed at business users. A few companies built their own internal DSL to increase business productivity.

But until recently, to be able to create a new application, you still needed to know how to code or at least have a strong technical background to understand the impacts of your choices on a CASE tool.

The advent of the cloud era changed everything. The power of the cloud removed the friction of installing a tool on your desktop (now available in anyone’s browser) and deploying quickly an application. This was true for software editors, and enabled the deployment of CASE tools in our browsers.

Inheriting decades of software engineering, low-code platforms represent this new generation of tooling, bringing together the abstraction levels of MDE and all the facilities enabled by the Cloud.


⚙️ Low-code platforms: business application development made easy

Definition
Low-code development platforms (LCDP) are SaaS (Software as a Service) platforms enabling creation of business applications, for internal or external use, with a limited need (or sometimes even no need) for custom code.

This definition of low-code platforms lies on three key ideas:

1️⃣ an iterative & fast development & deployment process in the cloud,
2️⃣ a focus on creating applications for the business, by the business, and
3️⃣ a limited (or sometimes even non-existent) need for code.

1️⃣ The cloud, an enabler for rapid application development platforms

As mentioned earlier, the first trigger of the LCDP revolution is the advent of the cloud. Indeed, the rapid growth of cloud providers enabled easy, iterative & fast deployments of our web applications.

Handling the application lifecycle used to be a pain for many IT teams. It usually involved:

  • setting up different environments (development, staging / testing, production), with the right configurations for the infrastructure to cope with the load and potential failures,
  • copying zip files from servers to servers and applying database scripts when a deployment was needed,
  • managing manually access control lists, etc.

Those tasks are now all automated, with auto-scaling, access control or deployment executed by applying the right configurations, making it easy to quickly iterate on an application creation process.

Automating & abstracting those tech-heavy tasks lowered the barrier to entry for application development, letting new profiles taste the power of app design.

2️⃣ Opening-up application development to a new fringe of the population

Low-code platforms are targeting a specific population: often referred to as “citizen developers”, and who we prefer to call Product Builders, their main task is building a product for the business.

This population doesn’t need to be as technical-savvy as users of rapid applications development platforms or CASE tools needed to be.

With proper training and given a correct User Experience, low-code platforms open the creation of business applications to a whole new category of builders.

The targeted application needs are very wide. The typical enterprise internal usage is replacing a scary spreadsheet, containing macros and shared across departments, with a brand new and secured web application. In that kind of scenario, the low-code platform is usually sponsored by the IT department and provided to the company business units in a controlled environment.

The types of applications built for external use will vary depending on the platform. From mobile to web applications, focusing on the end-user user experience or performance in handling data, each platform has its own capabilities.

3️⃣ Combining pre-defined building blocks for increased productivity

Building applications with a low-code platform should be simpler than setting-up a development environment, coding and managing our application deployment at each iteration.

That’s why those platforms rely on pre-defined building blocks that just need to be configured for the target purpose.

The main components usually handled by such platforms are data modeling, User Interface design and the business logic definition.

The main building blocks of most low-code platforms on the market

The main building blocks of most low-code platforms on the market

Data modeling

Through the data modeling brick, platform users will define the concepts manipulated within their target application and the relations between those concepts. For instance, one may want to build an HR tool to handle employee leaves. To do so, they will add the concepts of Collaborator, Company, Contract, Leave, etc.

User Interfaces

With the User Interface design component, product builders describe the interfaces to be displayed in their application. For their leave management app, they may want to define forms with input fields to collect the end-user data (e.g. a form to request a leave), some lists to view the existing requests, or any advanced UI widget proposed by the platform (e.g. dashboards…).

Business logic

To orchestrate the business logic of their application, product builders will usually have access to several possibilities.

  • With Business Rules, they will be able to define the custom rules mastering the visibility of UI components, the calculation of some entity fields in the data model, or maybe the validity of data inputs.
  • With Workflows, they will be able to define more asynchronous business logic, i.e. long-lasting processes such as the validation of an absence request.

Most low-code platforms are quite similar in the data modeling and the user interface components. They will differentiate themselves from other platforms through the versatility of their business logic components and additional configurable features: some will provide basic logic definitions, with a simple expression language compound to arithmetic operations and string concatenation while others will provide many functions to operate on the data (aggregates, filters…).

On the feature side, the best platforms will provide a security module where one can configure the access rules for each data model and user interfaces. Others will automatically generate documented API to interact with the data programmatically, enabling direct integration of the generated application into another ecosystem.

🤔 What about “code”?

At this stage of the description of the low-code platform, we actually haven’t mentioned the “low-code” part yet: indeed, while low-code platforms rely on the configuration of predefined building blocks, not everything can be configured and built like this. Code is needed at least somewhere – mostly for non-generic situations.

Most vendors in the current generation of low-code platforms go for a generic approach. The trade-off is that product builders will reach a limit where they won’t be able to express a specific need, being a very complex business rule or a very detailed UI widget.

That’s when the “low” in “low-code” kicks in: the particularity of these platforms, as opposed with the no-code platforms, is that they are extensible with actual code.

In blue, different extensions to the generic models with custom code (hardcoded entities, advanced UI widgets, code extension…)

In blue, different extensions to the generic models with custom code (hardcoded entities, advanced UI widgets, code extension…)

Of course, we won’t be expecting from product builders to implement this code. This is the role of developers. Their added value, in the context of a low-code platform, is in implementing manually the custom complex specificities of each use case.

Some platforms market themselves as no-code platforms. They usually have the same genericity approach with the same building blocks available. The only difference with low-code platforms is that their code is not directly extensible on a per-project basis. However, they usually (for the most advanced ones) provide extensions features through plugin systems or allow API connections to other systems which can handle the complexity.

This is the limit of no-code platforms: in order to cover the full complexity of a business application, one may need to put part of the business logic in another system, thus spreading the domain knowledge and its implementation across different systems.

🏡 A few words on PayFit’s in-house LCDP: JetLang

Unlike most low-code development platforms we described in this article, PayFit’s approach when building our internal JetLang Platform was not to provide our Product Builders with a generic application building tool.

Actually, we didn’t even know we were building a low-code platform until this trend took off a couple of years ago 😅.

JetLang was initially built as an internal Domain-Specific Language to let Product Builders (then called JetLang Masters) define the payroll logic themselves, without having to rely on software engineers to input local business rules. With that approach, Product Builders in France (the country we started from) were able to focus on their expertise: the French labour law, while developers were focusing on the technical aspects of the application. Having this approach also allowed us to quickly deploy our application in new countries (as of today, Spain, Germany, the UK and Italy) by reusing the same global product, adapted to the local business logic and labor law by local Product Builders.

This language evolved over the years to reach today’s JetLang platform, covering the various needs of our Product Builders to build in autonomy an application fit to local needs & rules.

So, we built a low-code platform without really thinking about it: our aim has always been (and still is) to empower our Product Builders to build the best product. And, as the history shows, it goes with offering them with the standard building blocks of a low-code platform: data modeling, user interface design and business logic definition.

An example of one of JetLang feature: the Legal Studio editor, where our payroll experts can configure computation based on local work laws)

An example of one of JetLang feature: the Legal Studio editor, where our payroll experts can configure computation based on local work laws)

There are a few differences with the generic approach taken by off-the-shelf low-code platforms though: in order to build the payroll application, PayFit’s main asset built with the JetLang Platform, Product Builders will rely on pre-defined payroll-specific first-class concepts.

For instance, the data model is linked to our core entities (e.g. Employee, Company…) that can be extended locally. Also, the language used to express the business logic contains some keywords specific to the payroll domain, with output locally adapted (e.g. to compute the number of working days between two dates). And of course we adapted our interface designer to use PayFit’s Design System, Midnight, and our pre-defined UI component.

If we were to compare ourselves to generic LCDP, JetLang Platform can be seen as a pre-configured low-code platform for PayFit business domains.

🔮 What’s next for low-code platforms?

The approach we took when building our platform overcomes two of the criticisms often heard about no-code/low-code platforms: scalability limits and flexibility on expressing the business logic.

Indeed, by having a very generic approach, low-code platform editors don’t know in advance their users’ use cases and need to make generic assumptions about the way their applications will be used. While genericity is probably good for 80% of the use cases, simple data-driven applications, the 20% left will endure performance degradation because the platform is not adapted to their use case.

With JetLang, we built a platform to fit our needs and our context. As the PayFit architecture evolves, we can adapt the platform to make sure it stays aligned with our scalability needs and the evolution of the product.

The other limit often mentioned in low-code development platforms is the barrier reached by citizen developers when it comes to defining business logic: for generic LCDP, there is often a time when the business logic becomes too complex and cannot be implemented within the platform boundaries and need the intervention of a developper. Again, this limit is linked to the fact that most low-code platforms take the genericity stand and cannot provide subject matter experts with a dedicated tool fit to configure their own app. At PayFit, we overcame this limit by introducing some of our domain specificities (Human Resources concepts, payroll-specific keywords…) in our platform, and providing a very powerful expression language to our experts, Product Builders, to make them more autonomous when building the product.

There is no doubt that low-code development platforms will become a standard in the next decade. If we were to take a bet on their future, we would probably say that it lies in providing a standard experience common to all platforms, extended with more specific, business-centered additions, enabling subject matter experts to express their business logic with more autonomy, while postponing the need for custom code.