Configure Over Code & Declarative Programming
Hello friends
I have some good news to share. We crossed 600 members in Godspeed's Discord channel this week! As well we have made Stay tuned for that. In meantime, let us more forward with our learning path towards 10X engineering.
Before we proceed, please ask yourself a question.
Who are you writing code for?
The codebase you author is not for you, but for the successors who work on the project after you are gone, and the organisation you work for.
In the previous post we looked into the 8 important guardrails, and the first one called Schema Driven Development (SDD) and Single Source of Truth (SST). In this post we will look into Configure over Code (CoC) and Declarative Programming (DP). Example of CoC and DP are actually reflected in the examples shared in the previous SDD and SST blog as well. SDD and SST are also examples of configure over code and declarative development. To get most out of this post, make sure to also read the previous entry on SST and SDD too!
Benefits of Configure over code and Declarative programming
By following CoC and DP you are giving your future maintainers and organisation more efficiency & effectiveness because they get
More maintainability
More flexibility and agility (Via separation of concerns (aka decoupling), and single source of truth principle)
More reusability
More readability
Less developer switching cost and experience requirement
Less probability of errors (BIR)
Less time to find root causes of errors and and apply fixes (MTTR)
How do these benefits happen?
By following some best practices like SDD, SST, CoC, DP etc, every org developer focuses on the tip of the iceberg for creation and maintenance of projects, and not the whole iceberg.
In the picture shown below, the part of iceberg which is below water (i.e. 90% of iceberg) is typically the not-actual-business-logic. Your actual business logic is 10% only! Whether you are a student (learning concepts or developing hobby projects), or a startup (with one or many services) or an enterprise (with many teams and many services), and you develop your applications using the traditional approach with bare Nodejs and Express server, trust me on this -
In traditional approach you will be working on the whole iceberg and adding 10X extra effort in developing, debugging, altering or maintaining the software.
Note: I am using Godspeed, Springboot etc as just examples. You can apply, develop and use these concepts anywhere.
Related and important concepts
Before we dive deep into CoC and DP, lets understand other related concepts along with these two
Convention over code
"Convention over code" prioritises adhering to established conventions and patterns rather than writing explicit configuration or logic, promoting simplicity and consistency in software development.
Example in the Java world: In frameworks like Hibernate, by following naming conventions for entities and their fields (e.g., class names match table names, field names match column names), developers can avoid specifying explicit mappings, reducing boilerplate code and configuration.
Note: Every language ecosystem behaves differently on this principle. While Java ecosystem generally follows convention over code approach, in the Javascript world, there is barely any consensus on conventions. For ex. location of transpiled code could be in , or directory. Or the main entrypoint of the program could lie in , or . The database schemas when defined using Mongoose JS follow similar approach to Hibernate, while Prisma JS follows its own syntax for model declaration.
Code over configuration
"Code over configuration" emphasises writing explicit code to configure and customise the behaviour of a system, favouring flexibility and fine-grained control over relying on predefined conventions or configuration files.
An example about setting up database services
An example from ExpressJS setup
Can you check this example and figure out which concerns could have been separated as configurations or declarations? Hint: Check the JWT setup, Schema validations (input and output).
Configuration over Code
"Configure over code" emphasizes storing configuration settings externally rather than hard-coding them into the source code, enhancing flexibility and maintainability.
Example in the Java world: In a Spring Boot application, database connection properties are stored in an external application.properties or application.yml file rather than being hardcoded in the Java code.
In the previous example of ExpressJS setup, could you figure out the concerns you could have separated? Check how the same is done in Godspeed.
ExpressJS Setup
Configuring the middleware
Endpoint setup
You will see here separation of concern: Express setup is decoupled with endpoint setup including urls, validations, authn and authz.
Read the previous blog on schema driven development or check these detailed explainer videos of working with eventsources and events in Godspeed.
Declarative Programming
Declarative programming is a programming paradigm that emphasizes expressing the desired outcome or behavior of a program without specifying the detailed control flow or algorithmic steps.
Imperative approach
Declarative approach
Even more declarative approach
A complex use case with a datastore
An example from Elasticgraph setup. Elasticgraph is a highly declarative ORM over Elasticsearch developed by yours truly (and his apprentices) when working for the office of His Holiness the 14th Dalai Lama :-)
Abstractions
Abstractions can be called the overarching principle or higher principle or superset of declarative programming and configure over code approach. Abstraction allows us to work with objects at a higher level of conceptualisation while encapsulating the specific details of each (lower level) implementation's behaviour. For ex. Inheritance in Object Oriented Programming or the function shown in the configure over code example above.
Abstractions are about A. Finding repeating patterns B. Expressing the repeatable patterns in one place (as single source of truth) and C. Reusing (or implementing) them in multiple places.
Abstraction of Eventsource in Godspeed
Example EventSource Implementation
Here is implementation of Cron eventsource in Godspeed
Abstraction of event definition independent of the cron library used
Notice how cron events' setup is decoupled from the use of library
Abstraction of event handler business logic from the event source libraries
In the example shown below, notice below how the business logic of a REST or Graphql API endpoint or CRON event or Kafka event is decoupled from
The actual event source mechanism (whether sync - REST, graphql, gRpc. Or async - Cron, message Bus or websocket)
The eventsource libraries (Express, Fastify, Apollo, Kafka, Salesforce, socket library etc)
The above example shows decoupling of functions with eventsource related code. Event ElysiaJS a Bunjs based web framework handles pure functions similarly to Godspeed's approach. (FYI You could add ElysisJS as an eventsource in Godspeed's meta-framework too.)
When to apply CoC or DP approaches?
When writing a new application, feature or service think about
Which configuration options are not going to change or change extremely rarely in this project during its lifetime? (For ex. port of your REST service or your JWT setup)
Which lines of code or implementation patterns are repeating or may repeat (even two times)? (Remember the CoC examples above where validation boilerplate code was repeated)
Is there some logic which could be simply declared instead of coded? (Remember Java Hibernate or Elasticgraph configurations shown above, or the automatic validations of the event schemas)
Are there any eventsource or datasource libraries merging with your business logic? Can you decouple your business logic from the libraries you use? (Remember eventsource, event and event handler examples from above)
Can you use single source of truth to generate remaining things like documentation (Postman, Swagger), CRUD APIs, integration tests etc from the source, instead of handwriting them or using AI to generate them? Even AI would mostly go wrong or be inefficient without using SST.
How can you make it easier for new maintainers to onboard this project? It is easier and faster for anyone (even AI) to fix things through configurations than finding a fix in between thousands of lines of code.
Which interfaces or declarations can you give to your future maintainers
Conclusion
Repeating again - 10X engineers don't write code for themselves. They write for the future maintainers of their projects.
Whether an AI or a human engineer is at work, by following we make their work easier & more efficient, from both project creation and maintenance perspective. Stay tuned for more on best practices on 10X engineering. If you like this blog, do share and recommend to your peers!
References
Explainer video: Eventsources in Godspeed with CoC approach
Explainer video: Events in Godspeed with SDD, SST and CoC approach