Not only working around proguard, but Minecraft mods are built on top of an incredibly cool and flexible runtime class file rewriting framework that means that each JAR can use simple declarative annotations like @Inject to rewrite minecraft methods on the fly when their mod is loaded or unloaded. This massively revolutionized mod development, which was previously reliant on tens of thousands of lines of manually compiled patches that would create "modding APIs" for developers to use. Putting the patching tools in the hands of the mod developers has really opened up so many more doors.
Minecraft also has a plugin system based around JSON file datapacks, but it's a lot more limited. It's more at the level of scope of adding a few cool features to custom maps then completely modding the game.
The devs for Java Edition really have mods in mind nowadays.
- They left in the code debug features that they used to strip out.
- They left in the code their testing infrastructure that they used to strip out as well.
- They started making everything namespaced to differentiate contents between mods (like in this week's snapshot they made gamerules namespaced with the "minecraft:" prefix like items and blocks and whatnot)
- They are adding a lot more "building blocks" type features that both allow new /easier things in datapacks, and in mods as well.
Method patching with Mixins is less needed now because the game's internal APIs are more versatile than ever.
That's definitely true, and I think that's a testament to Minecraft / Java's strong OO design—it dovetails very nicely with the Open/Close principle. However my view is that for a mod to be a mod, there's always going to be stuff that you can't/shouldn't implement just with datapacks—whether that's complex rendering features, new entity logic, or whatever. The Mixin processor makes it really easy to build these kinds of features in a very compatible way
These tools sound very powerful, could they find use for other Java codebases?
I don't know where you'd use it besides modding, but it is a general-purpose framework: https://github.com/SpongePowered/Mixin
Other codebases don't tend to need those tools, because they already use frameworks like Spring or Micronaut which have such features built-in. Usually without bytecode rewriting and with more concern given to API definition.
For example, in Micronaut (which is what I'm more familiar with) you can use @Replace or a BeanCreatedListener to swap out objects at injection time with compatible objects you provide. If a use-site injects Collection<SomeInterface> you can just implement that interface yourself, annotate your class with @Singleton or @Prototype and now your object will appear in those collections. You can use @Order to control the ordering of that collection too to ensure your code runs before the other implementations. And so on - there's lots of ways to write code that modifies the execution of other code, whilst still being understandable and debuggable.
You still need quite a lot of mixins / modified code to actually do useful things. Mojang isn't always making things unnecessarily extensible, just extensible enough for them to keep updating the game.
They've also been working with a lot of modders on the rendering engine over the past year or two.