Dimitri Glazkov

Web and About

Going Forward Is Leaving Past Behind

with 2 comments

Greetings, hypothetical Web app developer. So I wrote this thing. It’s for your eyes only. Your non-Web developer buddy will find my ramblings mostly trivial and nonsensical. But you… you are in for a trip. I think. Ready?

Prologue

It’s hard to part with the past. Things we’ve done, stuff we’ve learned, the experiences we’ve had — they aren’t just mental artifacts. They shape us, define us. Yet, they are also the scars we carry, the cold-sweat nightmares that keep us awake. And thus continues our struggle between embracing and shedding what has been.

In this way, a platform is somewhat like us. If it only embraces its past, it can’t ever evolve. If it only looks into the future, it’s no longer a platform. Striking the balance is a delicate game.

Progress

In order to survive, a platform has to move forward. A tranquil platform is a dead platform.

In particular, the Web platform had been caught napping. It awoke startled, facing the mobile beast that’s eating the world and went: Oh shit.

Turns out, our platform has gotten a bit plump. All those bells and whistles are now just flab in the way of scampering limbs. It’s time to get lean–or be lunch.

What’s worse, we aren’t even in the same league. While we’re still struggling to run without apoplexy, the other guy can fly and shoot lasers. We’re so screwed. Gotta get cranking on those lasers. And start losing weight.

Cost

Losing weight is hard work. Like with anything where we give up our habits, the way we steel ourselves and go through is by thinking of the cost of not changing.

For the platform, the obvious one is the code size, which is really a proxy for the cost of complexity — the engineering and maintenance complexity, to be precise. Making a modern browser is an incredibly large task and adding urgency further skews the triangle to higher costs.

Then there’s this paradoxically-sounding thing:

The less often a feature is used, the more it costs.

This is the opportunity cost. The more complicated the system, the more confused is the reasoning about the next steps. At the limit, you can’t step forward at all — there’s always an artifact from your past in the way, be it the fun extra nested event loop, the thing you thought was cool back then, or the the dead appendages you grew one day, just for the hell of it.

Here’s another way to put it (now with action figures!): You have a platform with features and users. Bob is a user of a feature. The cost of keeping this feature in the platform is evenly distributed among all users.

However, if Bob is the only user of the feature, something weird happens: all the users still pay the costs, but now they’re paying them to fund Bob’s habit.

As other users ask for new capabilities and polish, Bob’s feature slowly sinks to the bottom of priorities. A statistical wash, the code of the feature grows a beard and stops doing laundry. Bad smells and bugs creep in. With the rest of the code base moving on, the likelihood of a fire drill around this forgotten mess only goes up.

Time is finite and you spend non-zero time on every feature. There’s some feature work you’re not doing to keep this Bob-only feature.

At this point, all other users should be strongly motivated to make Bob stop using his feature. Bob’s dragging everyone down.

Budget

These are all pretty obvious thought experiments, I guess. Web platform engineers (aka browser builders) are a limited resource. For you, Web app developers, they are your home improvement budget.

Thus we arrive to the main point of this anecdote: how would you rather have this budget allocated?

The answer likely goes like this (pardon for possibly putting words in your mouth):

I want you bastards to let me build things that are not terrible on mobile. You are moving too slowly and that’s highly annoying. My boss is telling me to build a native app, and I SWEAR I will, if you don’t start moving your goofy ass NOW. You know what? I am leaving now. Hear these footsteps?

I’m holding my breath, hoping you’re just faking those footsteps. And if you are (whew!), it seems fair to assume that you want most of your budget spent on making browser leaner, meaner, and capable of flying while shooting lasers. Not maintaining the old stuff. Which means that we need to get serious about deprecation. And being serious means we need data.

Data

In Blink land, we have a fairly comprehensive usage measuring system. Despite some limitations, it provides a reasonable approximation of how widely a feature is used.

Just knowing how widely it is used isn’t enough. There’s definitely some extra dimensions here. Despite their equally low usage, there’s a difference between a newly-launched feature and a forgotten one. Similarly, something that’s rarely used could be so well-entrenched in some enterprise front-end somewhere that removing it will be met with tortured screams of anguish.

We also need to give you, web developers, clear indicators of our past mistakes. There are plenty of platform features that are frequently used, but we platform peeps can’t look at without a frown. It seemed like a good idea at the time. Then the reality happened. Communicating this frown is sometimes difficult, but necessary to look forward.

Action

Clearly, we have work to do. Arriving at a clear framework of deprecation principles is trial, error, and likely yet more tears. But we know we need it. We’re working on it.

As for you, my dear web developer… I need your help.

Use feature metrics in planning your new work and refactoring. If you see a feature that’s falling behind in statistics, think twice about using/keeping it. Talk to your friends and explain the danger of relying on old, rarely used things.

Don’t be a bob. Don’t let your friends be bobs. Being a bob sucks. Not the actual person named “Bob”, of course. Being that Bob is totally awesome.

Written by Dimitri Glazkov

April 24, 2014 at 3:13 pm

Posted in Uncategorized

What the Heck is Shadow DOM?

with 107 comments

If you build Web sites, you probably use Javascript libraries. If so, you are probably grateful to the nameless heroes who make these libraries not suck.

One common problem these brave soldiers of the Web have to face is encapsulation. You know, one of them turtles on which the Object-Oriented Programming foundation sits, upon which stands most of the modern software engineering. How do you create that boundary between the code that you wrote and the code that will consume it?

With the exception of SVG (more on that later), today’s Web platform offers only one built-in mechanism to isolate one chunk of code from another — and it ain’t pretty. Yup, I am talking about iframes. For most encapsulation needs, frames are too heavy and restrictive.

What do you mean I must put each of my custom buttons in a separate iframe? What kind of insane are you?

So we need something better. Turns out, most browsers have been sneakily employing a powerful technique to hide their gory implementation details. This technique is called the shadow DOM.

My name is DOM, Shadow DOM

Shadow DOM refers to the ability of the browser to include a subtree of DOM elements into the rendering of a document, but not into the main document DOM tree. Consider a simple slider:

<input id="foo" type="range">
 

Pop this code into any WebKit-powered browser, and it’ll appear like so:

Typical Slider Control on WebKit

Simple enough. There’s a slider track and there’s a thumb, which you can slide along the track.

Wait, what? There’s a separate movable element inside of the input element? How come I can’t see it from Javascript?

var slider = document.getElementsById("foo");
console.log(slider.firstChild); // returns null
 

Is this some sort of magic?

No magic, my fair person of the Web. Just shadow DOM in action. You see, browser developers realized that coding the appearance and behavior of HTML elements completely by hand is a) hard and b) silly. So they sort of cheated.

They created a boundary between what you, the Web developer can reach and what’s considered implementation details, thus inaccessible to you. The browser however, can traipse across this boundary at will. With this boundary in place, they were able to build all HTML elements using the same good-old Web technologies, out of the divs and spans just like you would.

Some of these are simple, like the slider above. Some get pretty complex. Check out the video element. It’s got trigger buttons, timelines, a hover-appearing volume control, you name it:

WebKit Video Element With Controls

All of this is just HTML and CSS — hidden inside of a shadow DOM subtree.

To borrow a verse from that magnetic meme duo, “how does it work?” To build a better mental model, let’s pretend we have a way to poke at it with Javascript. Given this simple page:

<html>
<head>
<style> p { color: Green; } </style>
</head>
<body>
<p>My Future is so bright</p>
<div id="foo"></div>
<script>
    var foo = document.getElementById('foo');
    // WARNING: Pseudocode, not a real API.
    foo.shadow = document.createElement('p');
    foo.shadow.textContent = 'I gotta wear shades';
</script>
</body>
</html>
 

We get the DOM tree like this:

<p>My Future is so bright</p>
<div id="foo"></div>
 

But it is rendered as if it were this:

<p>My Future is so bright</p>
<div id="foo"> <!-- shadow subtree begins -->
    <p>I gotta wear shades</p>
</div> <!-- shadow subtree ends -->
 

Or visually like so:

Shadow DOM Example

Notice how the second part of the rendered sentence is not green? That’s because the p selector I have in my document can’t reach into the shadow DOM. How cool is that?! What would a framework developer give to have powers like this? The ability to write your widget and not worry about some random selector fiddling with your style seems … downright intoxicating.

Course of Events

To keep things natural, events fired in shadow DOM subtree can be listened to in the document. For instance, if you click on the mute button in the audio element, your event listeners on an enclosing div would hear the click:

<div onclick="alert('who dat?')">
    <audio controls src="test.wav"></audio>
</div>
 

However, if you ask to identify who fired the event, you’ll find out it was the audio element itself, not some button inside of it.

<div onclick="alert('fired by:' + event.target)">
    <audio controls src="test.wav"></audio>
</div>
 

Why? Because when crossing the shadow DOM boundary, the events are re-targeted to avoid exposing things inside of the shadow subtree. This way, you get to hear the events, fired from the shadow DOM, and the implementor gets to keep their details hidden from you.

Reaching into Shadows with CSS

One other trick up the sleeve is the ability to control how and whether CSS reaches into the shadow subtree. Suppose I want to customize the look of my slider. Instead of the standard OS-specific appearance, I want it be stylish, like so:

input[type=range].custom {
    -webkit-appearance: none;
    background-color: Red;
    width: 200px;
}
 

The result I get is:

Slider with a custom-styled track

Ok, that’s nice, but how do I style the thumb? We already determined the that our usual selectors don’t go into the shadow DOM tree. Turns out, there’s a handy pseudo attribute capability, which allows shadow DOM subtrees to associate an arbitrary pseudo-element identifier with an element in the subtree. For example, the thumb in the WebKit slider can be reached at:

input[type=range].custom::-webkit-slider-thumb {
    -webkit-appearance: none;
    background-color: Green;
    opacity: 0.5;
    width: 10px;
    height: 40px;
}
 

Which gives us:

Fully custom-styled slider

Ain’t it great? Think about it. You can style elements in the shadow DOM without actually being able to access them. And the builder of the shadow DOM subtree gets to decide which specific parts of their tree can be styled. Don’t you wish you had powers like this when building your UI widget toolkit?

Shadows with Holes, How’s that for a Mind-bender?

Speaking of awesome powers, what happens when you add a child to an element with a shadow DOM subtree? Let’s experiment:

// Create an element with a shadow DOM subtree.
var input = document.body.appendChild(document.createElement('input'));
// Add a child to it.
var test = input.appendChild(document.createElement('p'));
// .. with some text.
test.textContent = 'Team Edward';
 

Displaying as:

Input Element and Nothing Else

Whoa. Welcome to the twilight DOM — a chunk of document that’s accessible by traversal but not rendered on the page. Is it useful? Not very. But it’s there for you, if you need it. Teens seem to like it.

But what if we did have the ability to show element’s children as part of its shadow DOM subtree? Think of the shadow DOM as a template with a hole, through which the element’s children peek:

// WARNING: Pseudocode, not a real API.
var element = document.getElementById('element');
// Create a shadow subtree.
element.shadow = document.createElement('div');
element.shadow.innerHTML = '<h1>Think of the Children</h1>' +
    <div class="children">{{children-go-here}}</div>';
// Now add some children.
var test = element.appendChild(document.createElement('p'));
test.textContent = 'I see the light!';
 

As a result, if you traverse the DOM you will see this:

<div id="element">
    <p>I see the light</p>
</div>
 

But it will render like this:

<div id="element">
    <div> <!-- shadow tree begins -->
        <h1>Think of the Children</h1>
        <div class="children"> <!-- shadow tree hole begins -->
            <p>I see the light</p>
        </div> <!-- shadow tree hole ends -->
    </div> <!-- shadow tree ends --> 
</div>
 

As you add children to element, they act as normal children if you look at them from the DOM, but rendering-wise, they are teleported into a hole in the shadow DOM subtree.

This is the point where you admit that this is pretty cool and start asking:

When can I have it in my browser?

Homework Assignment

Did you think you’d read through all this preaching and get away without homework? As a Javascript library or framework developer, try to think of all the different great things having shadow DOM would allow you to do. Then think of specific use cases (actual/pseudo code a plus) of where shadow DOM could be applied. To help you get your thinking groove going, here is current list of use cases.

Finally. share your use cases on public-webapps mailing list. The discussion about adding these capabilities to the Web platform is under way and your help is needed.

If you aren’t a much a framework writer, you can still participate — by cheering for the shadow DOM and spreading the joy on your favorite social networking site. Because joy is what’s it’s all about.

PS. SVG and Shadow DOM

Almost forgot. Believe it or not, SVG has actually had shadow DOM since the beginning. The trouble is, its shadow DOM is very… shady. No, that’s not it. There’s another qualifier that also begins with “sh” and ends with a “y”. Yeah, that one. I could go on, but trust me on this. Or read the spec.

Written by Dimitri Glazkov

January 14, 2011 at 4:40 pm

Posted in WebKit

Tagged with , , ,

From HTML5 to Gibson’s Matrix?

with 2 comments

I shouldn’t admit it, but — what the heck. I haven’t read the Sprawl Trilogy. Until this weekend. After falling prey to another round of the seasonal crud, and with the long Memorial Day weekend in sight, I dove in.

The books aged extremely well. It was too easy to ignore the awkward artifacts of the 80’s culture and go with the smooth and intricate flow. It felt just right. Not the mind-boggling, monolithic Stephenson’s universe that pounds you with all its kilo-page might. It was gentler and more focused on the characters, rather than the surrounding gadgetry and sound reasoning behind its existence.

Anywho. I walked away inspired. The Sprawl was a tantalizing illusion, my brain spinning in a vertigo of subconscious attempts to fill in the missing engineering details. But in riding this high, I also felt disappointment. It’s 2009, for crying outloud. Where are the AIs? I mean those that can reasonably fool a Turing test? Where are the consoles that connect you directly to the full sensory representation of the Internet? And hovercrafts?! I want my frickin hovercrafts!

How is it that we are still tinkering with a 10-year old hypertext format, asymptotically trying to make it work right on our respective rendering engines, bolting new steel plates on the old wooden boat as it creaks, sinking further under the weight of our add-ons? How come there’s a whole echelon of computer industry burning midnight oil congealing bits of CSS, HTML, and JS into the scary, scary nonsensical frankensteins that we call Web sites? And how come it is so hard to build and grow these sites — not to mention use them?

Where have we gone wrong? Perhaps it was the naive notion that HTML wasn’t just an accidental leader of the rising wave, that it was somehow special, because it was just like text and thus “easy of use?” I shudder even typing these three words. Or was it the idea that the Web is what it is and shouldn’t break it? Or maybe it was us, proclaiming that content is king and that the vehicle didn’t matter? We’ve become content with what we’ve got. Even new aspirations, however alien, look suspiciously like the same old stuff.

But yes, we are where we are. Otherwise, we wouldn’t be anywhere. Right? Riiight. We have this spec, called HTML5 and we’re trying to make it work. It’s better than what we have today, and it is a step forward. But on the big scheme of things — is this what we need? Small, painful incremental steps on the burning coals of the Web as we know it? Is this taking us somewhere? And if it is, are we there yet?

Are we there yet?

Written by Dimitri Glazkov

May 25, 2009 at 3:46 pm

Posted in Personal, Rant

Tagged with , , , , ,

Lucky Chrome

with 8 comments

How can you explain this sheer amount of luck? Are there any special terms for it? I have no clue.

To illustrate — this year, yours truly:

  • After long 14 years finally got his green card
  • Moved to California
  • Landed a job at Google
  • … on the Google Chrome team!
As my good friend put it: “Wear your seatbealt. You have used up all of your luck”.

Written by Dimitri Glazkov

September 3, 2008 at 11:19 am

Posted in Personal

Tagged with , , ,

Information Architecture Presentation at IPSA

with 2 comments

Today, I gave a small presentation on a large topic, “Information Architecture on a Large Scale” at IPSA (that’s Information Professionals Society of Alabama). Here are the slides:

And here are the notes:

Thank you guys for the warm reception! And if you have anything to add, comment, or critique, please leave a comment or two.

Update: here is a video, courtesy of the fearless Brit Mansell:

Written by Dimitri Glazkov

July 11, 2008 at 5:03 pm

Thank You, Birmingham

with 3 comments

It’s been a long time. I remember driving down I-59 for the first time and suddenly seeing you, lit up, silent and magical in the damp summer heat of 1995. I remember the shock of first encountering the true Southern talk at a McDonald’s drive-through and not being able to comprehend a word — or even make out a syllable. This was a whole different world. This was a whole different time.

Over the next 13 years, I learned lots of things. I learned that driving expensive German cars is not at all what I really want from my life. As a side effect, I learned how to get in debt up to my eyeballs and how to get out of it. I learned that parents will love you no matter what and that their hearts will bleed as they watch you making the stupidest mistakes on your path to comprehension of life.

I also learned that you can’t “fix” people or change them to your liking, no matter how hard you try. I learned that things will happen in most unpredictable ways and a beam of light would shine in the darkest of the night to reveal a new path. I learned what it means to be a family man and exactly how little sleep young fathers and mothers need to keep going.

Along the way, you were there for me. You cheered for my successes. You helped me deal with failures and consequences of poor choices. You taught me about serendipity, resilience, dedication and faith. And most of all, you taught me what it means to truly love someone.

You opened my eyes to the complexity and depth of the racial and cultural divide of this world and gave me hope that this divide can be overcome, even if one person at a time.

Thank you, Birmingham. Thanks for my friends, the opportunities, and the impeccable Southern hospitality. Thank you for your wisdom and willingness to embrace this quirky Russian.

On August 1, we part ways. True to your old-fashioned ways, you stay where you are. But a little part of you will move on with me and my family. Mountain View, here we come. Looking forward to meeting y’all out in California.

Written by Dimitri Glazkov

July 6, 2008 at 2:13 pm

Wrap Your Head Around Gears Workers

with one comment

Google I/O was a continuous, three-thousand-person mind meld, so I talked and listened to a lot of people last week. And more often than not I discovered that Gears is still mostly perceived as some wand that you can somehow wave to make things go offline. Nobody is quite sure knows how, but everyone is quite sure it’s magic.

It takes a bit of time to accept that Gears is not a bottled offlinifier for sites. It takes even more time to accept that it’s not even an end-user tool, or something that just shims between the browser and the server and somehow saves you from needing to rethink how you approach the Web to take it offline. That the primitives, offered by Gears, are an enabling technology that gives you the capability to make completely new things happen on the Web, and it is your, developer’s task to apply it to solve problems, specific to your Web application.

And it’s probably the hardest to accept that there is no one-size-fits-all solution to the problem of taking your application offline. Not just because the solution may vary depending on what your Web application does, but also because the actual definition of the problem may change from site to site. And pretty much any way you slice it, the offline problem is um, hard.

It’s not surprising then that all this thinking often leaves behind a pretty cool capability of Gears: the workers. Honestly, workers and worker pools are like the middle child of Gears. Everybody kind of knows about them, but they’re prone to be left behind in an airport during a family vacation. Seems a bit unfair, doesn’t it?

I missed the chance to see Steven Saviano‘s presentation on Google Docs, but during a hallway conversation, it appears that we share similar thoughts about Gears workers: it’s all about how you view them. The workers are not only for crunching heavy math in a separate thread, though that certainly is a good idea. The workers are also about boundaries and crossing them. With the cross-origin workers and the ability to make HTTP requests, it takes only a few mental steps to arrive at a much more useful pattern: the proxy worker.

Consider a simple scenario: your JavaScript application wants to consume content from another server (the vendor). The options are fairly limited at the moment — you either need a server-side proxy or use JSON(P). Neither solution is particularly neat, because the former puts undue burden on your server and the latter requires complete trust of another party.

Both approaches are frequently used today and mitigated by combinations of raw power or vendor’s karma. The upcoming cross-site XMLHttpRequest and its evil twin XDR will address this problem at the root, but neither is yet available in a released product. Even then, you are still responsible for parsing the content. Somewhere along the way, you are very likely to write some semblance of a bridge that translates HTTP requests and responses into methods and callbacks, digestible by your Web application.

This is where you, armed with the knowledge of the Gears API, should go: A-ha! Wouldn’t it be great if the vendor had a representative, who spoke JavaScript? We might just have a special sandbox for this fella, where it could respond to our requests, query the vendor, and pass messages back in. Yes, I am talking about a cross-origin worker that acts as a proxy between your Web application and the vendor.

As Steven points out at his talk (look for the sessions on YouTube soon — I saw cameras), another way to think of this relationship is the RPC model: the application and the vendor worker exchange messages that include procedure name, body, and perhaps even version and authentication information, if necessary.

Let’s imagine how it’ll work. The application sets up a message listener, loads the vendor worker, and sends out the welcome message (pretty much along the lines of the WorkerPool API Example):

// application.js:
var workerPool = google.gears.factory.create('beta.workerpool');
var vendorWorkerId;
// true when vendor and client both acknowledged each other
var engaged;
// set up application listener
workerPool.onmessage = function(a, b, message) {
  if (!message.sender != vendorWorkerId) {
    // not vendor, pass
    return;
  }
  if (!engaged) {
    if (message.text == 'READY') {
      engaged = true;
    }
    return;
  }
  processResponse(message);
}
vendorWorkerId = workerPool.createWorkerFromUrl(
                                'http://vendorsite.com/workers/vendor-api.js');
workerPool.sendMessage('WELCOME', vendorWorkerId);

As the vendor worker loads, it sets up its own listener, keeping an ear out for the WELCOME message, which is its way to hook up with the main worker:

// vendor-api.js:
var workerPool = google.gears.workerPool;
// allow being used across origin
workerPool.allowCrossOrigin();
var clientWorkerId;
// true when vendor and client acknowledged each other
var engaged;
// set up vendor listener
workerPool.onmessage = function(a, b, message) {
  if (!engaged) {
    if (message.text == 'WELCOME') {
      // handshake! now both parties know each other
      clientWorkerId = message.sender;
      workerPool.sendMessage('READY', clientWorkerId);
    }
    return;
  }
  // listen for requests
  processRequest(message);
}

As an aside, the vendor can also look at message.origin as an additional client validation measure, from simple are you on my subdomain checks to full-blown OAuth-style authorization schemes.

Once both application and the vendor worker acknowledge each other’s presence, the application can send request messages to the vendor worker and listen to responses. The vendor worker in turn listens to requests, communicates with the vendor server and sends the responses back to the server. Instead of being rooted in HTTP, the API now becomes a worker message exchange protocol. In which case the respective processing functions, processRequest and processResponse would be responsible for handling the interaction (caution, freehand pseudocoding here and elsewhere):

// vendor-api.js
function processRequest(message) {
  var o = toJson(message); // play safe here, ok?
  if (!o || !o.command) {
    // malformed message
    return;
  }
  switch(o.command)
    case 'public': // fetch all public entries
      // make a request to server, which fires specified callback on completion
      askServer('/api/feed/public', function(xhr) {
        var responseMessage = createResponseMessage('public', xhr);
        // send response back to the application
        workerPool.sendMessage(responseMessage, clientWorkerId);
      });
      break;
    // TODO: add more commands
  }
}

// application.js
function processResponse(message) {
  var o = toJson(message);
  if (!o || !o.command) {
    // malformed message
    return;
  }
  switch(o.command) {
    case 'public': // public entries received
      renderEntries(o.entries);
      break;
    // TODO: add more commands
  }
}

You could also wrap this into a more formal abstraction, such as the Pipe object that I developed for one of my Gears adventures.

Now the vendor goes, whoa! I have Gears. I don’t have to rely on dumb HTTP requests/responses. I can save a lot of bandwidth and speed things up by storing most current content in a local database, and only query for changes. And the fact that this worker continues to reside on my server allows me to continue improving it and offer new features, as long as the message exchange protocol remains compatible.

And so you and the vendor live happily ever after. But this is not the only happy ending to this story. In fact, you don’t even have to go to another server to employ the proxy model. The advantage of keeping your own server’s communication and synchronization plumbing in a worker is pretty evident once you realize that it doesn’t ever block UI and provides natural decoupling between what you’d consider the Model part of your application. You could have your application go offline and never realize it, because the proxy worker could handle both monitoring of the connection state and seamless switching between local storage and server data.

Well, this post is getting pretty long, and I am no Steve Yegge. Though there are still plenty of problems to solve (like gracefully degrading this proxy model to a non-Gears environment), I hope my rambling gave you some new ideas on how to employ the worker goodness in your applications and gave you enough excitement to at least give Gears a try.

Written by Dimitri Glazkov

June 2, 2008 at 7:38 pm

Posted in Uncategorized

Follow

Get every new post delivered to your Inbox.

Join 39 other followers