Package Fatigue
What on earth do I mean by package fatigue, I hear you asking? Have you ever worked on a project and tried to do a simple thing such as bumping up a Laravel version, only to be greeted with the dreaded Composer error screen because you have a package, utilised within your project, that is only compatible with your current version of Laravel?
No bother, you think to yourself as you load up GitHub or Packagist — I’ll just update the package to the next version.
The next version does not exist, nor has it been worked on for the last two years...
Okay, well let’s just remove the package completely and replace it with our own implementation. Let’s find references within the codebase and see what I’m dealing with!
100+ references and a deep spaghetti integration throughout the codebase. F*ck it, let’s not bother upgrading at all.
Welcome to package fatigue.
This issue doesn’t just affect the PHP ecosystem. Remember the whole left-pad
package disaster in NPM? It was 11 lines of code and yet some of the internet’s largest sites utilised this package until one day, it disappeared — unleashing hell across the web.
For some reason, there’s a common tendency across companies where developers find it easier to just bring in a package without much thought as to what the repercussions might be if one day it disappeared or stopped being updated. This package then gets used more and more throughout the codebase until it becomes a first-class citizen — yet we have very little control over it.
Yes, we could fork that codebase, but then we have the issue of maintaining an entirely separate one.
My Golden Rules for Using Packages
I’m not saying we should never use packages, okay? Packages are great, and the fact people go out of their way to maintain and update them is incredible. I’m just urging people to be cautious and do some due diligence. Here’s the thought process I take:
How long would it take me to write this into the project myself?
Let’s look at multi-tenancy, for instance. I can add in Spatie Tenancy and it’s a great package with a lot of features — but do I need that level of complexity? Could I accomplish this with a trait on a model and some scopes?
If I look at Filament, on the other hand, it would take me a long time to build anything close to what Filament provides. Understanding how long it would take you to add this into the project yourself helps you decide whether or not you should be using the package in the first place.
Is it maintained?
When did the package last have an update? Are there regular updates? Are there any open issues mentioning project ownership? Ensuring that we’re relying on well-maintained packages is crucial to the stability and security of our projects.
If this package disappeared tomorrow, how hard would it be to remove?
The final point I consider is how the package will be used. If it’s going to be a core component of the entire codebase, this is a red flag — relying so heavily on something outside of my control is risky.
However, if it’s something with a simple use case that we can potentially abstract using the adapter pattern, then I’m more likely to consider using it.
Look, my goal isn’t to put people off using packages. They’re great and save a lot of time. My point is that we need to be more intentional with the packages we do bring into our systems.
If you’re unsure, try wrapping the package in an adapter within your codebase. That way you give yourself the flexibility to swap it out more easily in the future.