Developers Need to Spend More Time on Low-End Hardware and Networks

Google is now shipping the Chromebook Pixel 2015 and it reminded me of something that greatly annoyed me at the GDG North America Summit 2015. This is a conference that Google puts together for people that organize Google Developer Groups across North America. Most of the attendees are developers (Android and Web). They were all excited about the just announced Chromebook Pixel (then called 2).

I committed something of a blasphemy when I said I was sorry to see a second model of the Pixel. The problem is that the Chromebook Pixel is much more capable than a normal Chromebook. Google really makes the Pixel only for use by Googlers and friends, such as many of the people attending the summit. These “friends” get these Pixels for free (for example when they attend I/O). While a few people do buy them, the pricing really makes them unreasonable to all but the most ardent Chromebooks fans. (I’m a big Chromebook Fan… but I’m using an Acer CB5-311 to type this post.)

So here’s the problem… the people that make software, web sites and Android apps all live on high-end hardware. The vast majority of these people live in areas with good LTE phone service. Almost all have high-end cell phones. Most enjoy very high-speed networks, such as Google Fiber. They have no idea what it is like to use lower-end things. Sure, they’ll talk about “testing” there, but that is nothing like “using” there.

As a developer I understand that certain kinds of tooling requires high-end computers. For Android and Windows development, I definitely reach for Core i5/Core i7 laptops and desktops. But I do try to spend as much time as I can on low to mid-range devices. For example, when I am doing development with Web Technologies, I usually do it from the Chromebook I’m typing this on. I remote into the development machines to run my tooling at higher speeds and do all the UI testing directly on the Chromebook. If it starts getting painful to test, then I see immediately that I need to optimize my app. Most of my tablets are low-mid range (most heavily used are Nexus 7, both 2012 and 2013). When I need to use a Mac, it is generally a rather old MacBook Air. My cell-phone is a Nexus 5 (now mid-rangeish) and when I replace it, it is going to be with a mid-range, Moto-G-ish sort of phone.

But even with my well-intentioned efforts in trying to live the life I’m preaching here… I fail. Especially in phones… the phone I get will have LTE. Most people, even in the industrialized world, do not have LTE!

Recently I was complaining about how software is continually bloated, focusing on WinJS and Polymer. But the problem is deeper than that, current popular development frameworks (Angular, Ember, and even Backbone), have unacceptable overhead on the most commonly used mobile devices.

The simple truth is that as developers we are often failing the majority of our users. Perhaps we should all have a day (say once a month) where we all use truly low-end hardware and networking? I personally would love to see Googlers use Gmail (web-based) on something less than Google Fiber… I bet those 20+ second app load times would quickly disappear.

ES6 Features You Can Use Now

Having sorted out the ES5 situation yesterday, I decided to take a look at ES6: what is shimable and what already has broad implementation (Chrome, Opera and Firefox).

You can easily use these string and number methods now, anywhere you have ES5 or an ES5 shim:

String.prototype.repeat
String.prototype.startsWith
String.prototype.endsWith
String.prototype.includes

Number.isFinite
Number.isInteger
Number.isNaN

I have collected polyfills for these here: tiny-es6

The ES6 features below are also broadly available and can be used via es6-shim. Unfortutuately es6-shim does things that are not compatible with Chrome Apps and WinJS Apps.

Map
Set
Promise

Math.clz32
Math.imul
Math.sign
Math.log10
Math.log2
Math.log1p
Math.expm1
Math.cosh
Math.sinh
Math.tanh
Math.acosh
Math.asinh
Math.atanh
Math.trunc
Math.fround
Math.cbrt
Math.hypot

Use ES5 Features Now

I’ve come to the world of JavaScript programming late, and one thing that really bugs me is the lack of use of ECMAScript 5 in many packages. I understand that people need backwards compatibility, but many of these things can be shimmed. It’s time to make the older browsers run more slowly, so the new ones can run faster.

When I look at the list of additions below, I can only wonder what took so long for these things to get there! The list below are things that are known to shim well. (You can use the ES5 shim, or use the polyfills available in the Mozilla Developer Network links below.)

Array.isArray

Date.now
Date.prototype.toISOString
Date.prototype.toJSON

JSON.parse
JSON.stringify
(The two JSON methods are not available in a shim, but they are supported by IE8+.)

Number.prototype.toFixed

Object.keys

String.prototype.trim

I list this next set separately as they are very important. There are often referred to as the functional programming additions, but regardless of how you feel about functional programming, you need to learn to use these.

For example, JSPerf.com, shows the filter method performing 6x faster than loop-based code, map performing 5x faster, indexOf performing 30x faster and forEach performing an amazing 46x faster. (Results vary with what you do inside the callback — but it seems to always be a good idea to avoid the loop when you can.) This is true because the internal Array.prototype.method implementations can avoid much of JavaScript’s dynamic overhead inside these methods.

Array.prototype.every
Array.prototype.filter
Array.prototype.forEach
Array.prototype.indexOf
Array.prototype.lastIndexOf
Array.prototype.map
Array.prototype.some
Array.prototype.reduce
Array.prototype.reduceRight
Function.prototype.bind

Function.prototype.bind is an exception here, it doesn’t shim as well as the rest, so you’ll need to be careful when using it. I include it as it completes the Function Programming additions in ES5. Unlike the array methods, it doesn’t give additional performance. It is used to make a function that executes as a method bound to an object and for functional programming techniques (partial application, currying).

Bemoaning Large Software

I’ve been doing professional software development for 35 years. For the last 25 years of that, software development has had a serious issue. It is always exceeding the bounds of the customer’s hardware. If it were the case that customers actually needed or at least had their lives substantially enhanced by the bloated software, I wouldn’t complain. But consider these cases:

  • Has office software needs changed enough since 1995 to justify an order of magnitude extra software driving it? (I think the popularity of Google Docs shows the answer to be a clear no.)
  • Given the current state of battery life and processors, is there any justification for putting a verson of Android on your wrist?
  • The current desktop version of Windows needs 6 gigbytes (6,000,000,000 bytes) to install. Windows out of the box really doesn’t do much of anything at all… notepad, calc, dir, paint. What could they possibly be using that space for?
  • And my main topic for this post: Web Frameworks. I thought that even a fairly small Dart program taking in excess of 500K of JavaScript was an anomaly… but it’s becoming ubiquitous. WinJS and Polymer, for example, have hefty overheads.

I am pleased to see that some developers are seeing the problem and engaging in push-back. Some examples:

  • The popularity of MarkDown. Even many professional writers are using it.
  • Micro-frameworks like Backbone rival even Angular in popularity.
  • Wearables like Fitbits, use limited, cut down software and interfaces to deliver good battery life, despite the need for 24-hour monitoring.
  • The Go programming language epitomizes forward thinking in features, while maintaining the ability to write programs that are resource-friendly. Yes, it’s a little less efficent than C, but hardware has capabilities, 4 orders of magnitude beyond what they were when C was created.

Looking at the bloat of Web Frameworks

I specialize in Single Page Web Apps, intended for Desktop and Tablet usage. I don’t really consider a web framework unless it provides me with a modern set of UI components.

Today, your best bets for web frameworks for Desktop SPAs are: Bootstrap (requires jQuery and some sort of event/binding supplement.) or Angular + Angular Bootstrap UI.

Looking towards the future: Angular + Material Design, Polymer + Paper, and WinJS (Microsoft).

So let’s assume that a hypothetical medium-sized desktop web app uses roughly the capability of Bootstrap (which is largely true). Below, none of the sizes includes fonts or icons as that makes it even harder to compare. It does include the JavaScript and CSS necessary to provide the component functionality.

Package Size (min in K)
BootStrap
(+ 150K for jQuery and plumbing)
320
Angular + Angular Bootstrap UI 315
Angular + reqs + Angular Material
(Estimated, missing parts, current 306K)
~350
Polymer + Core + Paper
Incredibly difficult to measure minimized size
(will be hard to minimize period)
(also, is still missing parts, estimate is likely low)
~1,200
WinJS 1,315

So, looking at the state of the art, it looks like it takes less than 350K of JS and CSS to make a decent component set. If you made a set specifically aimed at the Desktop SPA (you get to assume most of ES5/HTML5/CSS3), that number is probably more like 250K.

Now Polymer and WinJS get to make the ES5/HTML5/CSS3 assumption. How are they something like 4 times or more bigger?

This is a very serious question. Supposedly WinJS and Polymer are fully ready for mobile. It takes about 2 seconds to parse one megabyte of JavaScript on a low-end phone. That’s just parse time, not the substantial dynamic instantiation of components that has to occur. (This is especially bad in Polymer where everything is dynamic.) And you don’t even want to think about the amount of time it will take if you’re loading the app over 3G.

How did two large companies like Google and Microsoft get here?
They surely know that doesn’t work, right?
What’s really weird is that if they would just finish their HTML5 (for example, there is a menu element in HTML5… no one has implemented it.) and made the default styling not suck… most of these components sets wouldn’t be needed at all. JavaScript (like all dynamic languages) is great at being glue… using it to retool the OS with a new set of components, every time an app starts, is just plain silly.

Introducing Macro Web Components

Are you longing to be able to use Web Components? Realizing that Polymer is not really going to be usable outside of Chrome any time soon?

Me too… I decided to fix the problem.

Macro Web Components, while not quite as elegant as Polymer components, are every bit as powerful. You can use them now, on any browser that supports the CSS and Javascript you use in your component. They will organize your code in a way that should make it easy to transition to full-blown web components when they truly become available. Unlike Polymer, they do not force you to use technologies you don’t need in a component and will work nicely with your favorite event management, data-binding and templating systems.

When I was debugging a Polymer app in Chrome DevTools, a funny thought struck me… It seemed to me that the Polymer team had created the most complex (and inefficient) macro expansion system I had ever seen. All the “DIVs” were still there, but numerous additional HTML Elements and Shadow DOMs were now in the tree. While Polymer had done a good job of encapsulating component data and styles. It had actually made debugging harder and theming truly painful. Recursive, parameterized, macros seemed to me the obvious solution.

These days, macros need explaining because in the world of Object-Orientation, they came to be seen as archaic. If you’ve seen the C programming language, you’ve seen macros… that’s what a #define is. But don’t let the numerous abuses of C macros turn you off to them. Likewise, the various templating packages for web development are a simple, less structured form of macro processing. Essentially, a macro takes text of one form and expands it into a more detailed form. Macros are most interesting when the transformation is structured. Back in the days when one often had to program in assembly language, macros provided an elegant and indispensable way of writing code. The best example was in the calling sequence of a subroutine. Certain instructions had to be written in the same way every time any routine was called. Coding this by hand was tedious to write and difficult to maintain. Macros provided you with the facility to get it right every time. These macros were structured to look and act like normal assembly language op codes.

I have created Macro Web Components to capture the flavor of the old assembly language macros for HTML. Here is an example fragment of an MWC-enhanced HTML (.mwch) file:

1
2
3
4
5
6
<menu@ id="Menu" icon="hamburger">
<mi@ action="alpha" label="Alpha"/>
<mi@ action="beta" label="Beta"/>
<ms@/>
<mi@ action="omega" label="Omega"/>
</menu@>

The tags with ‘@’ appended are macro invocations. The mwc preprocessor will parse the .mwch file and automatically read and expand each macro into the appropriate HTML, CSS and JavaScript files. Any time, I need to write a menu in my web app, I can use this concise notation. Below are the three invoked MWC component (.mwcc ) files in my mwc_components subdirectory.

For the popular Bootstrap package, these component files would look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!-- menu.mwcc -->
<div class="dropdown">
<button id="${uid@}" class="btn btn-primary btn-lg" type="button" data-toggle="dropdown" aria-haspop="true" aria-expanded="false">
#if icon == "hamburger"
<span class="glyphicon glyphicon-menu-hamburger" aria-hidden="true"></span>
#elif defined(label)
${label}
#else
#error "Must specify either icon or label attribute"
#endif
</button>
<ul class="dropdown-menu" role="menu" aria-labeledby="${uid@}">
<content@/>
</ul>
</div>

1
2
<!-- ms.mwcc -->
<li class="divider"></li>
1
2
<!-- mi.mwcc -->
<li role="presentation"><a role="menuitem" tabindex="-1" href="#">${label}</a></li>

After expansion, the resulting HTML file would contain:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<div class="dropdown">
<button id="Menu" class="btn btn-primary btn-lg" type="button" data-toggle="dropdown" aria-haspop="true" aria-expanded="false">
<span class="glyphicon glyphicon-menu-hamburger" aria-hidden="true"></span>
</button>
<ul class="dropdown-menu" role="menu" aria-labeledby="Menu">
<li role="presentation">
<a role="menuitem" tabindex="-1" href="#">
Alpha
</a>
</li>
<li role="presentation">
<a role="menuitem" tabindex="-1" href="#">
Beta
</a>
</li>
<li class="divider">
</li>
<li role="presentation">
<a role="menuitem" tabindex="-1" href="#">
Omega
</a>
</li>
</ul>
</div>

For real world usage, you’ll need to modify the <mi@> component, to either use a class and JavaScript to add an event listener, or perhaps use onclick to trigger an event in your favorite publish/subscribe package. (If you are using this as a front-end to Polymer or WinJS, you could use their native mechanisms). In other words, you need to make the selected menu item actually do something. Any per component styling or JavaScript can be added using #style and #script sections inside the .mwcc file.

Writing web apps with macros is clearly shorter. It puts all the detailed HTML in one place for easier maintenance. Much of the work is done statically, reducing startup time and battery usage. Also, with the increasing use of web technologies for desktop/mobile apps, macros let you use one enhanced HTML file to deliver apps with different look and feel on the different platforms.

See examples/three-platforms for an example using the menu@ macro above and only one .mwch file to support Bootstrap, Polymer and WinJS.

I expect that fans of Web Components to be up in arms at this point… because web components are “so much more powerful”. But that really isn’t true. Web Components (as defined on WebComponents.org) are simply more object-oriented. Using standard JavaScript techniques, you can write anything you want. Here is Polymer’s my-counter example as an MWC component:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<div class="my-counter ${class?}" ${attributes-as-args@}>
<label><content@></label>
<div>Value: <span id="${uid@}-.span"/></div>
<button id=${uid@}-.button>Increment</button>
</div>

#style

.my-counter {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.my-counter button {
font-weight: bold;
}
.my-counter label {
font-weight: bold;
}

#script

hlp.initComponentClass('my-counter', function(scope, attrs) {
var uid = attrs['uid@'];
scope.counter = attrs.counter;
if (scope.counter === undefined) {
scope.counter = 0;
} else {
scope.counter = parseInt(scope.counter, 10);
}
hlp.$(uid+'-.span').textContent = scope.counter.toString();
scope.increment = function () {
scope.counter++;
hlp.$(uid+'-.span').classList.add('my-counter-highlight');
hlp.$(uid+'-.span').textContent = scope.counter.toString();
};
hlp.$(uid+'-.button').addEventListener("click", function(e) {
scope.increment();
});
});

You can find the code for the hlp helper functions above in the examples/my-counter/js/hlp.js subdirectory of the MWC distribution.

I didn’t need Shadow DOM because I name-spaced my CSS. I didn’t need a template for this component. I didn’t need HTML imports. Using Object.observe would be major overkill. I didn’t even need registerElement.

I would also expect to have Web Component advocates to complain that these components cannot be dynamically instantiated. But again not true [though significantly less elegant than Polymer].

Consider doing something like this <template@> macro:

1
2
3
<script id={$id} type="text/template">
<content@>
</script>

Now invoke with <template@ id="mc1"><my-counter@ id="mc1-ctr"/></template@> and then use the old-fashioned way of doing templates:

1
2
3
var template = document.getElementById("mc1").innerHTML;
var d = document.createElement('div');
d.innerHTML = template;

You will need to walk the DOM element tree of d and replace the mc1 with something unique on all the ids. You’ll also need to arrange to trigger the function in my-counter‘s initComponentClass for the dynamically created component. Regardless, it wouldn’t take much thought to make a convenience function to do it all automatically.

MWC has many more macro features than I’ve shown above. You can find a reference manual and examples in its Github repository. It can also be installed with npm:

1
npm install -g mwc

Web Components (and Polymer)

My Coder’s Next blog is about what is “next” in software development and I cannot think of a better topic to start this blog than Web Components. The emphasis in the blog is what is possible now. With this post and my next one, I hope to show a form of Web Components that can be used in production code now.

I think there is very little doubt that some form of Web Components is the “coming thing“. However, I have serious doubts about Google’s proposed mechanisms to give us Web Components. They are ill-thought out and don’t really accomplish the goals Google says they are trying to reach. Other mechanisms are possible. This post is about the short-comings in the proposed model which Google has recently added to Chrome. My next post will deal with an alternate approach that works now and will likely make it easier to migrate to full Web Components as wide-spread support becomes available.

Why do we need Web Components?

Google actually does a good job presenting this. Often they talk about, “DIV Soup”. The idea is that modern HTML is filled with <div> elements and that it is hard to understand what is going on. This is generally accompanied with a screenshot of the developer console showing the internals of Gmail. (See the image in the article header above.) Yes, this is a mess, but then so is assembly language. The problem is that we are coding the web in the equivalent of assembly language and then complaining that it is verbose and difficult to understand. Further, much of the problem is because the code in question is minified. Minification is necessary to help protect Google’s proprietary interest in its code.

Additionally, they talk about expressivity. Rob Dodson says he would like to replace:

1
2
3
4
5
6
7
8
<!-- Bootstrap Dropdown -->  
<div class="dropdown">
<ul class="dropdown-menu" role="menu" aria-labelledby="dLabel">
<li><a tabindex="-1" href="#">Action</a></li>
<li><a tabindex="-1" href="#">Another action</a></li>
<li><a tabindex="-1" href="#">Something else here</a></li>
</ul>
</div>

with:

1
<fancy-dropdown></fancy-dropdown>

A laudable goal, but Polymer is a very expensive way to do this. It doesn’t begin to solve the “DIV” soup problem… Polymer in fact makes it worse by adding additional layers of Shadow DOMs and DIVs.

Regardless, Google is right, we need better expressivity when writing and debugging HTML.

Google’s proposed solution

Google’s Polymer project is not Web Components per se, but is built upon them and is the only major library anywhere near finished, so I will be using it in my examples.

What Google calls Web Components, consists of 4 parts.
(The ordering below reflects my opinion of the technologies, from best to worst.)

  • Templates
  • HTML Imports
  • Custom Elements
  • Shadow DOM

Templates

Templates for the dynamic creation of elements in HTML are nothing new. Apparently, most of the frameworks do something like this:

1
2
3
4
5
6
7
8
9
10
<script id="temp" type="text/template">
<button>{{dynamicText}}</button>
</script>

<script>
var template = document.getElementById("temp").innerHTML;
/* call templating engine on template to replace {{dynamicText}} */
var d = document.createElement('div');
d.innerHTML = template;
console.dir(d);
</script>

The <template> tag is really just a refinement of that. It mostly avoids the tedious and possibly hazardous mucking about with .innerHTML. I have not studied the spec in detail, but it is likely a good idea in practice as well as in principal.

HTML Imports

HTML imports are born of a desire to store CSS, HTML and Javascript in one file per component. A laudable goal, but terrible in practice. An HTML import is done with <link rel="import"...> tag. To make a menu in Polymer I need to add five of these links for the 5 needed components. Each link is a separate download from the server. Imagine a large app with 100 components… it’s not like images… you have to wait for all the components before it is safe for your program to function. This just doesn’t work. Google’s made a tool that condenses all the html import links in your html file into one file. But surely, that is a strange way to do things. Shouldn’t they have made the program parse the HTML, and automatically find the custom-element files? The HTML import tag could then be used to import ONE file which contains the concatenation of the needed files. It is even reasonably simple to make a way of doing it that does not need the HTML import facility at all.

To be clear, HTML Imports are a nice feature, but it is not a proper way to handle individual Web Components.

Custom Elements

The concept here is that you get to define your own HTML tags (such as <custom-element-name>. In principal, these are a great idea, who wouldn’t want to say:

1
2
3
4
5
6
<menu icon="hamburger"> <!-- Or text="Menu Name" -->
<mi>Action 1</mi>
<mi>Action 2</mi>
<separator>
<mi>A Different Sort of Action</mi>
</menu>

But in practice using Polymer, it comes out looking more like this:

1
2
3
4
5
6
7
8
9
10
11
<core-menu-button relative>
<core-icon-button id="trigger" icon="menu"></core-icon-button>
<core-dropdown class="dropdown" relatedTarget="{{$.trigger}}" layered>k
<core-menu class="menu">
<core-item label="Import..."></core-item>
<core-item label="Export..."></core-item>
<core-separator></core-separator> <!-- Polymer hasn't made this one yet. -->
<core-item label="About..."></core-item>
</core-menu>
</core-dropdown>
</core-menu-button>

Worse it also requires me to add at the top of my HTML:

1
2
3
4
5
<link rel="import" href="bower_components/core-dropdown/core-dropdown.html">
<link rel="import" href="bower_components/core-menu/core-menu.html">
<link rel="import" href="bower_components/core-menu-button/core-menu-button.html">
<link rel="import" href="bower_components/core-icon-button/core-icon-button.html">
<link rel="import" href="bower_components/core-item/core-item.html">

This simply doesn’t constitute progress.

And there are numerous limitations:
(All are understandable, but doesn’t make your job any more pleasant.)

  • Custom element tag names must always have a ‘-‘ in them.
  • Custom attributes must always start with data-. (Google violates this in Polymer).
  • To sub-class a built-in element you have to use a syntax like: <button is="my-custom-element">
  • Custom elements must always have an end tag even if it is not desirable (for example: <core-separator></core-separator>).

Now don’t get me wrong. Because the registerElement call provides a standardized way to let you define new HTML tags, I do believe it will play an important role in the future of web components, but it is not free… Using it as a simple wrapper to get <fancy-dropdown></fancy-dropdown> is a bad idea. At the very least one will generate an extra HTMLElement and a layer of JavaScript invocation overhead. (Fine for one element, but what about 1,000?) If you use Polymer, the overhead as much as triples. And that doesn’t even count the extra overhead of /deep/ (see below) on a DOM tree that can be 3 times bigger than what it would have been without Polymer.

Shadow DOM

This is clearly the worst of the four. So much so that webcomponents.js (the Web Components polyfill used by Polymer and Mozilla Brick) now comes in two forms (one with and one without Shadow DOM). While in principal, one might want a way to encapsulate styles within a component. And initially at least, one thinks one would like to hide the DOM elements within a component. The “cure” here is clearly worse than the disease. It will make browsers even harder to write and will generate many efficiency issue. I have real doubts this proposed standard will be accepted.

Even if it does make it through the standards process, it will be years before it will be in the major browsers and the polyfill is huge and scary. (Mozilla and Apple have both questioned Shadow DOM in its current form.) Polymer’s polyfill for Shadow DOM is simultaneously the most breath-taking and horrifying work of engineering I’ve ever seen. My hat’s off to the people that did that work, but to quote Jurrasic Park:

Yeah, yeah, but your scientists were so preoccupied with whether or
not they could that they didn’t stop to think if they should.

Dr. Ian Malcolm

I won’t cover why it’s a bad idea to use the Polymer (and now Brick) polyfill (at least the one with Shadow DOM) in depth, but you can learn more in this article. I strongly suggest you explore the internals of the polyfills before depending on them in production work. I certainly have no intention of using a Shadow DOM polyfill for my production code.

When you first hear about Shadow DOM… you think of course I want my components to be isolated… but think again… you really probably don’t. You want your buttons to match your inputs to match your fancy animated-cookoo-clock component, right? That’s shadow DOM’s worst problem: theming.

Google has made a whole range of new CSS selectors to “solve” the problem. Previously, when you informally made a component, you name-spaced it, something like class="myc-cookoo-activate-button", which you then used in your CSS rules:

1
2
3
.myc-cookoo-activate-button {
background-color: chartreuse;
}

The styles were all in one file and if things were complicated enough, you’d use LESS or SASS to be able to change that hideous chartreuse you put in all your components to something better by making only one change in the file.

Now with Shadow DOM, you can have all that information separated on a per component basis. You can change them all one by one by hand, or use the sledgehammer approach. In your main CSS file, you would put:

1
2
3
my-cookoo-activate-button::shadow button {
background-color: chartreuse;
}

And we now have an additional place to look for miscreant styling and the CSS is more verbose.

This is not progress.

Worse, they’ve created the /deep/ combinator. A sample:

1
2
html /deep/ [layout][start] {
}

This rule would set styles on every element in the document, including inside Shadow DOMs. The rule would need to be checked every time any style was changed inside the document. Now I’m sure you saying… well it only takes effect if you use it. True… but Polymer uses it 46 times in its layout.html file alone. (It uses it elsewhere as well.)

This isn’t just “not progress”, it’s a step backwards.

Look at this cheatsheet if you want to know the details of the complete set of combinators.

But styling is not the only problem with Shadow DOM. It was supposed to help us with “DIV Soup”… but it really doesn’t, we now get DIV and Shadow DOM Soup. Open the developer tools on any Polymer app… to figure out what is going on, you’ll still need to open all those DIVs, but now you also get to open all those Shadow DOMs which subsection the DIVs. Between the Shadow DOM and the extra HTMLElement that registerElement gives you, you can have as much a 3 times the number of DOM elements.

This is not progress.

Quite simply the whole notion of Shadow DOM needs to be rethought. I’m not even sure it is a good idea at all. If you have a large component that needs to be that isolated, why not use a webview?

Other Polymer Sins

Polymer gives you a large selection of “layout” attributes, such as flex. These seem to be in direct violation of the w3c draft standard for HTML5. I understand that they are convenient. But this isn’t the way to do it. At least Angular namespaces such attributes with “ng-“. This gratuitous use of simple attribute names like “flex” will lead to clashes with other packages later. (Google trying to be the next perpetrator of an IE6-like fiasco?) Adding insult to injury, they use the /deep/ combinator to implement these attributes.

Polymer forces you to use a Shadow DOM on every element. Why? Suppose I want an hbox component:

1
2
3
<div style="display: flex; flex-direction:row">
<!--content goes here-->
</div>

Why would I want a Shadow DOM around that? Is that extra HTMLElement I get from registerElement necessary? But I’d really like to say <hbox>...</hbox>.

Surely, there must be a better way…

Modern programming language debuggers usually have to understand what is going on at the machine code level. What is usually shown to the programmer is the programming language level constructs. Put simply, HTML/CSS is low level, details often have to be dealt with there. How about something higher level, that doesn’t take away any of the power and efficiency of HTML/CSS? That will be the topic of my next post.