Anyone remember back when companies would try to be “cool” by advertising that they were looking for a “ninja” or “rock-start” software engineer? Thankfully, those days really are just memories (hopefully the days of the “10X egnineer” will go extinct soon, too). These terms were stupid as job titles because they had no bearing on what you actually did for a living. A “rock star” means that you spent some amount of time being playing in the Silver Bullet Band. And if people know that you’re a ninja, then you were really bad at it. I suppose these job titles stemmed from words people used to describe some the better developers where they worked, but there’s a difference between internal compliments and an actual role at a company. That said, the most useful role within any company is probably the programming equivalent of a plumber.
So if we’re going to introduce random new job roles that aren’t “software developer,” we should define what we mean clearly. In this case, I’m using the term “plumber” to refer to “any developer who does the crap work that nobody else wants to do.” So, basically, it’s the role of “makes everyone’s lives better” on the team.
How do you do that? Well, since the identifying trait of a “plumber” on the team is that the stuff they’re doing is the stuff other people don’t want to do, really the only step is to volunteer for the stuff that others don’t want to do. Work on automation, write documentation, find and try to resolve tech debt (keep track of it and fight for putting some of that work in every sprint), work on scoping and grooming out the vague tickets that nobody’s really sure what needs to be done with them yet. It seems thankless at first, but then everyone’s going to notice when you push something and life gets a little bit easier across the board. In short, volunteer to help with anything where you think you can contribute.
It’s a lot more tempting to take the cooler, flashier tickets. They have a lot more presumed managerial visibility, not to mention being…well, cooler. Here’s the thing though, what I’ve noticed that a lot of managers look for, is that stuff gets done, and it doesn’t cause problems. Not only that, they want to make sure that it can deployed easily, and that other people can be brought in (either to continue working on the project, or as users) easily. They may not be able to put their fingers on exactly what it is, but they’ll know that putting you on a project makes things stabler, more predictable, and just plain better. That’s the sort of thing that gets you put on the most important stuff going on. It’s also the stuff that puts you in the middle of nearly everything – architecture, design, deployments, and yes, still the coding.
It’s a lot of stress up front because you not only have your finger in a lot of pies, but your focus would be on increasing stability and reliability, so basically every problem that isn’t a standard programming bug is going to fall in your lap. Just keep pushing on and things will calm down. Similar to how we say that developers should do production support rotations to encourage fixing problems that users run into, getting involved in the things that make sure the whole development process consistently results in stable software encourages you to fix the biggest problems out there. It’s rough, but keep your head down, and focus on hitting pain points 1 at a time. Eventually, you find that you’re not putting out fires anymore. This lets you focus more on “fire prevention,” which is where you have the biggest impact on the code, as this is what makes sure things stay stable
To get started with making yourself into an indispensable “plumber,” probably the best place to start is the documentation, specifically, developer documentation. Make sure what’s already there is current, and fill in anything and everything that’s missing. Is there a README? Make sure that’s up-to-date and that anyone who clones the repo can have the project running locally in minutes. Is there an API involved? Generate an OpenAPI spec and/or a Postman collection so that there’s a handy reference to the API. Not only that, but find a way to automate that if you can. If you can export the API from the code, even better, because now you have documentation that’s automatically kept up-to-date. Start with any project you already own, and use that to set the standard. Also use it as a proving ground for any tool that helps simplify and automate managing documentation. This makes it easier for you to hand the stuff you’re currently working on off to others, and onboarding new teammates.
If your code is used by anyone else in the organization, this 1 thing will have the biggest impact on everything. Working documentation lets people answer their own questions about your code and how to use it, questions that would otherwise take the form of meeting, or a sporadic Slack barrages. Good, up-to-date project documentation is generally 1 of the last things to ever get done (if it ever gets done, which is usually the case for internal services and libraries), and as a result, there’s no good record of how to get a project up and running, or how a library or API works, or anything that a developer might need to know about the code. That means even if the code is stable, nobody can actually tell because the only thing that sticks in their head is that you need to ping specific developers on the project to get anything done. Sadly, this means getting people to read the documentation is also going to take work on your part, because internal documentation is often notoriously bad. You’re going to run into some resistance getting people to go to the documentation at first – after all, they’ve been trained from who-knows-how-long of dealing with everything from no documentation to inaccurate documentation that they can’t trust that good documentation exists. Plus, if someone can just ping a developer and get answers, why wouldn’t they, even if it is covered in the documentation? It’s the same information at first, but now they also have the benefit of an active channel for any follow-up questions.
My best advice for this is to only respond with links to the documentation for any questions that can be answered, at least in large part, by the existing documentation. The goal is to set a standard that direct developer assistance only comes for questions or issues that are not covered by existing documentation. Now we have a feedback loop where that lets you know what questions aren’t covered, which lets you know what needs to be added to the documentation so people don’t have to ask you anymore.
A focus on completely flushing out and updating the documentation will dovetail right into probably the second best thing you can do to update software “plumbing” – write scripts. This doesn’t have to be anything fancy, it can just be an executable file with nothing more than a list of commands and no logic. But any time you see a list of manual steps when you’re writing the documentation, particularly steps involving a sequence of command-line commands, dump them into a script and update the docs to say
run ./the-script.sh. Not only is it easier, but you’ve encapsulated any changes to setting up or running code so that you can change specifics about them without breaking people’s workflows, confusing users, or even having to update the documentation you just worked so hard on.
Starting to script out steps for setting up and running your code not only lets you practice a new skill (assuming you’re smarter than me and learn proper bash scripting scripting rather just writing everything that requires any custom logic in Python), but that new skill also helps gives you the ability to really start working on infrastructure and automation. That’s where the bulk of what we normally think of the software “plumbing” work lives, although as you’ve likely noticed by now, there’s a lot more to it than that. This is probably where you can have the biggest impact on productivity though. The more automating build and deployment steps, and integrating with CI/CD tools, you do, the easier it is for everyone to focus on writing code without having to deal with issues getting stuff to compile and run.
This next step is where the plumbing analogy breaks down – but get involved in anything you can help with. Not only does it help turn you into an ever-useful jack-of-all-trades, but it also gives you an understanding of what everyone does. That helps inform everything else you do – from writing documentation (what are the different levels of familiarity with this code that you can expect people to have, or different types of interest such as “I want to work on this” vs. “I just want to run it on my machine so I can test something I’m working on.”), to building some simple scripts (this is something a lot of people struggle with or is easy to screw up, so let’s put it in a script so nobody has to worry about actually doing this themselves anymore), to building automation pipelines (what does it take to deploy and run this code, and what areas could we standardize on to make our lives easier?). It rarely matters just how skilled you are at whatever part of the process you’re offering to help with, all it takes to make a positive impact is being willing to learn on the fly.
Lastly, another area you can focus on is writing automated tests and keeping them up-to-date. Now, at first glance this seem like it should have been the first item on the list of ways you can improve the pluming since it’s probably the easiest thing to do yourself and also the choice that probably involves the least amount of buy-in from other people to spend time on. It’s also the thing you can do that will make the least amount of immediate impact. The benefits of writing and maintaining unit tests come much later, after you’ve forgotten all the minor details and gotchas about the thing you’re testing now, and start messing with something only to discover that you inadvertently broke things because the tests failed. Yes, to reap those benefits later you need to write the tests now, but given the fact that the payoff to writing automated tests is to catch regressions introduced later moreso than finding bugs now, it works best when you have things calmed down and you’re in a position to try defend that calmness.
All of this sounds like you’re spending a lot of time doing a lot of stuff that in theory is covered by other jobs (technical writer, infrastructure engineer, and software engineer in testing), and not a lot of time doing regular coding (none of this lets you off the hook for regular development, trust me). The part that makes focusing on “plumbing” worthwhile is that you’re involved in the lifeblood of making the software development process work smoothly for everyone. Putting you on a team is going to be worth expanding it by several other people. Just remember, and insist on the fact, that you’re not going to be the only 1 doing all of these things. Your main role in setting these things up is in providing reference implementations and setting up the infrastructure to support good habits, like automatically generating documentation, automating setup and deployments, etc. As you start building that out, it gets easier for other people to add on to the “plumbing” as they add code, because the groundwork as already been laid out by you. Anyone who isn’t sure how to hook a new piece of code into the tool that generates the documentation, test some piece of logic, or update a piece of automation can look at how you did it earlier.
Making it easier to do all the little things that make up stable, usable software encourages everyone else to do all the little things that maintain that stability and usability going forward. Writing unit tests is a lot more bearable if you’re just updating existing tests or just adding a couple of new tests for a new function. Updating the documentation to reflect a change to the software isn’t nearly as a big a deal if you’re just changing an existing paragraph in documentation that’s already been written. This is probably the biggest impact good “plumbers” have in a software project – making the gruntwork easy enough that doing it doesn’t feel like friction.
There’s a lot of non-programming work that makes software successful, Generally, it’s the type of work that gets ignored by developers as it’s not pure code-writing, or nobody fights for it passionately enough to product owners for it to get prioritized. There’s a lot of value in being the person who gets this kind of work done on projects. Your work makes the whole team better, and enables to sort of development practices we all know we should be doing. The real difficulty in doing this, like everything else in life, is getting it started. It’s a jack-of-all-trades role, that comes with a lot of upfront stress every time you start a project. But, if you do things right, you create systems that make everyone’s lives easier, builds a personal toolkit, and a breadth of experience that makes you a software development equivalent of a first-round draft pick for any team.