Jason Lengstorf, VP of Developer Experience at Netlify, says there are two types of code work.
- Building out the actual vision of the business (building value)
- Building underlying boilerplate, configuration, and glue code that otherwise blocks building out the vision (foundational toil).
In both cases, code quality is paramount.
Lengstorf shares his insights on the most efficient ways to ensure quality code — and spend more time building value.
Why is it important to create automated processes for managing code quality?
Lengstorf: An analogy for this is a conveyor belt oven. Is it more expensive than a regular oven? Sure! But it eliminates a huge amount of cognitive load for the people in the kitchen — they can’t accidentally burn something if they get caught up in another task. The introduction of the right tool completely eliminates a category of failure and attention. People are freed up to focus on their other tasks, which are more valuable.
How do you manage code quality?
Lengstorf: To me, “code quality” is a blanket term for finding the right balance between safety and velocity. We want to be confident that what we ship isn’t going to break, and when it does, break, we want to be confident that we’ll discover the problem and ship a fix quickly.
Optimizing for safety can cause huge slowdowns in velocity. We add unit test coverage requirements, linting checks in our CI/CD, type checking, integration testing, snapshot testing, pre- and post-commit hooks, and a whole bunch of safety checks — and each one adds time and cognitive load for the developers using them. All of this reduces shipping velocity.
Optimizing for velocity leads to cutting corners, shipping sloppy code to production, and other choices that result in tech debt — and that also hugely reduces shipping velocity (but later down the road, which often makes it easy to ignore at first).
Great code quality is putting the minimum safety checks in place — and using the right tools to keep those checks fast — so that the team is confident, but remembering that safety is only useful if it’s in service of shipping. If the process becomes too cumbersome, devs will work around it and/or drag their feet about shipping because they don’t want to deal with the hoops. Getting the balance right means the team is as fast and as safe as they can reasonably be, and that’s a sign of high-quality code.
Which members of your team are responsible for code quality?
Lengstorf: Every team member is responsible for code quality in the cultural sense. We need to be fully bought into what “code quality” means on our team and be willing to follow the processes and guidelines that were put into place.
In addition to a culture of code quality, there should be a handful of folks on an internal tools team whose job is watching the dev workflow, spotting issues and pain points, and helping smooth those over either by improving the existing tooling, replacing troublesome tools with less cumbersome options, and/or removing redundant or unnecessary checks to reduce the cognitive burden on production teams.
How do you streamline their workflows?
Lengstorf: Set up processes that provide feedback as early in the process as possible. For example, running a code linter in CI/CD can be extremely frustrating — it takes minutes (or sometimes hours) to get feedback from the CI/CD process, which breaks flow for the developer. A linter should be running in the developer’s IDE so they catch issues before they even save. (Or even better: use Prettier and auto-fix issues and never fail a build on linting again.)
Choose platforms that give developers feedback in a way that’s as close to production as possible. This is one of the things we’ve worked hard on at Netlify: devs get a local dev experience through our CLI that matches the deploy preview environment that matches the production environment — devs don’t have to keep environmental differences in mind and can be confident that if their code works locally, it’ll work in staging and production, too.
Be realistic about what checks are actually adding value. Does 100 percent test coverage actually make the code better? Or does it slow down the team in a way that 80 percent coverage wouldn’t — and for no measurable gain other than a “perfect score”?
How much time can it save?
Lengstorf: In my own experience, putting the right systems in place saves huge amounts of time. This happens in a few ways.
- Developers get feedback quickly as they develop, so they stay in the flow and have fewer failed PR builds.
- By choosing tools that abstract away the boilerplate, developers spend the majority of their time building actual features instead of knocking out foundational toil tickets that are repetitive and not a differentiating feature. This means that devs working the same number of hours end up delivering more valuable work by setting them up with the right underlying platforms and tooling.
- A high-quality CI/CD flow that only runs useful checks is faster and less frustrating. This cuts down on the amount of time waiting for builds to complete — those saved minutes add up quickly over the course of a year!
- Striking the right balance on code quality creates a culture of building quality code — this means less tech debt accumulates over time, which avoids the major challenge many teams have where they have to trade off between getting something delivered on time with crappy code or missing the deadline to try and build it in a more maintainable way.
This means the speed gains are sustainable — and that’s before you factor in things like higher retention of team members because they’re not frustrated by the processes and codebase.