Low-code solutions have limitations that custom applications do not. The most important limitations are performance, flexibility, and user experience. Secondary—but still important—considerations are third-party services integration, vendor lock-in, and product discontinuation. That said, low-code solutions do solve real problems, particularly those less affected by the traits just listed. You can visit the website of any low-code solution to hear its praises, so I will focus on the distinction between low-code and custom applications, pointing out where custom applications may be the best avenue for solving a problem.
Low-code solutions often have limitations on performance. Even solutions designed to capture and report upon data often have low limits on the amount of they are capable of performantly displaying. A low-code solution might bog down trying to render 2,000 results. As a result, low-code solutions may limit the amount of data we can display in ways custom applications do not. They may also limit how often we can update the data and therefore lack real-time and push capabilities.
As the amount of data we capture explodes, search has become a vital feature of many applications. Algorithms to create and maintain search indices, filter data, and match and score search results save users time every time they use an application. Since time is knowledge workers' most valuable asset, these seconds saved add up to material cost savings. This especially true for heavily used or data-intensive applications. While a low-code solution may offer basic search, many such solutions lack the ability to customize searchable properties, indices, or the search algorithm itself.
When the performance of a custom application slows down, we can make adjustments to the code. Maybe we use a more efficient algorithm or restructure a query. We could use an in-memory cache for data that is regularly accessed but less frequently changed. We can set up edge computing nodes to get data and computing power closer to our end users, thereby reducing latency. Low-code solutions generally have one way of doing things, resulting in one level of performance that cannot be tuned.
Creating an application with low-code tools versus building a custom application is the difference between traveling by rail and traveling by air. Traveling by rail, we travel over a predefined route. The route may not go directly between our starting point and our destination. Modifying or extending that route is a slow process. Traveling by air, we go directly from Point A to Point B. If we need to make adjustments in flight, we do so immediately.
Limitations on flexibility reduce opportunities for automation. Continuous integration and deployment (CI/CD) to a variety of environments (e.g., development, testing, staging, and production) is common practice for custom applications. Many low-code solutions have only two environments: development and production. Whereas CI/CD solutions automatically run our test suites to immediately identify bugs, deployment of low-code solutions is often a manual process with no test automation. Do you want rolling upgrades so users do not experience downtime? Do you need affordable backup solutions to ensure you do not lose data to hardware failures or ransomware? What about logging to track errors and usage? How about A/B testing to see if a particular feature enhances sales or engagement? Low-code solutions have limited support for these scenarios.
Now examine the code itself. Say we have a server entity in our application. This server appears on a server list page, on a server properties page, on a search page, and on the properties page of the hardware on which the server runs. As a user, I want to take actions on that server (power on, shut down, rename, etc.) from any one of these contexts. As a developer, I want to reuse the same code in each context so I do not repeat myself. The Do Not Repeat Yourself, or DRY principle, is fundamental to software development. DRY reduces bugs and enhances extensibility because I only have to make adjustments in a single place. With low-code solutions, we often find ourselves copying code in order to offer the same feature in multiple contexts, violating the DRY principle. A substantial cost of software development is not just initial development, but testing, bug fixing, maintenance, and feature extension. When an application is not DRY, the cost of each of these increases.
Finally, where do we want to run our applications? Custom applications have the ability to run on any device and platform. Low-code solutions may be limited to a single platform. In some cases, low-code solutions may not be usable by people outside our organization unless we purchase a license for each user. Platform limitations extend to developer tools as well. Do we want to collaborate with other developers? If all our code is located within UI wizards on the vendor’s platform, collaboration and parallel development may be limited. With custom applications, we use tools such as Git to give every developer a copy of the development environment, even offline. Tools for merging code to which multiple people simultaneously contribute are readily available.
When it comes to designing the user interface, low-code solutions often look and feel prefabricated—square and modular with features that do not function well together. It may “get the job done”, but is it intuitive and delightful to use? Just as we prefer our home to be designed with unique combinations of room, doors, windows, and other features working together to suit our needs, we prefer the applications we use every day to solve problems ergonomically, in ways closely aligned with our unique business processes.
Does our business process involve complicated logic? How about permissions based on actions instead of a small set of user roles? Would a progress bar or dialog make the process more intuitive? Maybe a wizard guiding users through new features would make them less resistant to change. Should users be able to look up information based on a barcode with their phones’ cameras? In a custom application, imagination is the only limitation on user experience.
In certain contexts, data visualizations or interactivity are the best ways to engage users. Many enterprise solutions are simply forms over a database, a problem space for which low-code solutions can be a solid choice. For user experiences that display animated graphs with touch, hover, zoom, and sound capability, a custom application may be the only viable option.
Low-code solutions usually offer ready-made integration with a particular set of data or services. These integrations are built on top of APIs, commonly exposed via HTTP or gRPC. But what if we want to integrate with a service not offered? There may be limited ability to adopt the desired service. Even though the low-code solution may use HTTP or gRPC under the hood, we may not be able to make adjustments to that engine. Custom applications integrate easily with these types of services.
Pricing of low-code solutions varies with market conditions. Introductory pricing may expire, or another firm may acquire the solution and change its pricing strategy. If the solution becomes prohibitively expensive, there is limited ability to take the work we have done and make use of it elsewhere. With custom applications, Docker containers allow us to run applications on any hardware, including on premise. If we want to avoid vendor lock in, custom applications offer straightforward ways of doing so.
With any product or service, there is always the chance it will be discontinued. With a custom application, this decision lies entirely within our organization. With a low-code solution, this decision is outside our control. If the vendor goes out of business or sunsets the solution, we may be left scrambling to identify alternatives.
If you can live with their limitations, low-code solutions can be a viable option. They are especially attuned to capturing form data or creating a prototype when the development team is small. Low-code solutions are expanding their capabilities all the time, so limitations that constrained them in the past may no longer do so in the future.
When performance, flexibility, and user experience are paramount, a custom application is the only choice. They are capable of integrating with any third-party service and offer strategies for avoiding vendor lock-in and product discontinuation. When accompanied by the necessary technical expertise, custom applications allow the team and its software to scale to the scope and complexity of the problem at hand.