Connection is exactly the example I was thinking about
Yes and you are force telling your application that there’s a connection/user even when there’s not.
Actually, if I set userId for one package but not for the other I end up in a situation of inconsistency. If I set it “globally”, I can be sure that every piece of business logic receives the right userId.
This is only by consequence of and a solution to the problem actually created by the “not better” design.
What I mean by better is that the established best practices in software design around server methods (instance/connection/lifecycle handlers, domain models, business logic controllers, utility functions, data access etc) suggest keeping these methods as reliant as possible to their direct inputs/arguments.
There of course are patterns that either sidestep this because it is either more convenient for a specific part of the software or it makes more sense from another point of view like broader or cross-cutting concerns, testing etc. Patterns like singleton and dependency injection come to play at this point.
Environment is also another special piece of this design puzzle and again, best practices suggest keeping a single entry point in your app for such environment and directly passing in that entry point as a reference to your methods.
Now Meteor’s server context is also one of these patterns where the initial connection is grabbed, sanitized, formatted and passed on to the chain of execution. If you follow Meteor’s source code, you’ll see that even this globally available context is passed on to high level methods (publications, methods, etc) as instance methods, even though they still can be obtained from the global namespace. And then, officially endorsed packages like validated-methods take a step even further to convert those to function arguments because arguments make up a contract that you can validate against and they also serve as self documentation.
Now, when you pass these arguments explicitly (instead of assuming/shoehorning them to a global namespace) your program execution and testing will become more predictable, testable and maintainable. More debuggable even more so without having to attach arbitrary debugging watchers to seemingly unrelated parts of your app.
Now, coming back to the 3rd party packages example, a good package should provide you means to override the context by way of arguments or supplementary configuration because of all I’ve said above. Collection hooks does that by way of a configuration option where you can use it either globally (more towards your preference) or per instance/connection lifecycle.
By using more instance specific overrides on each distinct part of the app, rather than providing a global override, you won’t need to be aware of the global set up of your app and can isolate development, testing, debugging and maintenance to that single part of your app and it is easy for anyone reading your code to immediately see the outward bounds of that part of the app.
All this being said, best practices are not necessarily quantative things; if you and your team are comfortable with one way of doing things, that’s probably the most effective way of doing things for you for this time, until you yourself feel something else is fit to replace that. Perhaps this discussion can lead to that, or not. In either case, this topic should serve other readers as a succint reference to see alternative views to a given task