This message was imported from the Ruby/Rails Modularity Slack server. Find more info in the import thread.
Message originally sent by slack user U78YFUTNTH5
is packwerk opinionated around db transactions across different components?
This message was imported from the Ruby/Rails Modularity Slack server. Find more info in the import thread.
Message originally sent by slack user U78YFUTNTH5
is packwerk opinionated around db transactions across different components?
Message originally sent by slack user U783MOJYF8Z
Hey Andy! One of the packwerk authors here. packwerk
itself doesn’t know or care about transactions. It works purely on constant references.
Message originally sent by slack user U783MOJYF8Z
At Shopify we currently still do have transactions across components, although we’ve thought about building tooling to block them.
Message originally sent by slack user U78YFUTNTH5
cool, and what’s the rationale to block them? just to break up dependencies? or are you looking to split datastores? …
Well if you have one database with every table inside, boundaries might not be violated at the code level but could be violated at the Db level
Message originally sent by slack user U783MOJYF8Z
This is around the idea of DDD aggregates… you need transaction boundaries somewhere, if you have a large app. Otherwise you’re just accumulating reasons to roll back and delay the commit forever, and then at some point it gets really hard to commit the transaction.
If you haven’t encountered that problem yet you probably shouldn’t spend too much energy on it
Message originally sent by slack user U78YFUTNTH5
fair enough… so yeah one of the biggest reasons for me personally to stay in my monolith is db transactions…
good to understand the points you guys brought up, thanks
Message originally sent by slack user U783MOJYF8Z
We’ve had a few cases with transactions timing out because there was way too much stuff happening and nobody knew anymore what it was, so there had to be an investigation which took quite a while.
There is also the issue of encapsulation. If you have transactions across components you have the implicit assumption that the functionality you execute in another component persists its result to the same database that your component is using. You’re assuming knowledge of implementation, which waters down the boundary.
E.g. component A calls component B to do something, within a transaction opened by A. Sometimes it’s rolled back by A (or B) and everything is fine and consistent. But now B decides to persist the relevant data in redis instead of MySQL. Or B decides to also enqueue a background job (that won’t be rolled back with the transaction).
From the perspective of A this can be very confusing.
Message originally sent by slack user U78YFUTNTH5
yup that totally makes sense… thanks
one more question:
https://kellysutton.com/2019/10/29/taming-large-rails-codebases-with-private-activerecord-models.html
this is basically covering the “loophole” that anyone can access your data models via associations… would packwerk essentially cover this concern if you only allowed your module to access that Model Constant?
Message originally sent by slack user U783MOJYF8Z
But I think it’s important to remember we’re acting on a spectrum here between no boundaries and super hard boundaries, and the right tradeoff will be a different point of the spectrum for every specific case
Message originally sent by slack user U783MOJYF8Z
The technique in Kelly’s blog post, as far as I understand it, “solves” the association problem by saying that associations can only exist within a certain context. Packwerk can do the same; if a package’s active record models are not public, models in other packages will not be able to have associations to them.
Message originally sent by slack user U783MOJYF8Z
both approaches allow to keep an active record model private to a certain context.
Message originally sent by slack user U783MOJYF8Z
Packwerk is specifically geared towards introducing boundaries in existing code gradually, so you could start with a situation in which cross-package associations exist, and use packwerk to first stop the bleeding (prevent introduction of new ones), and then work off the deprecation list generated by it to remove them one by one.
Message originally sent by slack user U783MOJYF8Z
private_constant
is also a useful tool but it’s not as flexible.
Message originally sent by slack user U78YFUTNTH5
aye awesome, thanks!
Message originally sent by slack user U78YFUTNTH5
wait no i’m not done yet . in packwerk…
if i have ModelA in my DomainA, and DomainB needs read but not write to that model.
would you have to have some kind of public-facing ValueObjectA (data from ModelA) that DomainB can legally have a dependency on? (while not getting access to the ModelA to do any writes)
Message excluded from import.
Message excluded from import.
Message originally sent by slack user U78YFUTNTH5
hm i’m not grasping the nuance here…
so let’s say we have Books and Stores “domains?” each with their own models.
I’d like to control access so that Stores can query Books for a list of books by some author, but not able to change the author.
here i think packwerk’s dependency tree would allow a dependency from the Stores “domain?” to some public search method in Books as well as the BookModel since that gets returned in a list by that method. But having access to that model means i can update it now.
so what i’m wondering is that in this paradigm, would i need to have a BookDataObject so that Stores can legally have a dependency on that BookDataObject but not on BookModel
Message excluded from import.