Software developers sink a tremendous amount of time into boilerplate code. Code that does not bring any business value and is just there to “make things work”. Over the years, in some areas our community managed to reduce boilerplate code significantly. Projects like Spring Data Rest for instance remove the hassle of writing boilerplate code to access data from a database and map it to entity objects. It even removes the need to write controller code. But is that enough? This article implores more radical steps to avoid or remove boilerplate code.
I often encounter projects where most of the code, the components, the microservices are used for CRUD operations without any additional business logic.
Focus on business logic, not on boilerplate code
Business logic is the code that makes your business stand out from others. The custom automatic price generator that scrapes financial data, correlates weather forecasts and uses a complex algorithm to create limited discounts. The AI-driven recommendation system that infers which book you should read next to achieve your personal or business goals. The accounting system that uses OCR to read incoming invoices and automatically books them to the correct account. The custom process that took months to get right…
Especially as a startup, you should let your team focus on this game-changing technology instead of the busy work of boilerplate. Boilerplate systems don’t look bad on first glance. Developers can write and deploy them rather fast, given the right tools (scaffolding generator, powerful IDE, containerized deployments). The cost and time sink however is the continuous maintenance: Security fixes, upgrading, running tests against them, migrating them to new infrastructure, etc. So let’s get rid of them! But how do you build your admin panel to create products, product categories, tags, shipping fees? And the API the frontend developers can use for the mobile app to display this data?
A promising approach is keeping the CRUD operations separate from the business logic. In a microservice architecture, ignore the bounded contexts that have little to no business logic. Use tools to automatically generate the APIs for these areas instead.
Postgrest for REST, Hasura for GraphQL
If you prefer a classic REST API, Postgrest is an amazing (and free) tool to get results fast. You can connect it to your existing Postgres database and Postgrest automatically provides CRUD endpoints for your entities. Postgrest is extremely rich in features, secure and easily deployable as docker container.
In most new projects I recommend GraphQL instead, or additional to REST APIs. The API consumer controls which resources and embedded resources the API returns. GraphQL is especially helpful in use cases where you need to aggregate data from a lot of different tables and the requirements which data is needed changes frequently. Frontend developers love GraphQL, as tools like Apollo make it easy to work with it. I can recommend Hasura for providing a GraphQL API alongside analytics and development tools. It’s very easy to built a MVP with Hasura, however getting permissions right is a lot of work.
With Postgrest or Hasura, the backend systems are now boilerplate-free.
Remove frontend boilerplate code: Admin panels with Retool
One big strength of Retool is the number of possible data sources, and the possibility to COMBINE several of them in the same app: Postgres, MySQL, MS SQL, MongoDB, BigQuery, Oracle, Redis, CouchDB, REST, GraphQL, Salesforce, Google Sheets… You can achieve fast results by using a database directly, as Retool can automatically generate UI tables and forms in that case. For REST and GraphQL you need to drag and drop some components.
Note that Retool isn’t cheap, especially as you will likely need the Pro version. If you don’t like Retool, there are a lot of similar tools out there, e.g. UI Bakery.
Adding business logic again
When you need to add business logic to one of these “simple” contexts later, you can create a corresponding microservice for them. If the business logic does not apply to read operations (it usually doesn’t), you should use a CQRS-like approach where you only implement a new service for commands, but keep the read operations in the automated tools like Postgrest or Hasura. Keep in mind that permission management, auditing, logging and monitoring is not business logic. The tools mentioned above are sufficient for that.
When you have implemented your admin panel in Retool and realize that you need additional backend business logic, you can change your create / update / delete queries to use a REST API or GraphQL mutation and keep your read queries to directly access the database. That way you have performant read operations but can store complex business logic in write operations.