This stuff is complicated (or complex, at the very least), so don't be :)
>
>> This seems to indicate
>> that there shouldn't be a publicly available MediatorMap at all
>> because you should *never* instantiate that yourself.
>
> Agreed - and we already agreed *somewhere* that we would ship RL2 with a strong health warning that classes in the impl packages are for the RL2 framework's consumption only - you should only access API / DSL packaged classes.
>
> Unfortunately if we put them in a proper 'restricted' package a la PMD then their usage inside the extensions themselves would also flag up as 'illegal' - which it isn't.
>
> This is also why it can't be packaged internally - because it has to be available for extensions (one extension might rely on other maps). We did talk about custom namespaces as well, and decided that it wasn't ideal - perhaps we need to revisit that, but I think Joel's use case shows that it's overkill.
I personally might be in favor of using a custom namespace: That's
precisely what they're for and what I'm using them for in
Swiftsuspenders. See how it took Alec quite some time to figure things
out. Sure: he might have RTFM had it existed, but whom are we kidding,
really? (Meaning: yes, some, maybe most, people won't run into this
problem because they read the docs, but many will because they just
dive in and don't read docs or forget about this part or whatever.)
>
> So the 99% rule is that unless you are an extension developer you should only import things in the API and DSL packages.
>
> Alec is a little ahead of the game, so I'm not sure we have documentation spelling that out yet, or even whether we've done our final pass through the classes to check which package each belongs in. In *most* cases those classes will have (currently) an IClaudius look to them. The exceptions (other than events and errors) being classes such as Mediator which are intended for you to extend. (Again I *like* that clarity: inject against IClaudius, but don't try to extend IClaudiuses!)
>
>> Concrete classes can implement as many interfaces as the use-case
>> requires, of course. But I (still) don't really see why MediatorMap
>> should implement IMediatorMap, which is almost exactly a one-to-one
>> mapping of MediatorMap's public interface.
>
> I think it's actually so simple that you're looking for something bigger.
>
> The mediatorMap also implements IViewHandler.
>
> The IViewHandler methods (in this case the handleView method) are not for public consumption. Their presence in the api is confusing. They are not repeated in the IMediatorMap interface (your comment about repeating in a 3rd interface confused me as we're not doing that here).
>
> The only way to restrict what the user is offered to the relevant map() unmap() etc methods is to have a smaller interface than the whole public API offered by mediatorMap. Which is what IMediatorMap is...
So isn't the MediatorMap really a
MediatorMapAndMediatorMappingViewHandler, then? It might very well be
that that is the best way to implement things by far, but then that's
exactly that: an implementation detail which should definitely be
hidden behind an interface. And this is the point at which I'd again
say that I think the MediatorMap should always what you're interacting
with and that you shouldn't care about whether it's an interface or a
class. Same with the ViewHandler, which in this case just so happen to
be implemented by the same class (and, in a default Robotlegs 2 MVCS
app, represented by the same instance, even).
The advantages of this clear-cut, role-based naming of actors in the
system seem to outweigh the downsides by far, to me, which is why I
keep on harping on them. At the same time, I'm truly convinced that
the arguments against it must be stronger than I perceive them to be:
you wouldn't hold onto them as strongly otherwise.
>
>> almost exactly a one-to-one
>> mapping of MediatorMap's public interface.
>
> The *almost* there is very important. It doesn't matter (IMO) whether it's different by one method or more than one method.
>
> Surely the intent is much more important than the implementation details?
Agreed, that's a fair point. But see above about MediatorMap then
being mis-named. (And probably conflating two separate pieces of
functionality, which might be the right choice implementation-wise.)
>
> Having decided that we want to ensure that the user is never allowed to use a method that they shouldn't be using, if the way to achieve that is through an interface, what's the actual problem?
No problem whatsoever with that.
>
> I simply cannot see where the cost is in having an interface that funnels the user into the sensible choices and stops them using the things they shouldn't be using... (once the documentation etc is complete, and the injector is restored to its more helpful behaviour). The average developer will make use of the API on the mediatorMap many, many more times than they inject it.
>
> ---
>
> An additional reason for keeping the interfaces (putting aside modular):
>
> Mocking an interface is fast, mocking a concrete class is slow. The testing I do on commands and configs is often based on mocking the maps and injector and verifying that things have been gathered from events and then mapped in the expected ways.
>
> I'm actually about to do some performance testing on mocking the injector (vs an interface for it). I will possibly end up wrapping it in a delegating class, mapping that against an interface and injecting against that myself. Which - as you can imagine - makes me a very sad panda, but I don't want the hit to my test suite if it turns out to be as significant as I think it will be.
I never heard of that problem and a quick search only turned up
performance problems with mocking classes with a long inheritance
chain and/or a very large API. Neither is true for Injector: And
interface covering it would necessarily have exactly the same amount
of public members as Injector itself. That being said, I'm looking
forward to seeing the results of your testing: facts definitely trump
idle assumptions in this (as in every other) case.