How to Detect Monkey Patches with Experimental Parser in Ruby Stdlib and Gems?

This message was imported from the Ruby/Rails Modularity Slack server. Find more info in the import thread.

Something cool with the experimental parser is it allows you to detect monkey patches. This is similar to list-definitions --ambiguous , but across the ruby stdlib and gems.

https://github.com/alexevanczuk/packs/pull/93

Let me know what you think!

cc @mclark I thought you might find this interesting!

Message originally sent by slack user U70NN25TNJA

Got chance to play with this - super cool! It definitely found some monkeypatching we weren’t aware of in specs, for instance.

It also made us rethink an approach we were making with monkeypatching that used Module.prepend as a mechanism to apply a monkeypatch, as that was hidden from this as it wasn’t available statically. (The approach basically had some safe-guards in place, for instance, a version bomb to force folks to revisit monkey patches with gem upgrades)

Message originally sent by slack user U70NN25TNJA

This is a total aside, but…

It also got me thinking about potential future uses of extensions too. For instance, could the parsing of gemdir be a path towards declaring gem dependencies for packs (which may just be a silly idea), by checking references to constants defined by gems?

Alternatively, and this is probably going beyond the spirit of packwerk, but…I could see an extension where certain constants from gems could be declared as deprecated, so that migrations between different technologies could benefit from the same leverage that we get from packwerk for modularity. For example, if you had a monolith that used sinatra and grape, but wanted to migrate to Rails routes and controllers, marking constants like Grape::API as deprecated could give us an idea of progress, provide helpful points of intervention to aid teams make the shift to Rails, etc.

It also made us rethink an approach we were making with monkeypatching that used Module.prepend as a mechanism to apply a monkeypatch

I see where you’re coming with this, although conceptually I wouldn’t give too much weight to the mechanism the library uses to detect monkey patches. That’s more circumstantial (the tool to detect monkey patches based on opening up modules/classes was already in my toolbelt), but a future implementation could/should detect all forms of monkey patching, and even allow you to configure what forms of monkey patching are acceptable. Note that in this article, your style of monkey patching is considered the “most responsible.”

For your aside…
Absolutely! That’s very much the kind of idea I had in mind for the future of something like this. I’m not sure about the implementation (should packs consider a “parsed gem” to be a sort of “virtual pack?“), but the ability to gradually manage dependencies on gems feels like it could be useful for similar reasons as gradually managing intra-app dependencies. Note that with this you wouldn’t even need to mark Grape::API as deprecated if you’re moving off of grape entirely – you could just remove it from the dependency list and all uses of the gem would be gem dependency violations. That being said, I can see a natural extension to allowing users to wrap external gems in pack configuration to have more flexibility over which constants are used.

Backing up a bit, my hope is the “packs” ecosystem can provide a path to gradually gem-ify their code. A gem has its own Gemfile, so allowing a pack to gradually declare its dependencies is definitely in this spirit. We could think of lots of other static (such as Packs/RootNamespaceIsPackName , a cop that pushes packs to have gem-like namespace conventions) or runtime (although trying to stay away from these as they’re a lot more complex and often need to run in prod) checks that help move a user to a gem. Once their code is gem-like, the user could actually convert their pack into a gem, if they want (or they can choose to keep it as a pack if they prefer having less boiler plate)

I’m hoping to wait for folks to comfortable use packs in prod and provide feedback on its core functionality before going too far down this rabbit hole, although I’d also happily support anyone who wants to get their hands dirty upstream and explore what the implementation might look like :slightly_smiling_face:

Message originally sent by slack user U70NN25TNJA

Awesome! Exciting to see that you’re already thinking ahead to futures like that :slightly_smiling_face:

On the packs in prod front…we’ve decided to experiment, and try and see how far we can get with the Rust implementation for our modularity efforts!

We’re formally beginning the very early stages of our modularity journey in our monolith this week. We’re initially going to focus on working with just a couple of teams to iterate and see how the rust implementation feels from a developer experience perspective, before a very gradual roll out to > 30 eng teams. We’ll definitely let you know any learnings and takeaways as we discover them over the coming weeks!

Message originally sent by slack user U70NN25TNJA

We figured that rather than working to try and introduce some wonky shims to Rails with packwerk, we should explore how far we could get with a tool that’s under active development and designed to work in our circumstances

Love it, thanks for the update! Keep me in the loop!

I definitely support a gradual rollout here. At Gusto, I rolled out to to all teams rather quickly. The result was that on average, there was lower conviction in and effort behind the use of packwerk, and the signal it generated was less useful than I believe would be otherwise possible. My guidance to any other orgs using packwerk would be to work closely with individual teams to ensure they’re getting value and that they can be come strong supporters/champions/evangelists of the tool. Then when it has proven successful for 1-3 teams, fanning out.

Good luck! Let me know if you or your team want to chat more (slack or zoom)!

Message originally sent by slack user U72QT6YUPFK

:wave: Hi Alex, I work with Mike on the modularity work. Nice to meet you! This week we have been playing with the packs expose-monkey-patches command a bit. It was really cool that we can see all kinds of violations from the command line output. We are wondering if you have considered adding a mechanism to record the existing monkey patches, and a way to prevent future ones from being added, kind of like a pks validate-monkey-patches.

Hey <@U72QT6YUPFK> good to meet ya!

I’m curious to experiment with a command like validate-monkey-patches, but wondering if for now we can just use a little bit of shell to save and check the output, for example:

pks expose-monkey-patches [FLAGS] > results.md
# Check if there are differences in results.md
if [[ -n $(git diff results.md) ]]; then
    echo "Differences found in results.md"
    exit 1
fi