I recently wrote about how easily you can manage your patches with composer. It’s true, it’s pretty easy! Having said that, just because it’s easy doesn’t mean you should treat patches with any less rigor than the rest of your development / devops process. This article is going to dig into that, and why it’s so so important that you don’t keep patches locally.
What Patching Implicates
Typically patches get applied as a method of “fixing” a problem ahead of a release (or because you can’t update to a new release). In general, patches are only applied to non-custom code. Why? If you have custom code in your repository that has a problem, a patch isn’t actually required to solve whatever problem. You control the source code and you can just go make a change! Patches are required in situations where you do not control the source code, meaning that:
when you pull in the dependency, it has a problem
you want to fix that problem
the only way to fix that problem is to patch the code after the dependency manager (e.g. composer) pulls in the dependency.
But this raises an interesting implication: when you’re patching something that you don’t control you’re patching a moving target. Remember, composer uses its .lock file to “lock in” hyper specific versions of a given package (good). When you patch that dependency, the patch also goes into the .lock file. Assuming the patch applies cleanly, everything gets locked in place and all is well. That is, until you attempt to update your package(s) again. It is quite possible that a patch might stop applying after an update because the source of the package has shifted.
This means that in order to update your package, you might also have to update your patch. Obviously, if you’re using a patch from the community, hopefully the community will provide an update for you as well! If you’re managing your own patch however, you may need to update / rewrite that patch yourself.
Herein lies the problem with patching: if you aren’t careful with how you are managing and applying patches, you may semi-permanently block yourself from being able to update a given package and/or commit yourself / your team to maintaining that patch in perpetuity.
How to Properly Manage Patches
This is why I say to stop maintaining local patches. It’s much the same as you having a brilliant idea (or maybe a not so brilliant idea) in your head, but never telling anyone about it. If you keep it to yourself, it’s possible that your team may come to the same conclusion as you. It’s also very possible that they would go in a totally / completely different direction! Or they may never think of it (so never do it).
Patches are exactly the same notion. If you keep the patch to yourself, you are essentially signing up for ongoing maintenance of the patch. On the other hand, if you open an issue in the issue queue for the package, you start the process of letting someone else at least help (if not outright own) the patch. Ideally, you’ll face one of three scenarios when you open an issue (with or without a patch):
Someone takes your issue and fixes it the way you want it fixed
In this situation, the system is working as intended. There’s an issue, you report it, it gets fixed (and even better, you agree with the fix).
Ultimate outcome: you don’t have to maintain a patch because the issue is now fixed in the package. This is the best possible outcome.Someone takes your issue and fixes it (but perhaps not the way you want)
In this situation, the system is still working as intended. There’s an issue, you report it, it gets fixed (and no, it wasn’t fixed the way you wanted it fixed, but it’s still fixed).
Ultimate outcome: you don’t have to maintain a patch because the issue is now fixed in the package. You may have to slightly tweak your approach / other aspects, but again, you don’t have to maintain a patch. This is the best possible outcome.The issue languishes / gets closed (for whatever reasons)
Hopefully this doesn’t happen (and if it does, it doesn’t happen often). Sometimes a maintainer will tell you they aren’t interested in fixing an issue (or they think it isn’t an issue). Sometimes a maintainer will give you a work around / point you at documentation. Sometimes nothing happens at all.
Ultimate outcome: I would advise a serious gut check in this situation. Does the workaround / other methodology help and work? If you’re going to have to significantly alter / patch this package, should you be maintaining a patch, or should you look for another alternative? Theoretically you’re not much worse off here than you would be just maintaining a local patch. I would advise posting your patch on the issue so if nothing else, other folks can take advantage of the work.
The bottom line for each of these scenarios is that you should be working in the issue queue and posting patches online.
At any given point, we want to know why a patch was implemented, what it changes, how it impacts the package, etc. This gets more and more difficult to track and maintain over time. Every time the package changes / updates, you run the risk of some (or all) of your patch no longer applying and/or no longer doing what you intended it to do. This is bad! The goal should be any time you write or apply a patch that it is temporary with the end goal to get the “thing” you are patching fixed in the upstream package.
When Should You Write Patches
Let’s talk about a few scenarios where you might need to actually write a patch:
A module doesn’t do something the way you want to do it
In this scenario, let’s imagine that the markup / css from a module isn’t lining up with your expected result. While you certainly could patch the module to change the markup, Drupal provides a number of mechanisms to allow you to override styling, change templates, and/or preprocess the output of a given page/block/node/view/etc. In this scenario you don’t have to worry about patches because you should the other tools at your disposal to work around the problem.
Note that if you absolutely must patch something, open an issue on D.O and patch it there.A module has a problem (e.g. accessibility audit failing over markup)
This is one of the most common reasons to patch. There’s a contrib module that you want to use on your project. But, as it turns out, the contrib module has a problem. Maybe it’s a minor problem, maybe it’s causing a fatal error. Whatever that problem is, it’s impacting your ability to use the module!
Can you write a patch here to fix this problem? Absolutely! Patch away. Just don’t keep that patch locally. Put it in the issue queue. Hopefully other folks will use your patch and/or help get it merged in so that you can stop maintaining it.A module has a vulnerability
Drupal has a very specific security process. This is very similar to the previous item but you should make sure if the package you are using has a dedicated security queue or process that you follow these requirements.
In Conclusion
Write all the patches you want. I’m not trying to stop you from doing that! I am trying to stop you from keeping them to yourself. Get those patches out there, let other people contribute and test, let the maintainers help commit them. Why? The goal is to get rid of the patches! And, open source communities only thrive when folks (like you and me) contribute improvements to the software. Patching is an important part of that process.
If you have some fear, uncertainty, and doubt (FUD) about showing people your patches, do this for me! Consider: are you nervous because
you think you’re too new, don’t have authority, etc.? get over it! communities thrive on new contributors and I hope you take the leap
you’re doing something hacky, against best practices, being lazy, or publicly showing your work for whatever reason? I would argue that if you aren’t willing to show something more broadly it shouldn’t be in your codebase. If we’re not following standards / best practices, if you are “hacking on something” and you don’t want anyone else to see it, then you probably shouldn’t be maintaining this code as a patch locally, either.
Dependency trees can be massive, and with the upcoming Drupal 10 release PHP 8.1 could have a significant impact on your project.