Weighing The Value
Every project eventually reaches its limits. You'll encounter problems that can't be solved with your current approach.
As a system ages, it can become increasingly complex. Exceptions become the norm, making it hard for developers to understand how the system works. Old code can also cause problems, using outdated techniques that are no longer compatible with the rest of the codebase.
Hitting limits is a natural part of a project's life cycle. It's not a problem, but rather a sign of the project's evolution.
Don't assume that hitting limits means your initial design was poor. It's more likely that trying to predict the future would have led to a complicated design that would have failed even sooner.
Not every part of a project will reach its limits. Some components can continue to function well without changes, as long as they're well-designed, kept tidy, and handle exceptional cases effectively.
Future proofing can be dangerous because it's often unnecessary and often doesn't work.
Ignore, Tweak, or Refactor
You've hit a natural limit, but you don't have to start from scratch. You can:
- Live with it: Ignore the issue, or allow OR clauses, or buy more hardware.
- Tweak it: Simplify your filtering or caching or combined exceptions.
- Refactor it: Update your architecture to fit the changed problem or your deeper understanding.
How do you decide? Do you ignore the issue, make small changes, or do a major overhaul?
Gradual Evolution vs Continual Reinvention
Programmers often struggle with making changes to their code. Two common tendencies can lead to problems: Type One programmers fix issues by tweaking the existing code, while Type Two programmers want to start over with a new design.
Both extremes are bad. Type One thinking leads to a state of being stuck, while Type Two thinking leads to constant rewriting.
The best approach is to strike a balance. Knowing your and your team's tendencies can help you make better decisions.
Red flags for Type One thinking include:
- Describing the issue in terms of the current architecture
- Saying an issue is impossible to solve
- Using the project schedule as a conversation-stopper
- Not making major changes in years
Red flags for Type Two thinking include:
- Reworking the system just to "clean up" code
- Being driven by a single issue or excitement about a new technology
- Focusing on the solution rather than the problem
- Ignoring performance or resource issues
Understanding these patterns can help you make better decisions, but it won't make the decision for you. You need to consider both your and your team's tendencies and find a balance between incremental changes and reworking the system.
A Simple Rule of Thumb
To decide whether to make a big change, use this simple rule: is it twice as good? If the new system will be better by at least twice the amount, then it's worth the disruption and new problems that will come with it.
Sometimes, you have no choice but to make a change because your current system can't do what you need. For example, you might need to rework your server code to support new privacy regulations.
Other times, the decision isn't so clear-cut. You need to measure or estimate whether the new system will be better.
Was it worth it? Yes, because the new system would be twice as good on important metrics, such as storage and speed. We already had the height maps for rendering, so we would only need a few hundred bytes to integrate them into the physics engine. Basic physics operations would also be much faster.
In this case, the rule of thumb said that reworking the physics engine made sense, despite the challenges.
Dealing with Fuzzy Benefits
Don't use the difficulty of quantifying benefits as an excuse to skip the "twice as good" rule. For example, instead of just making programmers happier, try to measure how much more productive they'll be.
If you don't quantify benefits, you'll likely make the most comfortable decision, which can lead to trouble. Here are some questions to ask:
- If it's to make programmers happier, how much will they be more productive? Twice as much?
- If it's to improve UX authoring, how much better will the UX be? Why will it be better for users? How will you measure that improvement?
Measure the potential benefits to make informed decisions.
Rework Is a Good Opportunity to Fix Small Problems
When you decide to rework a system, take the opportunity to fix smaller issues too. Don't do major work just to fix outdated code, as it's not worth the trouble. But if you're already changing things, you might as well make the code modern and efficient.
This approach is efficient and effective. Keep track of small problems you can't fix immediately, then address them when you're doing bigger work.
Don't dismiss incremental improvements. Over time, you may gather enough ideas to justify major changes. If you notice patterns and a collection of small issues that can be solved at once, the improvement will be significant.
The key is "twice as good." Don't replace something with only a little improvement – do it for a big, significant gain.