Re: Component Models and Encapsulation (was Re: Component Model: Landing Experimental Shadow DOM API in WebKit)

On Jun 30, 2011, at 1:03 PM, Dimitri Glazkov wrote:

> Maciej, as promised on #whatwg, here's a more thorough review of your
> proposal. I am in agreement in the first parts of your email, so I am
> going to skip those.
> 
>> == Are there other limitations created by the lack of encapsulation? ==
>> 
>> My understanding is yes, there are some serious limitations:
>> 
>> (1) It won't be possible (according to Dmitri) to attach a binding to an object that has a native shadow DOM in the implementation (e.g. form controls). That's because there can only be one shadow root, and form controls have already used it internally and made it private. This seems like a huge limitation. The ability to attach bindings/components to form elements is potentially a huge win - authors can use the correct semantic element instead of div soup, but still have the total control over look and feel from a custom script-based implementation.
>> 
>> (2) Attaching more than one binding with this approach is a huge hazard. You'll either inadvertently blow away the previous, or won't be able to attach more than one, or if your coding is sloppy, may end up mangling both of them.
>> 
>> I think these two limitations are intrinsic to the approach, not incidental.
> 
> I would like to frame this problem as "multiple-vs-single shadow tree
> per element".
> 
> Encapsulation is achievable with single shadow tree per element by
> removing access via webkitShadow. You can discover whether a tree
> exists (by the fact that an exception is thrown when you attempt to
> set webkitShadow), but that's hardly breaking encapsulation.
> 
> The issues you've described above are indeed real -- if you view
> adding new behavior to elements a process of "binding", that is
> something added to existing elements, possibly more than once. If we
> decide that this the correct way to view attaching behavior, we
> definitely need to fix this.
> 
> I attempted to articulate a different view here
> http://lists.w3.org/Archives/Public/public-webapps/2011JanMar/0941.html.
> Here, adding new behavior to elements means creating a sub-class of an
> element. This should be a very familiar programming concept, probably
> more understood than the decorator or mixin-like "binding" approach.

How would your "subclass" idea resolve the two problems above?

> 
> For the key use case of UI widgets, sub-classing is very natural. I
> take a div, and sub-class it into a hovercard
> (http://blog.twitter.com/2010/02/flying-around-with-hovercards.html).
> I rarely bind a hovercard behavior to some random element -- not just
> because I typically don't need to, but also because I expect a certain
> behavior from the base element from which to build on. Binding a
> hovercard to an element that doesn't display its children (like img or
> input) is useless, since I want to append child nodes to display that
> user info.
> 
> I could then make superhovercard by extending the hovercard. The
> single shadow DOM tree works perfectly in this case, because you
> either:
> 1) inherit the tree of the subclass and add behavior;
> 2) override it.
> 
> In cases where you truly need a decorator, use composition. Once we
> have the basics going, we may contemplate concepts like <inherited>
> (http://dev.w3.org/2006/xbl2/#the-inherited-element) to make
> sub-classing more convenient.
> 
> Sub-classing as a programming model is well-understood, and easy to grasp.
> 
> On the other hand, the decorators are less known and certainly carry
> hidden pains. How do you resolve API conflicts (two bindings have two
> properties/functions by the same name)? As a developer, how do you
> ensure a stable order of bindings (bindings competing for the z-index
> and depending on the order of they are initialized, for example)?

I think decorators have valid use cases. For example, let's say I want to make a component that extracts microformat or microdata marked up content from an element and present hover UI to allow handy access to it. For example, it could extract addresses and offer map links. I would want this to work on any element, even if the element already has an active behavior implemented by a component. I should not have to "subclass" every type of element I may want to apply this to. It's especially problematic if you have to "subclass" even different kinds of built in elements. Do I need separate subclasses for div, span, address, section p, and whatever other kind of element I imagine this applying to? That doesn't seem so great.

You are correct that figuring out how multiple bindings work is tricky. But even if we choose not to do it, making components truly encapsulated does not make it any harder to have a one-binding-only model with no inheritance.


>> Notice that this scheme is not significantly more complex to use, spec or implement than the shadow/shadowHost proposal. And it provides a number of advantages:
>> 
>> A) True encapsulation is possible, indeed it is the easy default path. The component provider has to go out of its way to deliberately break encapsulation, though of course it can if it wants to.
> 
> Yup.
> 
>> B) Binding is atomic - the shadow root is not built up incrementally so you can't have a half-built binding.
> 
> I am not sure what's the danger here. Are you trying to protect the
> author from displaying the shadow subtree while it's still being
> built?

My experience with API design is: it's better to design APIs so that it's not possible to use them wrong. It's better not to 

> 
>> C) Has a natural extension to allowing more than one binding on an element, having a stacking behavior like XBL.
> 
> Given discussion above, I don't see this as an advantage.
> 
>> D) Can readily support custom components bound to form controls, with either semantics of stacking on top of the native binding or replacing it.
> 
> This is where override and compose approaches work well for
> inheritance-based approach.
> 
>> E) Avoids use of the jargon-ish, mysterious and potentially confusing term "shadow" in favor of "binding" and "component" which are much more clear IMO.
> 
> I agree that "shadow" is jargon-ish. I would love to have a better
> name for it that's not scary. I like "component" terminology!
> 
>> F) The code to build up the DOM for the binding with raw DOM calls only has to run once. After that it just gets cloned, which is likely faster than creating a whole fresh one with raw DOM calls.
> 
> Right. This is good stuff.
> 
>> G) Naturally extensible to other ways of creating components, perhaps on a declarative template a la XBL2.
> 
> Ditto.
> 
> Overall, aside from multiple trees and the use of bindings rather than
> object inheritance, I like this API. Without those two, it's exactly a
> superset of the my proposal, minus webkitShadow. I am a huge fan of
> being able to produce a Component object that acts like a DOM object.
> 
> To make further progress, I would like to concentrate on resolving
> these two issues:
> 
> 1) should we use object inheritance (one shadow subtree) or mixins
> (multiple shadow subtrees)?

I think it's possible to partially table this issue. If mixing are required, then raw access to the shadow tree is not viable. But using inheritance / single binding is possible with either proposal.

> 2) do we need webkitShadow or similar accessor to shadow subtree(s)?

This question is a helpful one. I haven't seen any reason articulated for why such an accessor is required. The fact that it's not present in other similar technologies seems like proof that it is not required.

> 
> I think these are all resolved by supplying use cases and rationale. Right?

If so, I think we need a real list of use cases to be addressed. The one provided seems to bear no relationship to your original proposal (though I believe my rough sketch satisfies more of them as-is and is more obviously extensible to satisfying more of them).

Regards,
Maciej

Received on Thursday, 30 June 2011 20:33:01 UTC