Engineering consistency

  Wynn Netherland • 2017-11-16

Southwest Airlines only flies 737s, saving them on maintenance costs and giving them greater flexibility to move aircraft between routes.

Inconsistency is a tax. Any mature software project is littered with conditional code to handle the edge cases, the business rule exceptions, the differences. We often struggle so hard to handle inconsistency in the problem domain, we never notice the cost of inconsistency in our code.

The cost of inconsistency

When you sit down to write code to meet a business requirement, there's a series of questions in the back of your head:

  • What types do I need to store this data?
  • Can I do this processing while the user waits?
  • How many rows can we expect per account?
  • Oh no, what if there were a million of them?

As developers, we've got enough UX considerations and Big O questions with any feature, we don't need our code base bringing its own. Every inconsistency in your project adds cognitive overhead, which David Demaree succinctly defines this way:

how many logical connections or jumps your brain has to make in order to understand or contextualize the thing you’re looking at.

Every inconsistency in your project loads up required context to work in the project, adding ongoing cost borne by the team as they build new features.

Sometimes you pay the cost all at once because inconsistent code is harder to refactor. Inconsistent naming conventions, folder structures, and syntax all make it more difficult to automate changes to code. The cost of that inconsistency is often more code to handle the exceptions, time, and energy spent outside of the actual problem domain.

Mitigating inconsistency

So how do we push back against the inconsistency that envelops our software projects?

Tools

As an industry that creates software to solve problems, we have a natural inclination to reach for software to solve the problems we face writing software. Sometimes that works.

Frameworks. We tend to think about frameworks primarily as abstractions, tools for reducing complexity, but many frameworks employ convention over configuration, effectively codifying consistency in the framework itself. I've worked on a lot of Rails projects in the last dozen years and never had to wonder where to put a model, view, or controller.

Style guides. Teams and communities often develop their own syntactical tastes and document those preferences. GitHub, Airbnb, and Google have all published their own opinionated guides.

Formatters. Some languages have developed tooling to automate the application of style guides, reformatting code in the editor or during the build process. If you've worked with gofmt or prettier wired up to your editor's save function, when you work without it, you're immediately aware of the small nanodecisions you make just to format your own code. For Vim users, Neoformat provides support for a long list of languages. Even if Vim isn't your editor, the README has a superb index of formatting tools by language.

Linters. Linters and static analysis tools can be valuable for encouraging or enforcing not only syntax style, but broader design patterns, naming conventions, and other candidates for inconsistency. GitHub curates an excellent collection of linters and static analysis tools.

People

Tools alone won't save us from inconsistency. Even where automated tools provide value, humans have to think about the standard, what our code should be consistent with.

Here are some tips to tackle inconsistency as a team.

Break it down. As a team, identify the cross-cutting concerns in your project. Where does the broader team need guidance? What areas are prone to evolve (or devolve) over time? These could be language or framework specific (CSS, JavaScript, React, Redux, etc.) or more topic-based (background jobs, REST API design, or GraphQL schema).

Form some teams. Even on full-stack teams, individual members have areas of the project that interest them more than others. I suspect your team already has folks everyone goes to with questions on certain topics. Why not formalize those roles and empower them to make decisions and steer the project towards horizontal coherence as the team works in the vertical feature silos? GitHub teams are an easy way to mention them in issues and pull requests. With the new CODEOWNERS feature, you can even automate code review requests.

More guardrails, fewer gates. As these teams field questions and provide feedback during code review, emphasis should be placed on surfacing answers and catching inconsistency earlier in the process, where it's cheaper to address. For recurring issues during code review, it's worth asking questions like:

  • Are we missing documentation?
  • Could we catch this next time with a linting rule?

Most developers prefer the well-trod happy path. It's up to the team to help each other find it.

Wynn Netherland
Wynn Netherland

Engineering Director at Adobe Creative Cloud, team builder, DFW GraphQL meetup organizer, platform nerd, author, and Jesus follower.