We’ve all been given this tautological advice throughout our career—write code that’s easy to change. But what does that actually mean?
I only vaguely remember the first time I was given this advice, but I do recall my first thoughts about it. A big reason I went into computer science as opposed to another science or an engineering discipline was the immediacy of software: I make a change, I run a command, I see results, and I learn. A virtuous cycle 🌈. I enjoyed programming because of how fast change I could see change. So my first reaction to this advice was… confusion. Isn’t code already easy to change?
I soon learned through experience that, when you’re working with other people to sell a software product, the ease of changing code varies based on context. It’s easier to change internal code than it is to change client-facing code; it’s easier to make changes your little corner than it is to change core platform bits that everyone relies on; it’s easier to change your code than it is to get a vendor to make a change. But these are all true independent of the decisions I make. So the question remains, what does it mean to write code that’s easy to change?
My first answer to this question was informed by observations of my first production code base. It was easier to change a value if it was a variable defined in one place instead of copy-pasted every where. It was to easier to modify a function when it only had a few parameters instead of dozens and was only twenty lines long instead of one-thousand. Essentially, it was easier to change well-written code. Code that followed the advice of SOLID principles or Code Complete was easier to change.
Well-written code remained my early career answer. But as I gained more responsibilities and ownership, I also gained a sense of frustration. I realized that it didn’t matter how clean the source was when there was three month release cycle and tedious manual testing for it to reach the client. It was hard to be agile and iterative when even a one-line change took months before feedback was possible. My answer to the question “What is code that’s easy to change?” eventually became “Well-written code with Continuous Deployment and Continuous Delivery”. The speed with which I changed literal source code didn’t mean a whole lot without being able to test and deliver the results to the end user on the same scale.
This definition continued to work for me until later in my career. Once again, my observed reality didn’t match the theory. Ostensibly well-written code that I could deploy within a day was still difficult to change. I was working with services that were coupled with multiple other services owned by other teams. I’d find myself unable to make simple changes because they depended on work lost in another team’s backlog. The converse was also true—my services had other services depending on them so I could never be certain that a given behavioral change didn’t break one of our dependencies. Having cleanly-written code that could be updated in less than a day didn’t mean a whole lot when a change cut across code bases owned by other teams. Backlog priorities don’t change in a day. This problem space helped me understand the true application of Domain Driven Development. Changes most frequently occur along business domain axes so decoupling different domains and making individual domain code cohesive will make changes easier. To have code that’s easy to change, I concluded, you need “Well-written code that follows DDD practices and leverages CI/CD infrastructure”.
While this definition currently matches my experiences and observations, I’m sure I’ll have some future epiphany that triggers an update. The important part is that I’m always refining my theory through continued experience with modifying shipped code.