Shopify/packwerk

How do you deal with specs?

Closed this issue ยท 13 comments

Description
In a componentised monolith, where should specs live to avoid causing privacy errors?

To Reproduce
Create a new Rails project, create a component with a private file like components/finance/app/models/account.rb.
Write a spec for that model, where would you put it?

Expected Behaviour
Documentation should explain how to deal with tests as this is a very common issue.

Version Information

  • Packwerk: v2.0.0
  • Ruby: v2.7.5

Additional Context
Two approaches comes immediately to mind, but none of them is straightforward:

  1. Create a components subdirectory in your spec folder and put the model test there (/spec/components/finance/models/account_spec.rb). This won't work because the model above is private, so directly referencing it from spec/components/... causes a privacy violation that needs to be ignored.
  2. Put specs in a spec subdirectory of your component (components/finance/spec/models/account_spec.rb). This makes packwerk check pass, but RSpec won't look for tests in that folder by default. I managed to tweak RSpec to do so locally (with --default-path and --pattern options), but this solution is hacky and our CI, that relies on Knapsack to run parallel tests, doesn't work as expected.

How do you do this in your packwerk-powered projects?

I just realised this would have lived better as a discussion ๐Ÿ˜„. Feel free to convert it if you prefer ๐Ÿ‘

Packwerk isn't opinionated on your app's layout. This is also why the docs talk about packages, and not about components - which are opinionated packages at Shopify.

However, since that's not a helpful answer, let me talk a little about components. The default at Shopify is to have per-component tests; in your example the tests would live at components/finance/test/....

We're also not using rspec, but we've configured minitest to pick up these tests.

This layout also opens up a path forward to having separate test suites per component.

Thanks for the input @exterm and I totally get your point on the opinionated docs ๐Ÿ‘.
Appreciate you trying to help anyway. It's actually helpful knowing this is how you do it at Shopify!
I guess we'll fight a bit more with rspec/knapsack before giving up then.
If you by any chance know anyone using packwerk components with Rspec, then feel free to send them our way ๐Ÿ™ !

Hi @iMacTia , my name is Alex and I work at Gusto on the Product Infrastructure team. We love packwerk, and we use it with rspec.

We use a tool called stimpack which we created. With this tool, the layout for our packages make them look a lot like engines, and the stimpack tool will make sure all autoload paths and tests are set up as expected. See more explanation of this here: #136 (comment)

Following this layout, our tests for each package are in a spec subdirectory that mirrors the production code, much like the convention for gems or engines. Let me know if this isn't clear or if you are having issues with setting it up -- happy to provide more thoughts and guidance.

Hi @alexevanczuk, thanks for pointing me towards stimpack and for sharing #136 ๐Ÿ™!
I'll definitely have a look and try to mimic the setup in our project, will share any findings!
I'll get in touch if anything is unclear, thanks a lot!

@alexevanczuk I was taking a look at stimpack and I think I managed to get the gist of how it works. The Rspec issue we're facing is solved here (TIL Rspec.configuration.pattern!). Thanks for working on this, it looks really useful and something we could consider using as well ๐Ÿ™Œ !

What I'm not entirely sure about is how to correctly use and configure the gem, as we have alrady settled on a folder structure that might not be the same as yours (e.g. components instead of packs).
It would be great if you guys could add some VERY BASIC usage instructions, enough for someone external to be able to connect the dots and eventually dive deeper into the code if need be.

@iMacTia
Yes, we should definitely add usage instructions! Going to touch base with the author at Gusto who created the gem and see if we can pair on improving usability.

The short version is that if you are willing to use packs, then things will just work. That is -- all you need to do is include it in your Gemfile, and the "railties" (rails's API for hooking into rails on gem load) will set everything up for ya. We don't have a way to configure the root folder to be called components vs packs (at Gusto we have a components directory but its for gems only), but personally I like the idea and will look more into it.

Hey @iMacTia we added a README! https://github.com/Gusto/stimpack#readme

My teammate @ngan is working on allowing the root folder name to be configurable.

Great news! I'll keep an eye on the repo for updates, thank you ๐Ÿ™Œ!

@iMacTia In the newest version of stimpack, the root folder is now configurable! https://github.com/Gusto/stimpack#usage

@exterm Would the team feel comfortable recommending stimpack in the packwerk README as a tool to configure packs (we could clarify its not necessary to use packwerk but if used it helps remove some configuration and choice complexity)? I think it creates some sensible conventions that make using packwerk easy and help align the community a bit. Let me know your thoughts.

Somewhat separately โ€“ tools like this are why I think it could be valuable to have a gem just to specify pack locations and parse them and their package.yml files. stimpack only relies on folders of code and not package protections. I imagine packwerk and stimpack could both rely on a common interface for parsing packages which any part of the ecosystem could rely on (such as our code ownership tool which relies on stored owners in package.yml files) and packwerk becomes more about the package protections that help create and establish domain boundaries. Curious to hear your thoughts!

My gut reaction is that if we want to have a common format to specify Ruby packages, it should be gemspec ๐Ÿ˜ƒ

It'd be great if could merge the concepts of gems and packages. However, that may not be realistic, especially in any sort of manageable timeframe.

I do think it makes sense to at least mention stimpack -- it'll be useful for many people using packwerk - I'd be careful with recommendations as I'm pretty happy with how general and pattern agnostic packwerk currently is. I'd also be interested to know if @rafaelfranca has an opinion on this (specifically the idea of a gem to define and manage the package concept, as a common base for packwerk and other tools).

That's a great point @exterm . I agree -- it would be amazing long-term if we could decouple things like distribution from gem specs, so that a gem spec can define a gem and a package and a gem spec could provide an interface to support gradual modularity in the same way a package.yml does today.

I do agree that having a single convention for a ruby library/package/etc. is better than multiple, and also agree it won't come anytime soon. I do wonder if it could come sooner if we did have this format decoupled from package protections, and over time, perhaps gemspec can have inspired changes incorporated. I am also curious as to what @rafaelfranca thinks!

I also agree about stimpack -- I like that it's so general and works so flexibly with different user choices. Calling it an option rather than a recommendation makes sense to me.

Thank you for your thoughts ๐Ÿ™