You are here

thinktime

"What do I owe you?"

Seth Godin - Wed 04th May 2016 20:05
One of the little-remembered innovations of the industrial economy was the price tag. If it was for sale, you knew how much it cost. And if you got a job, you knew what you got paid--by the piece, at first,...        Seth Godin
Categories: thinktime

Meaningful CSS: Style Like You Mean It

a list apart - Wed 04th May 2016 00:05

These days, we have a world of meaningful markup at our fingertips. HTML5 introduced a lavish new set of semantically meaningful elements and attributes, ARIA defined an entire additional platform to describe a rich internet, and microformats stepped in to provide still more standardized, nuanced concepts. It’s a golden age for rich, meaningful markup.

Yet our markup too often remains a tangle of divs, and our CSS is a morass of classes that bear little relationship to those divs. We nest div inside div inside div, and we give every div a stack of classes—but when we look in the CSS, our classes provide little insight into what we’re actually trying to define. Even when we do have semantic and meaningful markup, we end up redefining it with CSS classes that are inherently arbitrary. They have no intrinsic meaning.

We were warned about these patterns years ago:

In a site afflicted by classitis, every blessed tag breaks out in its own swollen, blotchy class. Classitis is the measles of markup, obscuring meaning as it adds needless weight to every page. Jeffrey Zeldman, Designing with Web Standards, 1st ed.

Along the same lines, the W3C weighed in with:

CSS gives so much power to the “class” attribute, that authors could conceivably design their own “document language” based on elements with almost no associated presentation (such as DIV and SPAN in HTML) and assigning style information through the “class” attribute… Authors should avoid this practice since the structural elements of a document language often have recognized and accepted meanings and author-defined classes may not. (emphasis mine)

So why, exactly, does our CSS abuse classes so mercilessly, and why do we litter our markup with author-defined classes? Why can’t our CSS be as semantic and meaningful as our markup? Why can’t both be more semantic and meaningful, moving forward in tandem?

Building better objects

A long time ago, as we emerged from the early days of CSS and began building increasingly larger sites and systems, we struggled to develop some sound conventions to wrangle our ever-growing CSS files. Out of that mess came object-oriented CSS.

Our systems for safely building complex, reusable components created a metastasizing classitis problem—to the point where our markup today is too often written in the service of our CSS, instead of the other way around. If we try to write semantic, accessible markup, we’re still forced to tack on author-defined meanings to satisfy our CSS. Both our markup and our CSS reflect a time when we could only define objects with what we had: divs and classes. When in doubt, add more of both. It was safer, especially for older browsers, so we oriented around the most generic objects we could find.

Today, we can move beyond that. We can define better objects. We can create semantic, descriptive, and meaningful CSS that understands what it is describing and is as rich and accessible as the best modern markup. We can define the elephant instead of saying things like .pillar and .waterspout.

Clearing a few things up

But before we turn to defining better objects, let’s back up a bit and talk about what’s wrong with our objects today, with a little help from cartoonist Gary Larson.

Larson once drew a Far Side cartoon in which a man carries around paint and marks everything he sees. “Door” drips across his front door, “Tree” marks his tree, and his cat is clearly labelled “Cat”. Satisfied, the man says, “That should clear a few things up.”

We are all Larson’s label-happy man. We write <table class="table"> and <form class="form"> without a moment’s hesitation. Looking at Github, one can find plenty of examples of <main class="main">. But why? You can’t have more than one main element, so you already know how to reference it directly. The new elements in HTML5 are nearly a decade old now. We have no excuse for not using them well. We have no excuse for not expecting our fellow developers to know and understand them.

Why reinvent the semantic meanings already defined in the spec in our own classes? Why duplicate them, or muddy them?

An end-user may not notice or care if you stick a form class on your form element, but you should. You should care about bloating your markup and slowing down the user experience. You should care about readability. And if you’re getting paid to do this stuff, you should care about being the sort of professional who doesn’t write redundant slop. “Why should I care” was the death rattle of those advocating for table-based layouts, too.

Start semantic

The first step to semantic, meaningful CSS is to start with semantic, meaningful markup. Classes are arbitrary, but HTML is not. In HTML, every element has a very specific, agreed-upon meaning, and so do its attributes. Good markup is inherently expressive, descriptive, semantic, and meaningful.

If and when the semantics of HTML5 fall short, we have ARIA, specifically designed to fill in the gaps. ARIA is too often dismissed as “just accessibility,” but really—true to its name—it’s about Accessible Rich Internet Applications. Which means it’s chock-full of expanded semantics.

For example, if you want to define a top-of-page header, you could create your own .page-header class, which would carry no real meaning. You could use a header element, but since you can have more than one header element, that’s probably not going to work. But ARIA’s [role=banner] is already there in the spec, definitively saying, “This is a top-of-page header.”

Once you have <header role="banner">, adding an extra class is simply redundant and messy. In our CSS, we know exactly what we’re talking about, with no possible ambiguity.

And it’s not just about those big top-level landmark elements, either. ARIA provides a way to semantically note small, atomic-level elements like alerts, too.

A word of caution: don’t throw ARIA roles on elements that already have the same semantics. So for example, don’t write <button role="button">, because the semantics are already present in the element itself. Instead, use [role=button] on elements that should look and behave like buttons, and style accordingly:

button, [role=button] { … }

Anything marked as semantically matching a button will also get the same styles. By leveraging semantic markup, our CSS clearly incorporates elements based on their intended usage, not arbitrary groupings. By leveraging semantic markup, our components remain reusable. Good markup does not change from project to project.

Okay, but why?

Because:

  • If you’re writing semantic, accessible markup already, then you dramatically reduce bloat and get cleaner, leaner, and more lightweight markup. It becomes easier for humans to read and will—in most cases—be faster to load and parse. You remove your author-defined detritus and leave the browser with known elements. Every element is there for a reason and provides meaning.
  • On the other hand, if you’re currently wrangling div-and-class soup, then you score a major improvement in accessibility, because you’re now leveraging roles and markup that help assistive technologies. In addition, you standardize markup patterns, making repeating them easier and more consistent.
  • You’re strongly encouraging a consistent visual language of reusable elements. A consistent visual language is key to a satisfactory user experience, and you’ll make your designers happy as you avoid uncanny-valley situations in which elements look mostly but not completely alike, or work slightly differently. Instead, if it looks like a duck and quacks like a duck, you’re ensuring it is, in fact, a duck, rather than a rabbit.duck.
  • There’s no context-switching between CSS and HTML, because each is clearly describing what it’s doing according to a standards-based language.
  • You’ll have more consistent markup patterns, because the right way is clear and simple, and the wrong way is harder.
  • You don’t have to think of names nearly as much. Let the specs be your guide.
  • It allows you to decouple from the CSS framework du jour.

Here’s another, more interesting scenario. Typical form markup might look something like this (or worse):

<form class="form" method="POST" action="."> <div class="form-group"> <label for="id-name-field">What’s Your Name</label> <input type="text" class="form-control text-input" name="name-field" id="id-name-field" /> </div> <div class="form-group"> <input type="submit" class="btn btn-primary" value="Enter" /> </div> </form>

And then in the CSS, you’d see styles attached to all those classes. So we have a stack of classes describing that this is a form and that it has a couple of inputs in it. Then we add two classes to say that the button that submits this form is a button, and represents the primary action one can take with this form.

Common vs. optimal form markup What you’ve been using What you could use instead Why .form form Most of your forms will—or at least should—follow consistent design patterns. Save additional identifiers for those that don’t. Have faith in your design patterns. .form-group form > p or fieldset > p The W3C recommends paragraph tags for wrapping form elements. This is a predictable, recommended pattern for wrapping form elements. .form-control or .text-input [type=text] You already know it’s a text input. .btn and .btn-primary or .text-input [type=submit] Submitting the form is inherently the primary action.

Some common vs. more optimal form markup patterns

In light of all that, here’s the new, improved markup.

<form method="POST" action="."> <p> <label for="id-name-field">What’s Your Name</label> <input type="text" name="name-field" id="id-name-field" /> </p> <p> <button type="submit">Enter</button> </p> </form>

The functionality is exactly the same.

Or consider this CSS. You should be able to see exactly what it’s describing and exactly what it’s doing:

[role=tab] { display: inline-block; } [role=tab][aria-selected=true] { background: tomato; } [role=tabpanel] { display: none; } [role=tabpanel][aria-expanded=true] { display: block; }

Note that [aria-hidden] is more semantic than a utility .hide class, and could also be used here, but aria-expanded seems more appropriate. Neither necessarily needs to be tied to tabpanels, either.

In some cases, you’ll find no element or attribute in the spec that suits your needs. This is the exact problem that microformats and microdata were designed to solve, so you can often press them into service. Again, you’re retaining a standardized, semantic markup and having your CSS reflect that.

At first glance, it might seem like this would fail in the exact scenario that CSS naming structures were built to suit best: large projects, large teams. This is not necessarily the case. CSS class-naming patterns place rigid demands on the markup that must be followed. In other words, the CSS dictates the final HTML. The significant difference is that with a meaningful CSS technique, the styles reflect the markup rather than the other way around. One is not inherently more or less scalable. Both come with expectations.

One possible argument might be that ensuring all team members understand the correct markup patterns will be too hard. On the other hand, if there is any baseline level of knowledge we should expect of all web developers, surely that should be a solid working knowledge of HTML itself, not memorizing arcane class-naming rules. If nothing else, the patterns a team follows will be clear, established, well documented by the spec itself, and repeatable. Good markup and good CSS, reinforcing each other.

To suggest we shouldn’t write good markup and good CSS because some team members can’t understand basic HTML structures and semantics is a cop-out. Our industry can—and should—expect better. Otherwise, we’d still be building sites in tables because CSS layout is supposedly hard for inexperienced developers to understand. It’s an embarrassing argument.

Probably the hardest part of meaningful CSS is understanding when classes remain helpful and desirable. The goal is to use classes as they were intended to be used: as arbitrary groupings of elements. You’d want to create custom classes most often for a few cases:

  • When there are not existing elements, attributes, or standardized data structures you can use. In some cases, you might truly have an object that the HTML spec, ARIA, and microformats all never accounted for. It shouldn’t happen often, but it is possible. Just be sure you’re not sticking a horn on a horse when you’re defining .unicorn.
  • When you wish to arbitrarily group differing markup into one visual style. In this example, you want objects that are not the same to look like they are. In most cases, they should probably be the same, semantically, but you may have valid reasons for wanting to differentiate them.
  • You’re building it as a utility mixin.

Another concern might be building up giant stacks of selectors. In some cases, building a wrapper class might be helpful, but generally speaking, you shouldn’t have a big stack of selectors because the elements themselves are semantically different elements and should not be sharing all that many styles. The point of meaningful CSS is that you know from your CSS that that button or [role=button] applies to all buttons, but [type=submit] is always the primary action item on the form.

We have so many more powerful attributes at our disposal today that we shouldn’t need big stacks of selectors. To have them would indicate sloppy thinking about what things truly are and how they are intended to be used within the overall system.

It’s time to up our CSS game. We can remain dogmatically attached to patterns developed in a time and place we have left behind, or we can move forward with CSS and markup that correspond to defined specs and standards. We can use real objects now, instead of creating abstract representations of them. The browser support is there. The standards and references are in place. We can start today. Only habit is stopping us.

Categories: thinktime

Learning from the rejection

Seth Godin - Tue 03rd May 2016 20:05
When someone doesn't say yes, they'll often give you a reason. A common trap: Believe the reason. If you start rebuilding your product, your pitch and your PR based on the stated reason, you're driving by looking in the rear...        Seth Godin
Categories: thinktime

Duck!

Seth Godin - Mon 02nd May 2016 19:05
Perhaps you can't see it, but we can. That 2 x 4, the board set right across that doorway, about 5 feet off the ground. You're running it at it full speed, and in a moment, you're going to slam...        Seth Godin
Categories: thinktime

How to use a microphone

Seth Godin - Sun 01st May 2016 19:05
More than 10,000 people attended the Lincoln Douglas debates, and yet they debated without amplification. It's only quite recently that we began to disassociate talking-to-many from talking loudly. Having a large and varied audience used to mean yelling, it used...        Seth Godin
Categories: thinktime

Errors in scale

Seth Godin - Sat 30th Apr 2016 18:04
A restaurant that's too small for its following creates pent-up demand and can thrive as it lays plans to expand. A restaurant that's too big merely fails. There are occasional counterexamples of ventures that fail because they were too small...        Seth Godin
Categories: thinktime

Your money and your future

Seth Godin - Sat 30th Apr 2016 02:04
Your money: Almost no one knows how to think about money and investing. Squadrons of people will try to confuse you and rip you off. Many will bore you. But Andrew Tobias has written a book that might just change...        Seth Godin
Categories: thinktime

Closing the gate

Seth Godin - Fri 29th Apr 2016 19:04
Sooner or later, tribes begin to exclude interested but unaffiliated newcomers. It happens to religious sects, to surfers and to online communities as well. Nascent groups with open arms become mature groups too set in their ways to evangelize and...        Seth Godin
Categories: thinktime

Transformation tourism

Seth Godin - Thu 28th Apr 2016 19:04
"I bought the diet book, but ate my usual foods." "I filled the prescription, but didn't take the meds." "I took the course... well, I watched the videos... but I didn't do the exercises in writing." Merely looking at something...        Seth Godin
Categories: thinktime

Just a little more

Seth Godin - Wed 27th Apr 2016 18:04
It's often about asking, not about what's needed. Years ago, when I lived in California, I'd go to the grocery store nearly every day. I usually paid by check. Each time, the clerk would ask me for my phone number...        Seth Godin
Categories: thinktime

Prototypal Object-Oriented Programming using JavaScript

a list apart - Wed 27th Apr 2016 00:04

Douglas Crockford accurately described JavaScript as the world’s most misunderstood language. A lot of programmers tend to think of it as not a “proper” language because it lacks the common object-oriented programming concepts. I myself developed the same opinion after my first JavaScript project ended up a hodgepodge, as I couldn’t find a way to organize code into classes. But as we will see, JavaScript comes packed with a rich system of object-oriented programming that many programmers don’t know about.

Back in the time of the First Browser War, executives at Netscape hired a smart guy called Brendan Eich to put together a language that would run in the browser. Unlike class-based languages like C++ and Java, this language, which was at some point called LiveScript, was designed to implement a prototype-based inheritance model. Prototypal OOP, which is conceptually different from the class-based systems, had been invented just a few years before to solve some problems that class-based OOP presented and it fit very well with LiveScript’s dynamic nature.

Unfortunately, this new language had to “look like Java” for marketing reasons. Java was the cool new thing in the tech world and Netscape’s executives wanted to market their shiny new language as “Java’s little brother.” This seems to be why its name was changed to JavaScript. The prototype-based OOP system, however, didn’t look anything like Java’s classes. To make this prototype-based system look like a class-based system, JavaScript’s designers came up with the keyword new and a novel way to use constructor functions. The existence of this pattern and the ability to write “pseudo class-based” code has led to a lot of confusion among developers.

Understanding the rationale behind prototype-based programming was my “aha” moment with JavaScript and resolved most of the gripes I had with the language. I hope learning about prototype-based OOP brings you the same peace of mind it brought me. And I hope that exploring a technique that has not been fully explored excites you as much as it excites me.

Prototype-based OOP

Conceptually, in class-based OOP, we first create a class to serve as a “blueprint” for objects, and then create objects based on this blueprint. To build more specific types of objects, we create “child” classes; i.e., we make some changes to the blueprint and use the resulting new blueprint to construct the more specific objects.

For a real-world analogy, if you were to build a chair, you would first create a blueprint on paper and then manufacture chairs based on this blueprint. The blueprint here is the class, and chairs are the objects. If you wanted to build a rocking chair, you would take the blueprint, make some modifications, and manufacture rocking chairs using the new blueprint.

Now take this example into the world of prototypes: you don’t create blueprints or classes here, you just create the object. You take some wood and hack together a chair. This chair, an actual object, can function fully as a chair and also serve as a prototype for future chairs. In the world of prototypes, you build a chair and simply create “clones” of it. If you want to build a rocking chair, all you have to do is pick a chair you’ve manufactured earlier, attach two rockers to it, and voilà! You have a rocking chair. You didn’t really need a blueprint for that. Now you can just use this rocking chair for yourself, or perhaps use it as a prototype to create more rocking chairs.

JavaScript and prototype-based OOP

Following is an example that demonstrates this kind of OOP in JavaScript. We start by creating an animal object:

var genericAnimal = Object.create(null);

Object.create(null) creates a new empty object. (We will discuss Object.create() in further detail later.) Next, we add some properties and functions to our new object:

genericAnimal.name = 'Animal'; genericAnimal.gender = 'female'; genericAnimal.description = function() { return 'Gender: ' + this.gender + '; Name: ' + this.name; };

genericAnimal is a proper object and can be used like one:

console.log(genericAnimal.description()); //Gender: female; Name: Animal

We can create other, more specific animals by using our sample object as a prototype. Think of this as cloning the object, just like we took a chair and created a clone in the real world.

var cat = Object.create(genericAnimal);

We just created a cat as a clone of the generic animal. We can add properties and functions to this:

cat.purr = function() { return 'Purrrr!'; };

We can use our cat as a prototype and create a few more cats:

var colonel = Object.create(cat); colonel.name = 'Colonel Meow'; var puff = Object.create(cat); puff.name = 'Puffy';

You can also observe that properties/methods from parents were properly carried over:

console.log(puff.description()); //Gender: female; Name: Puffy The new keyword and the constructor function

JavaScript has the concept of a new keyword used in conjunction with constructor functions. This feature was built into JavaScript to make it look familiar to people trained in class-based programming. You may have seen JavaScript OOP code that looks like this:

function Person(name) { this.name = name; this.sayName = function() { return "Hi, I'm " + this.name; }; } var adam = new Person('Adam');

Implementing inheritance using JavaScript’s default method looks more complicated. We define Ninja as a sub-class of Person. Ninjas can have a name as they are a person, and they can also have a primary weapon, such as shuriken.

function Ninja(name, weapon) { Person.call(this, name); this.weapon = weapon; } Ninja.prototype = Object.create(Person.prototype); Ninja.prototype.constructor = Ninja;

While the constructor pattern might look more attractive to an eye that’s familiar with class-based OOP, it is considered problematic by many. What’s happening behind the scenes is prototypal OOP, and the constructor function obfuscates the language’s natural implementation of OOP. This just looks like an odd way of doing class-based OOP without real classes, and leaves the programmer wondering why they didn’t implement proper class-based OOP.

Since it’s not really a class, it’s important to understand what a call to a constructor does. It first creates an empty object, then sets the prototype of this object to the prototype property of the constructor, then calls the constructor function with this pointing to the newly-created object, and finally returns the object. It’s an indirect way of doing prototype-based OOP that looks like class-based OOP.

The problem with JavaScript’s constructor pattern is succinctly summed up by Douglas Crockford:

JavaScript’s constructor pattern did not appeal to the classical crowd. It also obscured JavaScript’s true prototypal nature. As a result, there are very few programmers who know how to use the language effectively.

The most effective way to work with OOP in JavaScript is to understand prototypal OOP, whether the constructor pattern is used or not.

Understanding delegation and the implementation of prototypes

So far, we’ve seen how prototypal OOP differs from traditional OOP in that there are no classes—only objects that can inherit from other objects.

Every object in JavaScript holds a reference to its parent (prototype) object. When an object is created through Object.create, the passed object—meant to be the prototype for the new object—is set as the new object’s prototype. For the purpose of understanding, let’s assume that this reference is called __proto__1. Some examples from the previous code can illustrate this point:

The line below creates a new empty object with __proto__ as null.

var genericAnimal = Object.create(null);

The code below then creates a new empty object with __proto__ set to the genericAnimal object, i.e. rodent.__proto__ points to genericAnimal.

var rodent = Object.create(genericAnimal); rodent.size = 'S';

The following line will create an empty object with __proto__ pointing to rodent.

var capybara = Object.create(rodent); //capybara.__proto__ points to rodent //capybara.__proto__.__proto__ points to genericAnimal //capybara.__proto__.__proto__.__proto__ is null

As we can see, every object holds a reference to its prototype. Looking at Object.create without knowing what exactly it does, it might look like the function actually “clones” from the parent object, and that properties of the parent are copied over to the child, but this is not true. When capybara is created from rodent, capybara is an empty object with only a reference to rodent.

But then—if we were to call capybara.size right after creation, we would get S, which was the size we had set in the parent object. What blood-magic is that? capybara doesn’t have a size property yet. But still, when we write capybara.size, we somehow manage to see the prototype’s size property.

The answer is in JavaScript’s method of implementing inheritance: delegation. When we call capybara.size, JavaScript first looks for that property in the capybara object. If not found, it looks for the property in capybara.__proto__. If it didn’t find it in capybara.__proto__, it would look in capybara.__proto__.__proto__. This is known as the prototype chain.

If we called capybara.description(), the JavaScript engine would start searching up the prototype chain for the description function and finally discover it in capybara.__proto__.__proto__ as it was defined in genericAnimal. The function would then be called with this pointing to capybara.

Setting a property is a little different. When we set capybara.size = 'XXL', a new property called size is created in the capybara object. Next time we try to access capybara.size, we find it directly in the object, set to 'XXL'.

Since the prototype property is a reference, changing the prototype object’s properties at runtime will affect all objects using the prototype. For example, if we rewrote the description function or added a new function in genericAnimal after creating rodent and capybara, they would be immediately available for use in rodent and capybara, thanks to delegation.

Creating Object.create

When JavaScript was developed, its default way of creating objects was the keyword new. Then many notable JavaScript developers campaigned for Object.create, and eventually it was included in the standard. However, some browsers don’t support Object.create (you know the one I mean). For that reason, Douglas Crockford recommends including the following code in your JavaScript applications to ensure that Object.create is created if it is not there:

if (typeof Object.create !== 'function') { Object.create = function (o) { function F() {} F.prototype = o; return new F(); }; } Object.create in action

If you wanted to extend JavaScript’s Math object, how would you do it? Suppose that we would like to redefine the random function without modifying the original Math object, as other scripts might be using it. JavaScript’s flexibility provides many options. But I find using Object.create a breeze:

var myMath = Object.create(Math);

Couldn’t possibly get any simpler than that. You could, if you prefer, write a new constructor, set its prototype to a clone of Math, augment the prototype with the functions you like, and then construct the actual object. But why go through all that pain to make it look like a class, when prototypes are so simple?

We can now redefine the random function in our myMath object. In this case, I wrote a function that returns random whole numbers within a range if the user specifies one. Otherwise, it just calls the parent’s random function.

myMath.random = function() { var uber = Object.getPrototypeOf(this); if (typeof(arguments[0]) === 'number' && typeof(arguments[1]) === 'number' && arguments[0] < arguments[1]) { var rand = uber.random(); var min = Math.floor(arguments[0]); var max = Math.ceil(arguments[1]); return this.round(rand * (max - min)) + min; } return uber.random(); };

There! Now myMath.random(-5,5) gets you a random whole number between −5 and 5, while myMath.random() gets the usual. And since myMath has Math as its prototype, it has all the functionality of the Math object built into it.

Class-based OOP vs. prototype-based OOP

Prototype-based OOP and class-based OOP are both great ways of doing OOP; both approaches have pros and cons. Both have been researched and debated in the academic world since before I was born. Is one better than the other? There is no consensus on that. But the key points everyone can agree on are that prototypal OOP is simpler to understand, more flexible, and more dynamic.

To get a glimpse of its dynamic nature, take the following example: you write code that extensively uses the indexOf function in arrays. After writing it all down and testing in a good browser, you grudgingly test it out in Internet Explorer 8. As expected, you face problems. This time it’s because indexOf is not defined in IE8.

So what do you do? In the class-based world, you could solve this by defining the function, perhaps in another “helper” class which takes an array or List or ArrayList or whatever as input, and replacing all the calls in your code. Or perhaps you could sub-class the List or ArrayList and define the function in the sub-class, and use your new sub-class instead of the ArrayList.

But JavaScript and prototype-based OOP’s dynamic nature makes it simple. Every array is an object and points to a parent prototype object. If we can define the function in the prototype, then our code will work as is without any modification!

if (!Array.prototype.indexOf) { Array.prototype.indexOf = function(elem) { //Your magical fix code goes here. }; }

You can do many cool things once you ditch classes and objects for JavaScript’s prototypes and dynamic objects. You can extend existing prototypes to add new functionality—extending prototypes like we did above is how the well known and aptly named library Prototype.js adds its magic to JavaScript’s built-in objects. You can create all sorts of interesting inheritance schemes, such as one that inherits selectively from multiple objects. Its dynamic nature means you don’t even run into the problems with inheritance that the Gang of Four book famously warns about. (In fact, solving these problems with inheritance was what prompted researchers to invent prototype-based OOP—but all that is beyond our scope for this article.)

Class-based OOP emulation can go wrong

Consider the following very simple example written with pseudo-classes:

function Animal(){ this.offspring=[]; } Animal.prototype.makeBaby = function(){ var baby = new Animal(); this.offspring.push(baby); return baby; }; //create Cat as a sub-class of Animal function Cat() { } //Inherit from Animal Cat.prototype = new Animal(); var puff = new Cat(); puff.makeBaby(); var colonel = new Cat(); colonel.makeBaby();

The example looks innocent enough. This is an inheritance pattern that you will see in many places all over the internet. However, something funny is going on here—if you check colonel.offspring and puff.offspring, you will notice that each of them contains the same two babies! That’s probably not what you intended—unless you are coding a quantum physics thought experiment.

JavaScript tried to make our lives easier by making it look like we have good old class-based OOP going on. But it turns out it’s not that simple. Simulating class-based OOP without completely understanding prototype-based OOP can lead to unexpected results. To understand why this problem occurred, you must understand prototypes and how constructors are just one way to build objects from other objects.

What happened in the above code is very clear if you think in terms of prototypes. The variable offspring is created when the Animal constructor is called—and it is created in the Cat.prototype object. All individual objects created with the Cat constructor use Cat.prototype as their prototype, and Cat.prototype is where offspring resides. When we call makeBaby, the JavaScript engine searches for the offspring property in the Cat object and fails to find it. It then finds the property in Cat.prototype—and adds the new baby in the shared object that both individual Cat objects inherit from.

So now that we understand what the problem is, thanks to our knowledge of the prototype-based system, how do we solve it? The solution is that the offspring property needs to be created in the object itself rather than somewhere in the prototype chain. There are many ways to solve it. One way is that makeBaby ensures that the object on which the function is called has its own offspring property:

Animal.prototype.makeBaby=function(){ var baby=new Animal(); if(!this.hasOwnProperty('offspring')){ this.offspring=[]; } this.offspring.push(baby); return baby; };

Backbone.js runs into a similar trap. In Backbone.js, you build views by extending the base Backbone.View “class.” You then instantiate views using the constructor pattern. This model is very good at emulating class-based OOP in JavaScript:

//Create a HideableView "sub-class" of Backbone.View var HideableView = Backbone.View.extend({ el: '#hideable', //the view will bind to this selector events : { 'click .hide': 'hide' }, //this function was referenced in the click handler above hide: function() { //hide the entire view $(this.el).hide(); } }); var hideable = new HideableView();

This looks like simple class-based OOP. We inherited from the base Backbone.View class to create a HideableView child class. Next, we created an object of type HideableView.

Since this looks like simple class-based OOP, we can use this functionality to conveniently build inheritance hierarchies, as shown in the following example:

var HideableTableView = HideableView.extend({ //Some view that is hideable and rendered as a table. }); var HideableExpandableView = HideableView.extend({ initialize: function() { //add an expand click handler. We didn’t create a separate //events object because we need to add to the //inherited events. this.events['click .expand'] = 'expand'; }, expand: function () { //handle expand } }); var table = new HideableTableView(); var expandable = new HideableExpandableView();

This all looks good while you’re thinking in class-based OOP. But if you try table.events['click .expand'] in the console, you will see “expand”! Somehow, HideableTableView has an expand click handler, even though it was never defined in this class.

You can see the problem in action here: http://codepen.io/anon/pen/qbYJeZ

The problem above occurred because of the same reason outlined in the earlier example. In Backbone.js, you need to work against the indirection created by trying to make it look like classes, to see the prototype chain hidden in the background. Once you comprehend how the prototype chain would be structured, you will be able to find a simple fix for the problem.

In conclusion

Despite prototypal OOP underpinning one of the most popular languages out there today, programmers are largely unfamiliar with what exactly prototype-based OOP is. JavaScript itself may be partly to blame because of its attempts to masquerade as a class-based language.

This needs to change. To work effectively with JavaScript, developers need to understand the how and why of prototype-based programming—and there’s much more to it than this article. Beyond mastering JavaScript, in learning about prototype-based programming you can also learn a lot of things about class-based programming as you get to compare and contrast the two different methods.

Further Reading

Douglas Crockford’s note on protoypal programming was written before Object.create was added to the standard.

An article on IBM’s developerWorks reinforces the same point on prototypal OOP. This article was the prototypal “aha” moment for me.

The following three texts will be interesting reads if you’re willing to dive into the academic roots of prototype-based programming:

Henry Lieberman of MIT Media Labs compares class-based inheritance with prototype-based delegation and argues that prototype-based delegation is the more flexible of the two concepts.

Classes versus Prototypes in Object-Oriented Languages is a proposal to use prototypes instead of classes by the University of Washington’s Alan Borning.

Lieberman’s and Borning’s work in the 1980s appears to have influenced the work that David Ungar and Randall Smith did to create the first prototype-based programming language: Self. Self went on to become the basis for the prototype-based system in JavaScript. This paper describes their language and how it omits classes in favor of prototypes.

 

Footnotes
  • 1. The __proto__ property is used by some browsers to expose an object’s prototype, but it is not standard and is considered obsolete. Use Object.getPrototypeOf() as a standards-compliant way of obtaining an object’s prototype in modern browsers.
Categories: thinktime

Perfect; could be better

Seth Godin - Tue 26th Apr 2016 18:04
When we run a new session of the altMBA, we ask each student to write a short bio and submit a picture. A week later, we share the nicely laid out PDF with the extraordinary class that has been assembled...        Seth Godin
Categories: thinktime

The tidal wave is overrated

Seth Godin - Mon 25th Apr 2016 18:04
Yes, it can lead to wholesale destruction, but it's the incessant (but much smaller) daily tidal force that moves all boats, worldwide. And far more powerful than either is the incredible impact of seepage, of moisture, of the liquid that...        Seth Godin
Categories: thinktime

The other kind of power move

Seth Godin - Sun 24th Apr 2016 18:04
In the common vernacular, a power move is something that gets done to you. The person with power demands an accommodation, or switches the venue, or has an admin call you instead of calling you himself. Someone with a resource...        Seth Godin
Categories: thinktime

Supply and demand

Seth Godin - Sat 23rd Apr 2016 19:04
Just because you have a supply (a skill, an inventory, a location) that doesn't necessarily mean you are entitled to demand. The market decides what it wants. You can do your best to influence that choice, but it's never (alas)...        Seth Godin
Categories: thinktime

Turning paradoxes into problems

Seth Godin - Fri 22nd Apr 2016 19:04
A problem is open to a solution. That what makes it a problem. A paradox, on the other hand, is gated by boundaries that make a solution impossible. If you've been working on a situation, chewing on it, throwing everything...        Seth Godin
Categories: thinktime

Processing feedback

Seth Godin - Thu 21st Apr 2016 23:04
This is one of the most important untaught skills available to each of us. Three times in a row, a salesperson is rejected by one prospect after another. A customer complains to a company that its website is not working...        Seth Godin
Categories: thinktime

Numbers (and the magic of measuring the right thing)

Seth Godin - Wed 20th Apr 2016 18:04
What you measure usually gets paid attention to, and what you pay attention to, usually gets better. Numbers supercharge measurement, because numbers are easy to compare. Numbers make it difficult to hide. And hence the problem. Income is easy to...        Seth Godin
Categories: thinktime

OOUX: A Foundation for Interaction Design

a list apart - Wed 20th Apr 2016 00:04

There’s a four-year story behind my current design process, something I introduced last year on A List Apart—“Object-Oriented UX.” The approach advocates designing objects before actions. Now it’s time to get into the deeper benefits of OOUX and the smooth transition it can set up while shifting from object-based system design to interaction design.

The “metaphor,” once found, is a perfectly definite thing: a collection of objects, actions on objects, and relationships between objects. Dave Collins, Designing Object-Oriented User Interfaces (1995)

Imagine you’re designing a social network that helps chefs trade recipes requiring exotic ingredients. With good ol’ fashioned research, you develop a solid persona (Pierre, the innovator-chef, working in a gourmet restaurant) and you confirm the space in the market. You understand the industry and the project goals. Now it’s time to put marker to whiteboard.

Where would you start designing?

Would you start by sketching out an engaging onboarding process for chefs? We do need chefs to make this thing successful—no chefs, no network! So maybe we start by making sure their first interaction is amazing.

Or maybe you start with one of the most frequent activities: how a chef posts a new recipe. And that could easily lead you to sketching the browsing experience—how will other chefs find new recipes?

Three or four years ago, I’d start by storyboarding a critical user path. I’d start with the doing.

Pre-OOUX, my initial design-thinking would look something like this. I’d figure out the interaction design while figuring out what a recipe actually should be.

I imagine many other user experience designers begin the same way, by designing how someone would use the thing. One interaction flow leads to the design of another interaction flow. Soon, you have a web of flows. Iterate on those flows, add some persistent navigation, and voilà!—you have a product design.

But there is a problem with this action-first approach. We are designing our actions without a clear picture of what is being acted on. It’s like the sentence, “Sally kicked.” We’ve got our subject (the user) and we’ve got our verb (the action).  But where’s the object? Sally kicked what? The ball? Her brother? A brain-hungry zombie?

When we jump right into actions, we run the risk of designing a product with a fuzzy reflection of the user’s mental model. By clearly defining the objects in our users’ real-world problem domain, we can create more tangible and relatable user experiences.

These days, a lot happens before I begin sketching user flows (in this article, I use “user flow” and “interaction flow” interchangeably). I first define my user, asking, “Who’s Sally?” Next, I figure out her mental model, meaning all the things (objects) that the problem is made of, all the things she sees as part of the solution, and how they relate to one another. Finally, I design the interactions. Once I understand that Sally is a ninja armed with only a broomstick, and that she is faced with a team of zombies, I can better design the actions she’ll take.

In retrospect, I feel like I was doing my job backwards for the first two-thirds of my career, putting interaction flows before building an object-oriented framework. Now, I would figure out the system of chefs, recipes, and ingredients before worrying about the chef onboarding process or how exactly a chef posts a recipe. How do the objects relate to one another? What content elements comprise each object? Which objects make up my MVP and which objects can I fold in later? Finally, what actions does a user take on each object?

That’s what Object Oriented UX is all about—thinking in terms of objects before actions. In my previous article, we learned how to define objects and design a framework based on those objects. This time, we’re exploring how to smoothly transition from big-picture OOUX to interaction design by using a very simple tool: the CTA Inventory.

What’s a CTA Inventory, and why is it important?

Calls to action (CTAs) are the main entry points to interaction flows. If an interaction flow is a conversation between the system and the user, the CTA is a user’s opening line to start that conversation. Once you have an object framework, you can add possible CTAs to your objects, basically putting a stake in the ground that says, “Interaction design might go here.” These stakes in the ground—the CTAs—can be captured using a CTA Inventory.

A CTA Inventory is a bridge from big-picture OOUX to detailed interaction design.

A CTA Inventory is just a fancy list of potential CTAs organized around your objects. Since most (all?) interactions involve creating, manipulating, or finding an object, we create this inventory by thinking about what a user wants to do in our system—specifically, what a user wants to do to objects in our system.

Creating a CTA Inventory does two things. First, it helps us shift gears between the holistic nature of system design to the more compartmentalized work of interaction design. Second, it helps us:

  1. think about interactions creatively;
  2. validate those interactions;
  3. and ultimately write project estimates with greater accuracy.

Let’s explore these three benefits a little more before creating our own CTA Inventory.

Creative constraints improve brainstorming

Simply understanding your objects will help you determine the things that a user might do with them. We know that Sally wants to destroy zombies—but it’s only after we’ve figured out that these are the fast, smart, light-averting zombies that we can be prepared to design exactly how she’ll do it.

When we think about interactions in the context of an object, we give ourselves a structure for brainstorming. When we apply the constraints of the object framework, we’re likely to be more creative—and more likely to cover all of our bases. Brainstorm your actions object by object so that innovative features are less likely to fall through the cracks.

For example, let’s think about the object “ingredient” in our Chef Network app. What are all the things that Pierre might want to do to an ingredient?

  • Mark the ingredient as a favorite.
  • Claim he’s an expert on the ingredient.
  • Add the ingredient to a shopping list.
  • Check availability of the ingredient at local stores.
  • Follow the ingredient to see new recipes that are posted using this ingredient.
  • Add a tip for using this ingredient.

By using the object framework, I might uncover functionality I wouldn’t otherwise have considered if my brainstorming was too broad and unconstrained; structure gives creative thinking more support than amorphous product goals and squishy user objectives.

Validate actions early

Good news. You can user-test your system of objects and the actions a user might take on them before spending long hours on interaction design. Create a prototype that simply lets users navigate from one object to another, exploring the framework (which is a significant user goal in itself). Through observation and interviews, see if your system resonates with their mental model. Do you have the right objects and do their relationships make sense? And are the right “buttons” on those objects?

Armed with a simple prototype of your interconnected objects and their associated CTAs, you now have a platform to discuss functionality with users—without all the hard work of prototyping the actual interactions. In a nutshell: talk to your users about the button before designing what happens when they click it.

Interaction design can be some of the most difficult, time-consuming, devil-in-the-details design work. I personally don’t want to sweat through designing a mechanism for following chefs, managing alerts from followed chefs, and determining how the dreaded unfollow will work…if it turns out users would rather follow ingredients.

Estimate with interaction design in mind

As we’ve established, interaction design is a time- and resources-devouring monster. We have to design a conversation between the system and the user—an unpredictable user who requires us to think about error prevention, error handling, edge cases, animated transitions, and delicate microinteractions. Basically, all the details that ensure they don’t feel dumb or think that the system is dumb.

The amount and complexity of interaction design your product requires will critically impact your timeline, budget, and even staffing requirements, perhaps more than any other design factor. Armed with a CTA Inventory, you can feel confident knowing you have solid insight into the interaction design that will be handled by your team. You can forecast the coming storm and better prepare for it.

So, do you love this idea of better brainstorming, early validation, and estimating with better accuracy? Awesome! Let’s look at how to create your amazing CTA Inventory. First, we will discuss the low-fidelity initial pass (which is great to do collaboratively with your team). Next, we will set up a more formal and robust spreadsheet version.

CTA Inventory: low-fidelity

If you haven’t read my primer on object mapping, now would be a great time to go and catch up! I walk you through my methodology for:

  • extracting objects from product goals;
  • defining object elements (like core content, metadata, and nested objects);
  • and prioritizing elements.

The walk-through in the previous article results in an object map similar to this:

An object map before layering on a CTA Inventory.

I’ve used outlined blue stickies to represent objects; yellow stickies to represent core content; pink stickies to indicate metadata; and additional blue stickies to represent nested objects.

A low-fidelity CTA Inventory is quite literally an extension of the object mapping exercise; once you’ve prioritized your elements, switch gears and begin thinking about the CTAs that will associate with each object. I use green stickies for my CTAs (green for go!) and stack them on top of their object.

An object map with a quick, low-fidelity CTA Inventory tacked on. Potential CTAs are on green stickies placed next to each object.

This initial CTA brainstorming is great to do while workshopping with a cross-functional team. Get everyone’s ideas on how a user might act on the objects. You might end up with dozens of potential CTAs! In essence, you and your team will have a conversation about the features of the product, but within the helpful framework of objects and their CTAs. Essentially, you are taking that big, hairy process of determining features, then disguising it as a simple, fun, and collaborative activity: “All we’re doing is brainstorming what buttons need to go on our objects! That’s all! It’s easy!” 

Each object might need roughly 10–15 minutes, so block out an hour or two to discuss CTAs if your system has three to five objects. You’ll be surprised at the wealth of ideas that emerge! You and your team will gain clarity about what your product should actually do, not to mention where you disagree (which is valuable in its own right).

In our chef example, something pretty interesting happened while the team was hashing out ideas. During the CTA conversation about “ingredient,” we thought that perhaps it would be useful if chefs could suggest a substitute ingredient (see circled green sticky below). “Fresh out of achiote paste? Try saffron instead!” But with that in mind, those “suggested substitute ingredients” need to become part of the ingredient object. So, we updated the object map to reflect that (circled blue sticky).

After brainstorming CTAs, we needed to add a nested object on “ingredient” for “ingredients that could be substituted.”

Although I always begin with my objects and their composition, CTA brainstorming tends to loop me back around to rethinking my objects. As always, be prepared to iterate!

CTA Inventory: high-fidelity

CTAs can get complicated; how and when they display might be conditional on permissions, user types, or states of your object. Even in our simple example above, some CTAs will only be available to certain users.

For example, if I’m a chef on an instance of one of my own recipe objects, I will see “edit” and “delete” CTAs, but I might not be able to “favorite” my own recipe. Conversely, if I’m on another chef’s recipe, I won’t be able to edit or delete it, but I will definitely want the option to “favorite” it.

In the next iteration of our CTA Inventory, we move into a format that allows us to capture more complexities and conditions. After a first pass of collaborative, analogue brainstorming about CTAs, you might want to get down to business with a more formal, digitized CTA Inventory.

A detailed CTA Inventory for our chef network example. Dig in deeper on the actual Google Sheet.

Using a Google spreadsheet, I create a matrix (see above) that lets me capture thoughts about each object-derived CTA and the inevitable interaction flows for each one:

  • Why do we even have this CTA? What’s the purpose, and what user or business goal does it ladder up to?
  • Who will trigger this CTA? A certain persona or user type? Someone with a special permission or role?
  • Where will the CTAs live? Where are the obvious places a user will trigger this interaction flow? And are there other creative places we should consider putting it, based on user needs?
  • How much complexity is inherent in the interaction flow triggered by this CTA? This can help us estimate level of effort.
  • What is the priority of this interaction flow? Is this critical to launch, slated for a later phase, or a concept that needs to be researched and validated?
  • What questions and discussion points does this CTA raise?

Before you start designing the interactions associated with each of your CTAs, get comfortable with the answers to these questions. Build an object-oriented prototype and validate the mental model with users. Talk to them and make sure that you’ve included the right doorways to interaction. Then you will be perfectly positioned to start sketching and prototyping what happens when a user opens one of those doors.

A solid foundation for designing functionality

You’ve collaboratively mapped out an elegant object-oriented design system and you’ve created a thorough CTA Inventory. You built a rough, clickable prototype of your system. With real users, you validated that the system is a breeze to navigate. Users pivot gracefully from object to object and the CTAs on those objects make sense for their needs. Life is good.

But OOUX and a CTA Inventory will not help you design the interactions themselves. You still have to do that hard work! Now, though, as you begin sketching out interaction flows, you can feel confident that the functionality you are designing is rooted in solid ground. Because your CTA Inventory is a prioritized, team-endorsed, IxD to-do list, you’ll be more proactive and organized than ever.

Most important, users getting things done within your system will feel as if they are manipulating tangible things. Interacting will feel less abstract, less fuzzy. As users create, favorite, add, remove, edit, move, and save, they will know what they’re doing—and what they’re doing it to. When you leverage an object-based CTA Inventory, your product designs and your design process will become more elegant, more streamlined, and more user-friendly.

Categories: thinktime

Abstaining

Seth Godin - Tue 19th Apr 2016 21:04
Not voting leads to an outcome as much as voting does. You're still responsible, even if you didn't actively participate. In any situation, not stating your opinion allows things to move forward. Silence is not nothing, it is still an...        Seth Godin
Categories: thinktime

Pages

Subscribe to kattekrab aggregator