Envision the following scenario: you are working away at the final 5% of a project, glad to be near the end, when you catch the first hints of unexpected changes coming in the near future.
Your chat channel starts to fill up with innocuous phrases like "next iteration" and "looks good, now let's see how the users respond." It seems harmless, until you begin to receive successive waves of PDF files with pages upon pages of new requirements. “Huh…,” you might think to yourself, “this is turning into a completely different application!”
If this is the first or second time you’ve experienced this, you might be somewhat new to the field of software development, and you may be feeling defeated. You want to feel that feeling of completion! Of crossing the finish line. It was so close. And now it appears so far away.
How did this happen? People want to build software. They have a theory about what they want, and what their end users want. The perfect set of features, which will naturally be intuitive, simple and easy to use. But, it's just a theory. Once that theory is tested, it will most likely be only partially correct. That critical feature we built last month? We shipped it! It works perfectly. But, the users don’t understand it, and no one is using it. And so… the requirements will change. The goalposts will move.
Here are some strategies to help you survive this lamentable, all-too-common predicament.
Acknowledge the Emotional Impact
Late stage changes can brew a soul-crushing concoction of emotions.
The first step out of this quagmire is to acknowledge that yes, you are frustrated. It's reasonable to be so. The code you've painstakingly engineered to match the original requirements might be critically maimed by "a few tweaks" in the 11th hour of the project. You feel stranded and overwhelmed. You start to wonder if life could have been easier if you had taken up a simpler career as a stuntman, or even as an astronaut.
The next thing to do? Consciously choose constructive over destructive reactions to this distressing situation.
Say No to Destructive Reactions
You may be tempted to wallow in self pity, or lash out in frustration. But this will only isolate you from the people you need to work with in order successfully navigate those changes. Succumbing to feelings of helplessness or inadequacy is likewise counter-productive, as that will blunt your ability to confidently rewrite or even discard code that no longer makes sense. Finally, a total emotional disengagement from the project may temporarily insulate you from feeling bad, but apathy will completely block you from any productive work until you get beyond it.
Grow by Facing Tough Times Head-On
Try to adopt the mantra "I grow when challenged". Internalize that hard situations are invaluable for your growth as a software engineer.
Consider an athlete who only trains with other, less capable athletes. While that individual may feel good about their performance, in reality they are capped at their present level of development. Similarly, a workplace devoid of significant and unexpected challenges will be a sterile and lifeless environment, which will stunt your growth as a professional problem solver.
The path to becoming a better software engineer is a narrow one, full of rough patches and at times, very challenging terrain.
Tell Your Rubber Duck All About It
Take a deep breath and step away from your computer. It’s time to make a fresh assessment of the situation, unencumbered by the weight of all that code you've written up to this point.
First, gather up all the information relating to the requested changes. This might include the latest slide deck of changes, previous flow charts that you or a coworker has written, or scribbled notes and pinned chat messages.
Once you've got that organized, the next thing to do is to try and explain to yourself what needs to be done in the simplest terms possible. Describe the present situation, the changes to be made, and the end goal. Using these thoughts as a guide, tour the regions of the system where changes are likely to occur. You might find that when you put a magnifying glass to them, those changes might turn out to be less pervasive than you initially thought.
Finally, pick up a whiteboard marker and present your ideas to your peers. See if you can explain the problem and your proposed solution, using large, broad brushstrokes. Chances are, if you can articulate it, you've got a workable first draft solution.
Practice Paired Planning
Paired planning is a great way to see the changes through someone else's eyes. It's likely that your partner will have a different perspective, and come up with a novel approach, or bring up some edge cases you hadn’t considered. A taste test between several possible approaches is a great way to find a simple, efficient, and correct solution.
Choose Lo-fi When Designing
During the planning phase, your goal should be to generate as many ideas for efficient solutions as possible. Don’t jump headfirst into coding. It's better to spend an hour outlining what you intend to do, explaining it to someone else, and clarifying your understanding. Whiteboard drawings, sequence diagrams, and high level design summaries can be some of your best tools during this process.
With a whiteboard, you can virtually reimplement a system hundreds of times in the same duration it would take to incorrectly refactor the codebase once. The disposable nature of whiteboarding helps to not fall in love and commit to your first idea, which may not be the most optimal solution.
Weigh the Scope of Changes Against Your Budget
Before writing more code, ask the following questions to help guide the process of a refactoring a large software project:
- How much tolerance is there in the project schedule? Can we make paradigm shifts, or should we fall back to bandaids until the next release? Can we ask for more time to "do the right thing"?
- Given a tight delivery deadline, can the changes be quarantined to a particular layer of the application? For example, in the situation where the UI must change but it's too risky at this point to change business logic, one could build transformation logic to retrofit objects flowing between the UI and the business layers.
- Given a more liberal deadline, which other parts of the codebase should we also improve, while we're in here making the essential changes?
- Is this an opportunity to clean up the codebase? For example, could we delete logic which models a deprecated requirement? If the answer here is yes, could that be helpful in formulating part of the solution?
Get Up and Take a Break
It's always helpful to stop, take a break, and come back fresh. Move your body, and get outside of your own head for a short while. Do some jumping jacks. Pet a friendly dog. Go for a walk. Go get coffee, enjoy the outside air. Once revitalized, start coding with conviction, and you will prevail.
Accept that Change Is Inevitable In Living Projects
It's several weeks later, and you've finally got a stable release. You matched the designs and the changes in functionality that they requested. Confidently, you submit your work for review. To your surprise, they ask for even more changes. The cycle begins anew.
Actually, this is a great thing! After seeing their vision come to fruition through your labors, and watching how end users react, your product owner better understands what they ultimately need. Based on what you delivered to them already, they can now see how much more is possible. It’s plainly obvious they trust you to make the next set of changes, since you've proven you're more than capable.
So roll up your sleeves, and take the new challenge in stride. Carry on knowing that you are growing though the experience, and validating your ability to deliver software that is a living organism, always changing, always adapting!