Development isn’t over until it’s packaged
Most software development I’ve done has been utilities for highly specific workflows. I’ve written code to ensure that metadata for a company’s custom file format gets copied along with the rest of the data when the file gets archived, code that ensures a search field doesn’t mangle input, lots of Git hooks, file converters, parsers, and of course my fair share of dirty hacks. Because most software projects I work on are designed for a specific task, very few of them have required packaging. My utilities have been either integrated into a larger code base I’m not responsible for, or else distributed across an infrastructure by an admin. It’s like a magic trick, which has made my life conveniently easier but, as magic does, it has also tricked me into thinking that my development work is done once I can prove that my code does its job. The reality is that code development isn’t actually done until you can deliver it to your users in a format they can install.
I don’t think I’m alone in forgetting that software delivery is the real final product. There are many reasons some developers stop short of providing an installable package for the code they’ve worked on for weeks or months or years. First of all, packaging is work, and after writing and troubleshooting code for months, sometimes you just want your work to be over just as soon as everything functions as expected. Secondly, there are a lot of software package formats out there, regardless of what platform you’re delivering to. However, I view packaging as part of quality assurance. There are lots of benefits you gain by packaging your code into an installer, and you don’t have to target every package format. In fact, you get the benefits of packaging by creating just one package.
Checking for consistency
When you package your code as an installable file, whether it’s an RPM file or a Bash script or a Flatpak or AppImage or EXE or MSI or anything else, you are checking your code base for consistency. Pick whatever package format you’re most comfortable with, or the one you think represents the bulk of your target audience, and you’re sure to find that the package tooling expects to be automated. Nobody wants to start packaging from scratch every time they update code, so naturally packaging tools are designed to be configured once for a specific code base and then to create updated packages each time the code base is updated. If you’re building a package for your project and discover that you have to manually intervene, then you’ve discovered a bug in your code.
Imagine that you’ve got a project repository with a name in camel-case. You hadn’t noticed before, but your code refers to itself in a mix of lowercase and camel-case. Your package build grinds to a halt because a variable used by the packaging tools suddenly can’t find your code base because it was set to a lowercase title but the archive of your code uses camel-case. If this happens to you, it’s also going to happen for every software packager trying to help you deliver your project to their users. Fix it for yourself, and you’ve fixed it for everyone.
Discover surprise dependencies
For decades, one of the most common problems of software troubleshooting has been the phrase “well, it works on my machine.” No matter how many tools we developers have at our disposal to make it easy to build and run software on a clean system, it’s still common to accidentally deliver software with surprise dependencies. It’s easy to forget to revert to a clean snapshot in a virtual machine, or to use a container that just happens to have a more recent version of a library than you’d realised, or to get the path of an important executable wrong in a script, or to forget that not all computers ship with a thing you take for granted.
Not all packaging tools are immune to t