The first time you pad an estimate, you’ll feel guilty for all the extra money you’re about to make. The last time you do it, you realize you’re accounting for what you’re about to lose.
Client: Asks for a new featureMe: Recognizes I can build this simple feature for $100.00, provides customer estimate for $100.00(Older & Wiser) Me: Recognizes $100.00 is the best case, $150.00 is the worst, provides customer estimate for $125.00
In the grand scheme of history, that 25% buffer will net out to $0.00. Some are best-case, many are worst-case, some things fall into the middle. By the time you improve your process, you’re lucky if you can get to $0.00.
A buffer is basically an over-under estimate on the risk associated with a task. There are developer situations where virtually no buffer is necessary. Here are some examples that I would characterize as low risk:
Here are some high risk, higher buffer examples:
Not shockingly, it’s very easy to come up with the cases where a high buffer is necessary. Most software developers are optimists, and we tend to ignore the headwinds and the warning signs that should be obvious from past experience.
Developers have to manage another over-under bet that is much less exposed to our customers:
Should I refactor this hack and push for best practice?
Hacks, in this case are understood to be places in the codebase where you (or someone) has just made it work.
I’ve been doing this long enough to suggest that you’ll never have a project without hacks in place. Robot surgery and space missions notwithstanding, the vast majority of business & consumer centric software can manage a few strategically placed hacks.
A short list of the reasons we decide it’s best to go with a hack solution:
If we were to take a high-level view on these hack solutions, you could easily place them into these quadrants:
Not in all cases, but C & B seem to be the regions we are attracted to:
Syntax issues and poor organization get thorough code reviews. Some people spend entire days making sure the strings are using ES6 `${REPLACEMENTS} here` instead of REPLACEMENTS + ‘ here’. Refactoring for poor syntax is fun, easily trackable, and rarely requires the hard cost-benefit judgements that come from riskier features.
Developers love this space. It’s fun to argue about code style. It’s fun to make rules and put systems in place. My team has had great success with custom ESLint rules. These rules have had great impact on shortening our code review process. Our syntax is much more consistent. People spend time thinking about it.
A clean codebase is inspiring, fun to work with, and constantly challenges the collaborative wisdom of the group. Code style is a meaningful topic because it’s one of the more creative aspects of programming. It is one situation where form takes the wheel from function. In the best cases, good form is good function.
Hopefully you are fortunate and have product owners that do not know the difference between your hack solutions and best practice solutions. This is not because your customers should be poorly informed. It’s just that business and product will be better off, less aware of your architecture.
All decent business and product customers know you’ll spend precious time on some amount of cleanup. They know that you’ll have to make choices about when to pursue best practices or when to allow a hack.
Here is what they assume their smart, confident, good-looking senior developers will do:
Customers want you to push best practices in places where the hacks are the most dangerous from a stability perspective. Syntactical sugar is sweet, but not a fulfilling meal. Your customers desire the dense meatloaf that is risk mitigation.
Let’s use some examples:
Developer preference: Replace all var declarations with const or let because we just upgraded to Node 4+.
Customer preference: Make sure service calls are not reliant on random error handling patterns. Create consistent user expectations for errors and features, application wide.
Developer preference: Consistently use either Lodash or native methods, instead of mixing and matching.
Customer preference: Find out why the newest joins in your fetch request have caused the data to load 3x slower.
Developer preference: Switch to (Redux, Ramda, Observables) from (Reflux, Lodash, Promises) or choose your own adventure.
Customer preference: Mitigate issues faced by 5% of users where GET requests are loading out of order and causing bugs + forced refresh. Some of these calls are made using non-standard methods, why?
Time is a precious and limited resource. Knowing that, we all know that some pieces of the wishlist are going to get cut.
Everyone seems to be on the same page with that declaration. It’s what we choose to do and what hacks we choose to fix, that’s where the division lies.
Agile teams place risk values on bugs. This actually works very well when determining how to prioritize a production issue. QA people are very good at asking the right questions and assessing risk:
I have seen much less of this thorough evaluation process in matters of hack resolution. Maybe it’s a good idea for developers to ask similar questions about a proposed hack resolution?
Oh, and step away from the code. If you’re staring at the code, then code style issues will be top of mind. They will be like a tipped over garden gnome. You stand a few feet away, unable to think of anything other than restoring the gnome to full height.
Managing your evaluation process away from your development machine will help detach you from your completely valid feelings about code quality.
Some hacks remain, and you have to live with that. It’s hard to admit that “based on current prioritization, this issue may never actually get fixed.”
Once you can get comfortable with that mindset, you can focus your efforts on the greatest areas of need. If you’re lucky, you’ll get ahead of schedule. Then, the code quality hacks are yours for the taking.
Happy, properly-prioritized hacking!