How will you choose to compromise code quality?

Written by tewen | Published 2017/09/12
Tech Story Tags: software-development | agile | javascript | technology | product-management

TLDRvia the TL;DR App

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:

  • Re-implement an existing feature in another view with slightly different copy, design, and validations.
  • Automated tasks of known quantity and context. Examples: Send an email with CSV export, delete records with invalid names, save daily file to S3 bucket.
  • Copy changes (in most cases).

Here are some high risk, higher buffer examples:

  • Sweeping changes to a key data model.
  • New, performance-intensive functionality within a UI.
  • Reporting or analytics with unstructured data sources.

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.

Hacks and best practice

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.

The Hack Solution

A short list of the reasons we decide it’s best to go with a hack solution:

  • Laziness
  • We do not understand the best practice for this use case
  • Covering up the mistakes of others (or ourselves)
  • The framework lacks the correct pattern
  • The environment lacks a decent solution for this problem

If we were to take a high-level view on these hack solutions, you could easily place them into these quadrants:

  • Preferred Syntax: Good code quality, consistent, best practice
  • Poor Syntax: Messy, inconsistent, visually oppressive
  • High Risk: Changes are likely to create bugs
  • Low Risk: Changes easily managed, unlikely to create bugs

What developers do

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.

What customers imagine

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.

A system for evaluation

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:

  • Is a customer likely to see this?
  • How many parts of the app does this touch?
  • How essential is this feature / behavior?

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?

  • Is this veer toward best practice likely to prevent future bugs?
  • Does it improve user experience?
  • Does it improve production monitoring and issue triage in real time?
  • Does fixing this hack expose our engineering team to greater risk?

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!


Published by HackerNoon on 2017/09/12