I came across this interesting article about how easily software code can transform from the cleanest, slickest code this side of codemonkey Shangri-La, into a giant mess of spaghetti code that becomes a nightmare for the poor code monkey who has to inherit it and figure out how to maintain it, let alone CHANGE it.
And that’s the true litmus test of good quality code.
How easy or hard is it to make changes to the code?
I still clearly remember two nightmare projects I inherited and had to be responsible for their upkeep and maintenance.
I have no doubt every software developer has been in the same shoes at some point in their career, where they end up inheriting something that they had no original hand in designing.
The first project I inherited was what we now refer to as an SPA, short for Single Page Application.
It’s just a fancy term for a web application where all the interaction happens in a single HTML page, where the application doesn’t redirect you to any other navigation pages or website.
As I began to get familiar with the codebase, I noticed that the majority of the code and business logic for the application was intermixed and embedded directly inside the user interface layer of the application.
This is a design principle violation of an important concept known as separation of concerns.
The core idea behind separation of concerns is that code that belongs in a certain “category” needs to belong ONLY in that category.
Most modern-day software applications are comprised of three major “tiers” or “layers”.
1. User interface layer
This is the visual piece of the application the end user actually sees on their computer screen, tablet, or smartphone.
This layer should only contain code that is responsible for the “look & feel” of the application. This will include things like button controls, text input controls, and all the graphic elements of the user interface.
2. Business logic layer
The business logic layer of the application is where all code logic, business rule validation, and any other rules are enforced by the application. It should only contain code that is responsible for all business rule enforcement and validation requirements of the application.
Say you’re creating a banking ledger application, and let’s suppose you’re working on the code implementation responsible for making a withdrawal from a bank account.
So one of the very first business rule validations you would want to enforce are things like making sure your withdrawal amount is a valid numeric data type… so no strings, no booleans or anything else that isn’t a valid number.
The other major business rule is to make sure you don’t allow a withdrawal that exceeds the current bank account balance you are trying to withdraw from and throw some sort of validation error that indicates you’re triggering an “insufficient funds” type withdrawal action.
And if something DOES go wrong with the actual withdrawal, you want to make sure you rollback any attempted withdrawal actions, back to the original state of the bank account balance.
All this type of business rule validation should happen in this business layer of the application.
3. Data layer
The last layer of the application, the data layer, is where all important data used by the application is stored in a permanent cached system like a database or text file. So any code that needs to persist or retrieve data out of this data layer, should happen in this last data layer of the application.
If you took a look at the underlying source code of a software application following this 3 tier (layers) design principle, you would notice that all the user interface related code would typically be stored in a single folder structure representing the UI layer of the app.
All the business rule validation code would end up in its own separate folder.
And all the data layer persistence code would be in its own folder structure as well.
The important thing to keep in mind is every single piece of code belongs in a certain specific “layer” or “tier” of the application.
Why is separation of concerns important?
When an application is following this principle of “separation of concerns”, it becomes very easy for the software developer to know which section of the application they need to focus on, when they want to add new features or fix something that went wrong in the application.
So say you want to add some new button controls into the visual layer of the application.
If your project is following the principle of separation of concerns, you’ll know that you can quickly jump over to the user interface layer of the project and know that is where you need to make your new enhancements to the visual layer of your application.
Or if you need to change or add some new business rule validation of the application, you will go to the business logic tier of the project, and make your changes there.
Or if you need to change the data persistence layer, you’ll go to the data persistence section of your project and make your changes, accordingly.
The problem with the project I inherited was that it did not follow this principle of separation of concerns, whatsoever.
Code that SHOULD have belonged in the business logic and data layers, was embedded directly inside the user interface layer.
Why is this a bad thing?
Let’s suppose the boss suddenly asks you to change this web application into a mobile application that would work on a tablet or smartphone.
All that critical code that was embedded directly inside the HTML web page, would have to be moved out and moved into the mobile user interface code files.
But let’s suppose your boss asks to convert the mobile application into a client desktop application that needs to work on a full-sized computer?
When your code from your business layer or data layer is embedded directly inside the user interface layer of the application, it becomes a major pain to swap out the user interface, because those layers are stuck inside the user interface layer.
If those layers of code were located completely outside the user interface layer, it becomes much easier to swap out your user interfaces with new ones because all the important code in your business and data layer, exist in the other parts of your project.
This is the true power of adhering to the principle of separation of concerns in application development. When you structure your code so that it belongs in the right layer of your application, you get the benefits of knowing where to go in your application when you need to change the user interface. Or the business rule layer. Or the data persistence layer.
The other benefit is following the principle of separation of concerns also helps to avoid the other big problem that contributes to code going bad. Repeating code.
Does your code smell?
I inherited a different project at another organization that suffered from the problem of code repeating itself all over the place.
And I’m not talking about code that RESEMBLES other previous code. I’m talking about cloned code that was scattered in multiple places in the application.
Repeating code is probably the WORST “sin” that contributes to bad code because it becomes a nightmare to figure out how to fix or add new changes to the application.
Say there’s some duplicated code that has been repeated 20 times in the application. That means you would have to change it in 20 separate places to fix all the bugs.
The same goes for making changes. You’d have to add your new functionality in those 20 repeated places in the application.
It’s why the principle of DRY, short for Don’t Repeat Yourself, is the golden rule of programming. When code exists in one and ONLY one place, it means you only have to find or change it exactly ONCE for the changes to take place.
They even have a term for bad code. It’s referred to as “code smell”. You can think of it almost like milk that goes sour in the fridge.
Unless you have a cast iron stomach, most people will be repelled by sour milk.
Or sour code. I mean what code monkey likes to pour sour code on their cornflakes?