Hi Maciej!

First off, I really appreciate your willingness to get into the mix of
things. It's a hard problem and I welcome any help we can get to solve
it.

I also very much liked your outline of encapsulation and I would like
to start using the terminology you introduced.

I am even flattered to see the proposal you outlined, because it's
similar to the one we originally considered as part of the first
iteration of the API
(https://raw.github.com/dglazkov/component-model/cbb28714ada37ddbaf49b3b2b24569b5b5e4ccb9/dom.html)
or even earlier versions
(https://github.com/dglazkov/component-model/blob/ed6011596a0213fc1eb9f4a12544bb7ddd4f4894/api-idl.txt)

We did remove them however, and opted for the simplest possible API,
which effectively only exposes the shadow DOM part of the component
model (see my breakdown here
http://lists.w3.org/Archives/Public/public-webapps/2011AprJun/1345.html).

One of the things to keep in mind is that the proposal outlined in
http://dglazkov.github.com/component-model/dom.html is by no means a
complete component model API. It's just the smallest subset that can
already be useful in addressing some of the use cases listed in
http://wiki.whatwg.org/wiki/Component_Model_Use_Cases.

It seem obvious that it is better to have few small, closely related
useful bits that could be combined into a bigger picture rather than
one large monolithic feature that can't be teased apart.

As for addressing encapsulation concerns, one of the simplest things
we could is to introduce a flag on the ShadowRoot (we can discuss the
default value), which if set, prohibits access to it with the
element.shadow property.

:DG<

On Wed, Jun 29, 2011 at 9:03 PM, Maciej Stachowiak <m...@apple.com> wrote:
>
>
> I am not a fan of this API because I don't think it provides sufficient 
> encapsulation. The words "encapsulation" and "isolation" have been used in 
> different ways in this discussion, so I will start with an outline of 
> different possible senses of "encapsulation" that could apply here.
>
> == Different kinds of "encapsulation" ==
>
> 1) Encapsulation against accidental exposure - DOM Nodes from the shadow tree 
> are not leaked via pre-existing generic APIs - for example, events flowing 
> out of a shadow tree don't expose shadow nodes as the event target,
>
> 2) Encapsulation against deliberate access - no API is provided which lets 
> code outside the component poke at the shadow DOM. Only internals that the 
> component chooses to expose are exposed.
>
> 3) Inverse encapsulation - no API is provided which lets code inside the 
> component see content from the page embedding it (this would have the effect 
> of something like sandboxed iframes or Caja).
>
> 4) Isolation for security purposes - it is strongly guaranteed that there is 
> no way for code outside the component to violate its confidentiality or 
> integrity.
>
> 5) Inverse isolation for security purposes - it is strongly guaranteed that 
> there is no way for code inside the component to violate the confidentiality 
> or integrity of the embedding page.
>
>
> I believe the proposed API has property 1, but not properties 2, 3 or 4. The 
> webkitShadow IDL attribute violates property #2, I assume it is obvious why 
> the others do not hold.
>
> I am not greatly interested in 3 or 4, but I believe #2 is important for a 
> component model.
>
>
> == Why is encapsulation (type 2) important for components? ==
>
> I believe type 2 encapsulation is important, because it allows components to 
> be more maintainable, reusable and robust. Type 1 encapsulation keeps 
> components from breaking the containing page accidentally, and can keep the 
> containing page from breaking the component. If the shadow DOM is exposed, 
> then you have the following risks:
>
> (1) A page using the component starts poking at the shadow DOM because it can 
> - perhaps in a rarely used code path.
> (2) The component is updated, unaware that the page is poking at its guts.
> (3) Page adopts new version of component.
> (4) Page breaks.
> (5) Page author blames component author or rolls back to old version.
>
> This is not good. Information hiding and hiding of implementation details are 
> key aspects of encapsulation, and are good software engineering practice. 
> Dmitri has argued that pages today do a version of components with no 
> encapsulation whatsoever, because many are written by monolithic teams that 
> control the whole stack. This does not strike me as a good argument. 
> Encapsulation can help teams maintain internal interfaces as they grow, and 
> can improve reusability of components to the point where maybe sites aren't 
> quite so monolithically developed.
>
> Furthermore, consider what has happened with JavaScript. While the DOM has no 
> good mechanism for encapsulation, JavaScript offers a choice. Object 
> properties are not very encapsulated at all, by default anyone can read or 
> write. But local variables in a closure are fully encapsulated. It's more and 
> more consider a good practice in JavaScript to build objects based on 
> closures to hide implementation details. This is the case even though the 
> closure approach is more awkward to code, and may hurt performance. For 
> ECMAScript Harmony, a form of object that provides true encapsulation is 
> being considered.
>
> I don't want us to make the same mistake with DOM components that in 
> retrospect I think was made with JavaScript objects. Let's provide good 
> encapsulation out of the gate.
>
> And it's important to keep in mind here that this form of encapsulation is 
> *not* meant as a security measure; it is meant as a technique for robustness 
> and good software engineering.
>
>
> == Are there use cases for breaking type 2 encapsulation against the will of 
> the component? ==
>
> I'm not aware of any. I asked Dmitri to explain these uses cases on IRC and 
> he didn't have any specific ones in mind, just said that exposing the shadow 
> DOM directly is the simplest thing that could possibly work and so is easy to 
> prototype and implement. I think there are other starter approaches that are 
> easy to implement but provide stronger encapsulation.
>
>
> == 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.
>
>
> == OK Mr. Fancypants, do you have a better proposal? ==
>
> I haven't thought deeply about this, but here's a sketch of a component model 
> that is just as trivial to use and implement as what is proposed, yet 
> provides true encapsulation. It sticks with the idea that the only way to 
> create a component DOM is programmatically. But it immediately provides some 
> advantages that I'll expand on after throwing out the IDL:
>
> interface Component {
>    // deliberately left blank
> }
>
> interface TreeScope : Node
>  {
>    readonly TreeScope parentTreeScope;
>    Element getElementById (in DOMString elementId);
> }
>
>  interface BindingRoot : TreeScope {
>   attribute bool applyAuthorSheets;
>   readonly attribute Element bindingHost;
>  };
>
> [Callback]
> interface ComponentInitializer {
>  void initialize(in BindingRoot binding);
> };
>
>  partial interface Document {
>     Component createComponent(in Node template, in ComponentInitializer 
> initializer);
>  };
>
> partial interface Element {
>    bindComponent(in Component component);
>    unbindComponent(in Component component);
> }
>
> The way this works is as follows:
>
> (1) The component provider creates a DOM tree that provides templates for 
> bindings that instantiate that component.
> (2) The component provider also makes an init function (represented above as 
> a callback interface) which is called whenever an instance of the component 
> is bound (see below).
> (3) The component provider calls createComponent with these things and gets 
> back a Component object, which is completely opaque and exposes no 
> implementation details (though if we wanted we could add some visible 
> metadata attributes like a name or what have you) but can be bound to an 
> element.
> (4) The component provider hands back this token to its client.
> (5) The client can instantiate the component as many times as it wants by 
> binding it to one or more elements.
> (6) When Element.bindComponent is called, it creates the BindingRoot, clones 
> the template into it as children (it can be a DocumentFragment if desired), 
> attaches it to the element, and then calls the initializer function on the 
> newly created binding root, so that it can set up event listeners and such.
>
>
> 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.
> B) Binding is atomic - the shadow root is not built up incrementally so you 
> can't have a half-built binding.
> C) Has a natural extension to allowing more than one binding on an element, 
> having a stacking behavior like XBL.
> D) Can readily support custom components bound to form controls, with either 
> semantics of stacking on top of the native binding or replacing it.
> 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.
> 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.
> G) Naturally extensible to other ways of creating components, perhaps on a 
> declarative template a la XBL2.
>
>
> I hope this comprehensively expresses my concerns, and I believe I have shown 
> at least one way in which my concerns about encapsulation can be addressed 
> without adding unwarranted complexity.
>
>
> Regards,
> Maciej
>
>

Reply via email to