Building software today is a challenging pursuit. Teams often work with tight deadlines and shifting requirements. Even after the project’s completion, you may find yourself following the long tail of the Software Development Life Cycle (SDLC), which usually involves production support and complex updates.
One of the reasons this happens is because applications have traditionally been built in the same way as a house. It starts with a foundation, then the walls, utilities, and finishing touches. Fixing any damage or attempting a remodel adds another layer of changes.
In this post, we propose a different way of development. What if you built applications that were dynamically composed and based on configuration? What if you built an application that could easily adapt with just a few changes in this configuration? Welcome to Configuration Driven Development (CDD). In the next sections we’ll be introducing CDD, and then walking through an example application we built called “Sandbar”.
To follow along with the source code from this post, checkout the front end GitHub repo here. The application also uses a set of Azure Functions and Cosmos DB for the APIs, checkout the back end GitHub repo here.
What is CDD?
As we mentioned in the intro, CDD is a different way to build applications.
Traditionally we build applications like this:
Lead architects design around business requirements
Application is built and deployed
Changes are done through additional components (SOLID Principles) or painful refactor
With CDD we build applications like this:
Independent components are built first, starting at the atomic level
An interface (usually JSON) is defined to compose the higher level UI
Combination of reusable components and JSON blueprint allows developers to easily build up and out
At its core, CDD is a way of using modularity to build a loosely coupled set of components that are then composed together using a common interface.
This is all exemplified in the following graph (shoutout to Ram Ramkumar for the visual):
Let’s look at our application “Sandbar” and see how it works.
In the climate of a quarantine and pandemic, people still need to find ways to relax and enjoy time away — primarily at the beach. Our app capitalizes on this idea by providing a way for users to reserve “spots” that are safely set apart from the others for a specific time period.
The application has users with a basic login and logout setup. The users create “reservations” for a specific beach “spot.”
Reservations require different fields to sign up, including email address, phone number, time, etc.
The application also has “basic” and “premium” users. Where “basic” users just get beach access, “premium” users get additional premium amenities.
For the purposes of demonstrating the benefits of CDD, this reservation modal is where we will focus to showcase how easy it becomes to manipulate these fields through configuration.
If you look at the level-0 branch of the front end GitHub project you’ll see Sandbar without configuration. Specifically let’s look at the code in the src/components/ReservationModal.js file. We have some state hooks around the basic fields:
This component serves as the popup modal you see when you try to create a reservation.
The component is also broken down into “basic” vs. “premium” fields.
All of this is built out directly in the template, just as you see in most applications today. There are fields in the template that are then bound to hooks that pull in state from Redux or APIs.
First, you’ll need to create some basic configuration that you can retrieve in the template like so:
Then you can also consolidate the field information into one place in the state replacing the ones specific for each field like so:
If you notice, we’re using the same handleFieldChange method as before as well.
Next you’ll need to create some smaller components that will be used to compose your form. We added components for select dropdowns, radio groups, and text fields. These replace the basic form implementations from level-0 that will then take their place in the reservation modal:
Notice that we’ve created components for the multiselect, radioGroup and text parts of the form. These all just read in their values directly from props.
We also created a CustomFormComponent that will wrap those.
Then in the original ReservationModal.js file that we had before, you have references to the form component for the applicable fields:
CDD Level 2
Now you’ve got the basic structure set up, but you don’t have a configuration file to edit. You’ve still got a nested set of components that are statically built.
If you pull the level-2 branch of the front end GitHub project, then you’ll see the completed CDD in action.
Open the file src/utilities/configs/componentConfig.js and you’ll see the central configuration that the project is using.
First thing to note is that we’ve moved the following into a configuration file:
Second thing to note is that we have “basic” and “premium” form fields:
All of this will now be read in by that ReservationModal.js component that we were looking at originally.
In the src/components/reservationModal.js you’ll see that we now have also created a “FormContainer” component that wraps our dynamically composed CustomFormComponents.
This “FormContainer” component is nothing more than a map of the fields that have been brought in by the application:
As we mentioned before, you’ll also find that using the useState React Hook, we are setting the fields dynamically from the properties passed in:
In the component that is used to display the “Cards” for the reservations and spots, the “ReservationModal” takes in all the necessary field information directly as a prop:
This means that any changes to the fields that are defined in src/utilities/configs/componentConfig.js will be passed through all the way to the ReservationModal.js component. Therefore, you can add and remove fields with just a change in configuration!
In conclusion, CDD is a very powerful way to compose your applications. What we’ve done here is just one example and the possibilities are limited only by your imagination.
And while are using config files in this example, you could just as easily add all of these values to an API. Server Side Rendering (SSR) hinges on the ability to do just this. You can compose an application just from an API call.
There are a lot of use cases for this approach. If you’re looking at a legacy application and hoping to update it to use this approach we highly recommend iterating over it. The great part about this approach is you can start small, and expand it throughout your application.
Thanks for reading our post! We hope you’ve enjoyed it and learned something in the process. Feel free to connect with us on LinkedIn!