Need help configuring "packs" gem for monolith app and preventing private code usage - Issue with validation and setup

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

Message originally sent by slack user U73KUSJ2V5Q

Hello, need some support of the initial configuration of “packs” gem (or I need just packwerk?). My app is already a pretty big monolith and we want to start moving some code into components/packs, just to split domains.

Basically, I’m facing now an issue with how to validate that private code from pack cannot be used in the existing codebase (app/models for example)

I have posted an issue here: https://github.com/rubyatscale/packs/issues/144 (hope it’s a good place).

Maybe it’s a silly question, but there are not many articles in the internet on how to setup everything.

there are not many articles in the internet on how to setup everything

You got that right!

Message originally sent by slack user U73931AEHVB

Note that privacy checks are not actually a part of core packwerk. If you want to use them, you need to include packwerk-extensions

Message originally sent by slack user U73KUSJ2V5Q

yeah, thanks for reply, moving slowly, now I have

my Config (I also tried enforce_privacy: true or strict)

And I have such code in app/models/some_file.rb
(CalculateExpectedShipmentData not in public)

def predicted_delivery_details
      Rails.cache.fetch("delivery_promise_predicted_delivery_details_id_#{merchant.id}_#{warehouse.id}",
        expires_at: Time.current.end_of_day) do
          ExpectedShipmentData::CalculateExpectedShipmentData.new(warehouse:1, merchant:1).call
      end
    end

Message originally sent by slack user U73KUSJ2V5Q

do you know how I can trigger validation error of ExpectedShipmentData::CalculateExpectedShipmentData use in the model?

Message originally sent by slack user U73KUSJ2V5Q

I’m really confused, I tried to just add another package, and use inside it “private” class from first package

Message originally sent by slack user U73KUSJ2V5Q

because it shows me no violations

Message originally sent by slack user U70TIGAX94P

IMO you don’t need rubyatscale/packs. A simpler approach with engines is described by Julián Pinzón Eslava in https://www.youtube.com/watch?v=StDoHXO8H6E and discussed in https://github.com/Shopify/packwerk/discussions/361. That pattern is very close to what we did at Shopify.

rubyatscale/packs is a bit more complex under the hood and more opinionated, which has advantages (more convenience) and disadvantages (less flexibility). I’d personally lean towards the simpler solution.

There are also two blog posts from Shopify that talk about the danger of privacy enforcement in an otherwise tightly entangled monolith:

https://shopify.engineering/shopify-monolith
https://railsatscale.com/2024-01-26-a-packwerk-retrospective/

I’d recommend starting with disentangling the dependencies. That’s also the reason why privacy enforcement was removed from packwerk itself and moved into an extension.

Furthermore, packwerk and the rubyatscale/packs tooling is geared towards making the monolith easier to think about, gradually. If you think you can go from the current state to fully isolated (maybe in small parts) in a few weeks, you probably want to take a slightly different approach, for example starting with separated test suites. Packwerk can help you gradually get closer to that goal but because of its focus on static dependencies you shouldn’t overestimate its ability to keep code from executing together.

Message originally sent by slack user U73KUSJ2V5Q

Thanks, I’ll take a look into it.

Just a few more questions:
• do you know if there is an example app with few components (a little bit more complex then 1 mentioned in 1m video, but even that app full source code is not available)
• is it possible to catch a package dependency from a component used inside a regular model (outside any component)?
PS: maybe some of the answers in the resources above, but still want to check.

Thank you

Message originally sent by slack user U70TIGAX94P

Sadly I don’t know of an example app. Maybe I should try to create one. I don’t have a concrete reason though other than convincing people that it’s possible :smile:

To your second question - it sounds like you should just start experimenting!

If you set up packwerk, you can drop a package.yml into any folder and see what happens. Any folder with a package.yml is a package.

You‘ll see that packwerk initialisation creates a package.yml in the root folder of your app, which means that everything is in the root package by default.

Message originally sent by slack user U73KUSJ2V5Q

thanks for the update,
its very difficult for me understand what is wrong, or this is expected result

because I receive:

No offenses detected
No stale violations detected

but should not I receive an error about using EstimatedShipmentData::Shipment in Prediction class?

Message originally sent by slack user U70TIGAX94P

I’d be curious to see how you’ve set up your auto load paths. There’s probably a mistake in there.

Can you run rake zeitwerk:check successfully on that app?

Message originally sent by slack user U73KUSJ2V5Q

hmm, correct, moved the components folder to “app”
and now I see this