What Is Flexible Code?
I may have made up the term “flexible code”. Oh well. Flexible code to me means the architecture can be changed easily (and support multiple integrations easily).
I once read in a software architecture book that the best architects don’t immediately answer software architecture questions. They keep pushing them off to the future.
The idea is that by doing this, you keep your code flexible.
For example, suppose you need to decide whether to have a web front-end or an application GUI for your software.
You could immediately decide on the application GUI and design your software accordingly.
Or, you could design your code in such a way as to support both. For example, you could use a REST architecture. Then both a web interface and application GUI could use that REST API.
Following that approach, your design is not hard-coded towards one front-end or GUI. Rather, you could replace that part of the code with something entirely different.
The Benefits of Flexible Code
Sometimes it seems the only thing you can accurately predict with software and requirements is that they will change. Even the best predictions are rarely 100% accurate.
In such an environment, a hard-coded solution will destroy your business. As requirements quickly change, your software will accrue more and more technical debt over time.
The business may quickly pivot, but your software is going to be left behind if it isn’t flexible.
Part of code being flexible is good quality design. Investing time in good-quality code and good processes (like continuous integration, continuous development, and automated testing) will allow the code to be changed quicker.
This isn’t to say that you’re going to be able to make all pieces of the code as flexible as it needs to be. It’s just saying that doing so will protect yourself more from future changes.
How to Make Your Code Flexible
There are several ways you can make your code more flexible:
- Use good design patterns
- Use existing frameworks
- Follow good software processes
Using Good Design Patterns
I’m not going to explain a lot of design patterns here. I will give two examples that show how code can be more flexible: using several functions and using an existing state machine design pattern.
A good software practice is dividing your code into several small functions. This can make your code read like a book.
Not only does this make your code easier to read, but it also makes it easier to change. For example, you can change one function and get completely separate functionality.
Sure, you could change an existing really long function to make your code ‘more flexible’. However, it’s going to be a lot harder to test that code to make sure it works.
Using a good unit test framework, it is much easier to test smaller functions. In a short function, there are going to be way fewer edge cases and conditions to meet to test that entire function.
This makes it easier to change your existing code without breaking it.
In addition to smaller functions, I remember two instances of state machines used in two different places I worked.
In one case, the software engineer used a design pattern for the state machine. It worked very well and had very few if any bugs. It was also much easier to replace it with a completely different implementation, if needed.
In another case, the software engineer made a home-grown version of a state machine. It had several issues. It was also very difficult to test. In order to test the end state, you had to go through the entire state machine rather than have some mechanism of testing the end state independently.
Using existing design patterns will make your code more flexible for several reasons.
- Many smart developers have already optimized it for flexibility.
- It most likely will be easier to replace in the code if you ever need to use a different implementation.
- It will have fewer bugs.
Remember this the next time you write code for something others have probably already implemented in the past.
Use Existing Frameworks
Several smart people have already developed frameworks that are available for our use thanks to the open-source community.
Take Docker, for instance.
Let’s say the code needs to drastically change, and the method for starting the program as well as the environment has changed.
If all of this is wrapped in a Docker container, you can run the program the same way… by starting a Docker image.
Other frameworks can be used for the same principle.
Python web frameworks like Flask and Django already have several pieces of code ready to integrate with them.
Use frameworks to your advantage!
Follow Good Software Processes
Many software processes can make our code much higher quality.
Let’s take the example of unit tests.
If our code is flexible, it needs to be able to be changed easily. But how do you know you didn’t break existing functionality?
If you don’t have a good set of tests, the answer is… you don’t.
If write unit tests against your code, you will be able to automatically know when your code works and when it doesn’t.
Other software process can help achieve the same goal.
For example, suppose you do continuous delivery using something like Ansible. You may be able to use the same deployment mechanism regardless of how different the underlying code is. The way to deploy the code may be very different, but it is still controlled by running a playbook. This makes your code much more flexible.
Making your code more flexible doesn’t have to be a massive undertaking. Good software architecture can start with baby steps.
At the beginning, you must know the big picture of where you want to be. Do you want continuous integration? Continuous delivery? An entirely different software architecture?
Once you’ve determine the big picture end goal, you need to break it into smaller and smaller steps. Trying to tackle the whole project at once is daunting. Instead, focus on small, actionable steps.
Perhaps you can setup a Jenkins server? Then you can write your first unit test that adds 1 + 1 or something else trivial. Next, add a very simplistic unit test that runs a very small portion of your code.
Or perhaps you want to make your software more usable by other external programs. A REST architecture can help. Or perhaps you don’t know how. Do a Google search. Read a good book. Then determine a baby step.
As you create these in-between steps, you must make each of them work with the existing process or architecture.
This might be a little more work than if you tackle the whole project at once. But it also means it is more likely to get done.
So focus on those small steps. If you ever try to tackle a whole project, it will rarely work. You must break apart your goals into tiny action steps in order to make progress. Otherwise you will quickly become overwhelmed.