If there’s one constant in software development, it is change. Our entire workday is spent changing things and responding to change.
Every time you write a line of code, you are changing it. You might add new features, fix bugs, or make changes to existing code. However you put it, you’ll be changing the code.
Requirements will change. You often find this out after you’ve coded a feature, and now the business either changes their mind or you find out that you made some wrong assumptions.
Business priorities will change. What was important yesterday may not be important today, and six months from now, all kinds of things might change. There could be new, more important projects on the horizon, new people in charge, or new business opportunities.
Software development teams change too. You might stay at your company for many years, but during that time, you might get moved from project to project. Developers will leave the company, and others will join. The end result is that many different people will end up working on the code that you’re writing today.
Since we know that we are going to have a lot of change, it would therefore make sense to reduce the cost of change so that we can respond to change as quickly and easily as possible. So how can we reduce the cost of change?
Automated Testing
Every time I add a line of code, I risk breaking my application. Breaking the application is just not acceptable. We’ve come to accept bugs as a part of the process, but that doesn’t mean that it’s OK to write bugs. If you’re not striving to write bug-free code, then maybe you need to raise your standards.
Nevertheless, the fact is that we all screw up and we all have the capability to create bugs. Knowing that, I want a way that I can easily test my application so that I can ensure that I find out if I broke something once I change it.
On my current project, I’m writing an application that helps my client bid on construction projects. They can’t afford to have bugs in their system that will cause them to incorrectly bid on these jobs or they could be out a lot of money. The bottom line is that it has to work because their entire business is now running on the application that I’m writing. They also come to me on a regular basis with new feature requests and things they need changed. They don’t want to wait months to get this functionality, and they also don’t want me to break any existing code.
Thankfully I have a large suite of automated tests that I can run to ensure that I didn’t break anything. This isn’t foolproof and things sneak through, but it’s usually little stuff that isn’t critical. But it’s good enough proof for me that I didn’t break the existing functionality. As a result, I can release to production daily and I spend virtually no time manually regression testing my application when I deploy. My unit test suite has reduced my cost of change to pretty much just the time it takes me to code the changes, so now I can react quickly to changes, release all the time, and I can do it without breaking existing code.
Clean Code
Sometimes people will write their unit tests, write the code to make the tests pass, and then assume that that is good enough. That’s great that you wrote tests, but how easy is it for someone to make a change in your code?
I feel that clean, readable code is very underrated these days. When you write code, are you thinking of the person that is going to need to understand what you did once you’re not around anymore? That scenario is very likely to play out at some point. So when you write code, create methods, variables, and classes that are very descriptive. Place a priority in making your code easy for someone else to read.
“Clever code” is the opposite of clean code. I’m talking about using complex algorithms to solve simple problems, trying to using a complicated LINQ statement to do an operation that would be more readable in a foreach loop, or trying to implement something in the fewest lines of code as possible. There are times where you might want to do things like this, but usually it’s more important to write code that is easier for someone else to read and understand. Again, remember that someday someone else is going to have to change your code, so write descriptive code that makes it easier for that other someone to know what to do.
Tests Are Documentation
Your unit tests are documentation of what your code is supposed to do. I practice behavior driven development, which means that my unit test methods describe some business functionality that my code is in charge of executing. This way, if someone needs to know what my code does, they can look at the test classes and methods and see what it is supposed to do.
Lately I’ve started adding a lot more comments in my test methods. The class names and methods names may describe what the code is supposed to do, but it doesn’t always explain why. I’ve found that sometimes it helps to write down the why because that is also important information. Since people can look at my tests as documentation of what my code does, I figured that this would be the best place to put the whys, because if someone has to change my tests, they’ll immediately know why I did what I did and they’ll have a reminder that they need to update my comment.
Build Iteratively
Since business priorities and requirements are going to change, we want to reduce the cost of this change too. If the business comes to you and drastically changes the requirements or certain assumptions that you might’ve made, it might be really costly and painful to change, and you can only do so much about that. What we can do is make sure that we’re constantly checking back with the business to see what they want now so that we have as few surprises and as little rework as possible.
This is one reason why Agile projects often run on iterations. As a part of this process, meet with your business sponsor every week or two and talk about what you’re going to do next. Show them what you’ve done in the last week or two, and make sure you’re on the right track. This way, if they’re going to change their minds, you’re giving them permission to do so and you can adjust what you’re doing as soon as possible so that you have the least amount of rework.
Always Be Aware of Change
Quit thinking short-term and quit shoving code in just to get it done as fast as you can. You may think you’ve done something good by getting it done faster, but if you create more work and pain in the future, it’s a net loss. Instead, always think about what the effects of what you are doing now will be two years from now. Your goal is to create business value without creating technical debt. A home builder can do shoddy construction and put nice looking paint and siding on the house, but 10 years from now when the problems arise, people won’t be thinking very highly of that builder. Don’t make the same mistake. Take pride in your work and strive to always leave your code base cleaner than you found it.
In response to the inevitable “You’ll always need QA” argument:
Yes, you’ll always need QA, but now they can focus on testing edge cases and the risk that your changes create to the system, instead of retesting things that already work. This is because they will (eventually) learn to trust the fact that developers will ensure that stable features remain stable.
A nice phrase I heard from Alan Stevens to combat: “Clever code†is the opposite of clean code.
“Beauty is the ultimate defense against complexity.”
True, it’s not word for word the same because some people will equate clever == shorter == beautiful. But, if you keep your code clean, readable, and by design beautiful it’ll be much more fun to work in.