Skip to main content
Nick Scialli home page

Engineering for maintainability

Software engineering is hard. Sometimes it feels like a herculean effort just to ship something that works. One of the biggest mistakes I see engineers of all levels make is stopping development work once their feature is done.

This is a mistake because it's typically not only our job to produce working software. We also have to maintain it. This means working code isn't enough! We should also strive to ship maintainable code.

What is maintainable code? I consider maintenance to include at least the following tasks:

Code that satisfies an initial set of requirements doesn't inherently satisfy any of these maintenance tasks! Here I'll talk about some ways I like to write code to satisfy each of these points.

Troubleshooting #

To help with troubleshooting, the code or feature should be well-integrated into whatever observability or monitoring tool the team uses. Some of this comes for free—for example, most Application Performance Monitoring (APM) tools will auto-instrument all network requests, including ones for your new feature.

This might not be enough! In some cases, I have added some custom events or traces within feature code that will give some clues to whoever is troubleshooting. Additionally, I will surfacing user-facing error messages that might help the user self-serve a solution, if possible. Finally, I'll also try to add and error code or trace identifier to user-facing errors that can immediately point engineers to the exact type of problem and exact instance of issues in the observability platform.

Monitoring feature usage and performance #

When shipping a feature, I like to put together a feature dashboard that the feature team (engineers, product managers, anyone else) can use to monitor the feature's performance. What goes into this dashboard depends a lot on the feature itself, but I like to include things like usage metrics, error rates (by endpoint or otherwise), request timings, and user flows. This dashboard can be derived from observability and/or product metric systems, depending on what the team uses.

Ideally, some of this information will be useful to the product manager in verifying the feature is performing well. At the very least, it should give the feature team a real-time glimpse into how the new feature is doing.

Onboarding new developers #

Onboarding to a new codebase or feature is tough. It's even harder if the feature isn't well-documented. Part of an engineers job, and one that's often neglected, is documentation. This documentation may come in the form of inline comments, markdown files, technical specs, and tests.

There is a notion of "self-documenting code." I think well-written code is somewhat self-documenting, but it's really not efficient: there are very few people who will understand feature code from reading the code itself better than some good documentation about the feature.

Updating the feature #

Features almost always get updated. Perhaps the customers want some additional, related functionality. Maybe there were some bugs in the initial implementation. When initially writing feature code, it's important to think about how easy the code will be to update.

For example, it's possible an initial, working version of some feature includes 1,000 lines of procedural code in a single file (hey, no judgment!). Sure, this code may function properly, but it will likely be a nightmare to extend. After getting code to a functional state, it's important to review the code to see if it can be broken down into smaller functions or methods, use existing utilities, and is well-tested.

Making sure these things happen #

It can be hard keeping yourself accountable to engineer code for maintainability. It's even tougher when there's a whole team merging features—and when that team is under time pressure to ship.

A couple ways I like to make sure the team focuses on maintainability are:

There is a team culture aspect to this too. Template sections will turn into paper exercises and PR checklist items will get ignore if the team doesn't buy in to the idea that maintainable code is good code.

If you enjoyed this article, consider subscribing on Feedly or your favorite RSS consumer. If you'd like to chat, I'm most active on Bluesky.