-
Notifications
You must be signed in to change notification settings - Fork 119
Mark non-documented API as explicitly private #276
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
| module Packwerk | ||
| extend ActiveSupport::Autoload | ||
|
|
||
| # Public APIs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I chose these APIs with these rationales:
Checker
API for extending checkers
Cli
Main API for calling packwerk right now. Eventually we might want API like Packwerk.check instead of using the CLI, but this is the de-facto API.
Offense
Part of the interface for OffensesFormatter
OffensesFormatter
API for extending offenses formatter
OutputStyle
Implementation of this needs to be passed into CLI
Package, PackageSet, PackageTodo
API for getting information about YML files
Parsers
Contains documented API for Packwerk::Parsers::Factory.erb_parser_class=(...), which is the current API for substituting the ERB parser.
The hope is that #243 will allow us to mark this API as private.
This module also contains ParserInterface as well. With the above PR, we'd allow the interface to be public but the rest to be private.
Reference, ReferenceOffense
Part of the API to Checker
Result
Return value of CLI
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Result is overloaded, I vote to nest the toplevel result in CLI. We should also nest the app validator result in Validator instead, especially if we use it in the interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah makes sense, changed!
|
|
||
| # Private APIs | ||
| # Please submit an issue if you have a use-case for these | ||
| autoload :ApplicationLoadPaths |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is more easily read commit by commit. A previous commit sorts these then another separates them.
88a66c6 to
3440c34
Compare
gmcgibbon
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree with the shape of this API, but I think we need to label each class as @api private and make sure the public ones are documented (at least at the class/module level). Though, maybe private_constant does this for us. @rafaelfranca do you have an opinion on using private_constant here?
Also, can we confirm private_constant works on autoloaded constants without loading them?
3440c34 to
0b584f6
Compare
Happy to use another construct if the team prefers and would love to learn about the pros/cons as you see them. I'm also generally really curious what you think of the
Yep -- I verified that. You can see my verification in the commit history, where I throw a |
|
I created the alternate implementation where I nest everything under Let me know what you think! The diff is a bit messy when not viewed commit by commit since it looks like a bunch of files are deleted/renamed, so its easier to just review the last four commits (since that PR is based off of this one) one by one. |
USAGE.md
Outdated
| While `packwerk` ships with its own offense formatter, you may specify a custom one in your configuration file via the `offenses_formatter:` key. Your custom formatter will be used when `bin/packwerk check` is run. | ||
|
|
||
| Firstly, you'll need to create an `OffensesFormatter` class that includes `Packwerk::OffensesFormatter`. You can use [`Packwerk::Formatters::OffensesFormatter`](lib/packwerk/formatters/offenses_formatter.rb) as a point of reference for this. Then, in the `require` directive described above, you'll want to tell `packwerk` about it: | ||
| Firstly, you'll need to create an `OffensesFormatter` class that includes `Packwerk::OffensesFormatter`. You can use [`Formatters::OffensesFormatter`](lib/packwerk/formatters/offenses_formatter.rb) as a point of reference for this. Then, in the `require` directive described above, you'll want to tell `packwerk` about it: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be reverted. We should fully qualify constants in the USAGE doc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For sure, I think this just came from an errant find and replace.
lib/packwerk.rb
Outdated
| # Private APIs | ||
| # Please submit an issue if you have a use-case for these | ||
| autoload :ApplicationLoadPaths | ||
| private_constant :ApplicationLoadPaths |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should move these declarations to the files they are loading. This is because if we want to refactor to use a documentation tool to define our API boundaries we can more easily do so (instead of referencing the main entrypoint, it is clear via search that a module/file is private).
So what I'm saying is I think this line should be moved to lib/packwerk/application_load_paths.rb under the class definition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure thing
| class << self | ||
| def parse(source) | ||
| Packwerk::Parsers::Ruby.new.call(io: StringIO.new(source)) | ||
| module Packwerk |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be in a packwerk folder. Same with all the other test helpers that have packwerk module nesting. This one should also be moved to support.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mind if we move test files in a subsequent PRs?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is noisy enough, we can do it later.
| private | ||
|
|
||
| sig { returns(Packwerk::ApplicationValidator) } | ||
| sig { returns(ApplicationValidator) } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like unit tests also are missing the toplevel packwerk folder to match the module nesting. We aren't autoloading our tests, but this would make it easier if we ever chose to.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment – let me know if you're okay with us moving test files in another PR.
lib/packwerk.rb
Outdated
| autoload :ParseRun | ||
| autoload :UnresolvedReference | ||
| autoload :Reference | ||
| private_constant :ParseRun |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've always wondered why this is called ParseRun. Should we just rename it to Run? It is private API so we can do this for free later if need be.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure about that one either. Personally, my preference would be to just have API on packwerk directly, e.g.
Packwerk.check
Packwerk.update_todo
This feels like the best UX to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be, but these methods aren't called in code, so I don't think toplevel access matters much. We can also potentially do this later.
I think it makes sense to keep the approach in this PR (#276). In my opinion, naming and visibility should be separate concerns. While I understand and appreciate the explicit nature of using a |
beacfea to
c5bc226
Compare
eaeac74 to
e1da318
Compare
What are you trying to accomplish?
This PR addresses a portion of #275.
In this PR, I mark many constants as explicitly private API.
PR is best reviewed commit by commit with hide whitespace changes set to true.
Alternate implementation: https://github.com/Shopify/packwerk/pull/282/commits
What approach did you choose and why?
I used
private_constantas the vanilla Ruby way to mark something as private. I did this instead of something like:nodoc:, which requires folks to either read the source code or look at code with YARD.private_constantgives the user unavoidable feedback when their code is executed.I separated out the main autoloads into two lists – one to autoload public API and one to autoload private API. This is mostly for the benefit of maintainers to easily see what APIs need to stay supported and what can change.
As a result of this, I needed to change references to these constants to omit the leading
Packwerknamespace, which would constitute a private (and therefore not allowed) reference.I had an alternate idea, which was to create a module
Packwerk::Privatewhere we could move all of our constants. With this approach, we could have a singleprivate_constant :Privatecall that would mark everything as private. I like this pattern because it would mean all public API would be in one place that can easily be seen, and private things would be in their own explicit location. I'd be happy to apply this pattern instead if other maintainers prefer it.Here is that implementation: https://github.com/Shopify/packwerk/pull/282/commits
What should reviewers focus on?
Type of Change
Additional Release Notes
Include any notes here to include in the release description. For example, if you selected "breaking change" above, leave notes on how users can transition to this version.
If no additional notes are necessary, delete this section or leave it unchanged.
This is a breaking change because we've marked a lot of things as private. I've left many things as public where we know we are exposing a public API, but its possible some folks are using some of these constants that are currently private. My hope was that they could release an issue against packwerk 3.0 if they have a use-case for these private constants.
Checklist