Objectify

Behaviour Driven Development for JavaScript: Part Two

MarcoEmrich
BDD

In the concluding part of a two part series, Marco Emrich shows you how you can use JavaScript as a vehicle to carry you into the wonderful world of BDD.

Marco Emrich is an author, trainer, software developer
and project manager with an 
academic degree in
computer science. He speaks at various IT-conferences (OOP, Seacon,
Webtech, SoCraTes), writes articles (ObjektSpektrum, RailsWay, PHP
& Web Magazine) and facilitates code retreats. This
extract is taken from his eBook Behaviour
Driven Development with JavaScript
, which was released by
our sister publishing arm, Developer.Press. 

This article is the second in a two part series – to get up to
speed, you can find Part One here. 

JavaScript is object oriented

JS is an object oriented language; this differs
from being class oriented. If you have a background in industrial
languages like C++ or Java, you might think JS is missing
something. I thought so for a long time too.

Actually popular languages like C++ or Java have
less powerful implementations of OOP-concepts, which they inherited
from the mighty Smalltalk. The development of OOP did not even stop
with Smalltalk. There are many languages that took the concepts
from Smalltalk even further. These concepts are mostly used only in
academia.

One improvement was to get rid of classes.
Languages like Cecil, Self or more recently IO experimented with a
prototypical approach, which also found its way into JS.

You might still argue that JS does not have the best
implementation of prototyping and an ugly syntax compared to
languages like Self. The prototypical inheritance concept itself
is, however, a great improvement.
 

The old way

The old way of creating objects was to supply a
constructor function. This was targeted at Java and C++ developers
to provide them with a coding style that they were used to. But the
constructor function also had its downsides. Therefore ECMAScript5
introduced a better way for creating objects.

So how did it look before ECMAScript5 stepped
in? Let’s assume you have built a shop and now you need to start
selling various products online. In the old days, you would have
written something like this:

var Product = function(name) {
this.name = name;
};
Product.prototype.showName = function() {alert(this.name);};
var myProduct = new Product("Super Fancy TV");
myProduct.showName(); 

Constructor function
(javascript_refresher/product_in_ecma3.js)

Actually, this isn’t that bad. You have a constructor to
create your objects and attach methods to the prototype. All
individual products have these methods, but there are several weak
points to consider.
 

  • There are no private
    attributes
    in the JS language. The value of name can
    be changed at any time from the outside.
  • The methods
    are scattered. Even if you put
    them all in one place, there is no single structure
    to
    define your object concepts – like a class in many other
    object
    oriented languages.

  • You can easily
    forget
    to use the “new”
    keyword
    .
    This won’t throw an error, it just
    leads to completely different
    behaviour and probably
    to some really nasty bugs that are hard to

    find.
  • Inheritance
    will provide even more problems. There isn’t an
    agreed way in the
    JS-community of how to do it
    properly.

Because
of these concerns, many developers have created libraries,
frameworks and tools that provide all types of object creation and
instantiation logic. Many of them introduced classes (for example
Prototype5 or Coffeescript6).

You can take this path if you want, but I
wouldn’t recommend it. It may be hard to believe, but prototypical
inheritance is actually much easier than class-based – and even
provides additional benefits. Just take a look at other
prototypical languages like IO or Self. It is the old JS syntax
that made prototypes hard to use.

A better approach was pioneered by Douglas
Crockford. He wrote a short Object.create method that has made its
way into the ES5 standard in a slightly extended
form.
 

Object.create

The good news is that you don’t need a modern browser with
an ES5 implementation. There is a polyfill from the Mozilla
Developer Network (MDN). A polyfill is a technique to make modern
features available to older browsers. You can find other polyfills
on the Modernizr-Wiki.

The Object.create-polyfill from MDN allows you
to use the new way of creating objects in older browsers, such as
IE8. This is important when you consider that IE7/IE8 still has a
combined market share of about 7% (January 2013). It is not an
issue if you only target IE9+, Firefox, Chrome, Safari or Opera
users. If you are in doubt, take a look at the compatibility
chart.

if (!Object.create) {
Object.create = function (o) {
if (arguments.length > 1) {
throw new Error('Object.create implementation only accepts the
first parameter.');
}
function F() {}
F.prototype = o;
return new F();
};
} 

Just include the polyfill from listing 1.6 to
ensure that you have the Object.create function. The first line of
the snippet checks if Object.create is already there. This
ensures that the polyfill won’t override the native implementation
if the current browser provides one. If you need additional
polyfills for other ES5-features, you can use either Kris Kowal’s
or David de Rosier’s es5-shim.
 

Solo objects

Let’s take another look at the shop project. If you would
like to create only one product, there is no need for
Object.create. Just create the object directly:

var myProduct = {
price: 99.50,
name: 'Grindle 3'
};

However,
this isn’t the best option. You can manipulate the properties of
the objects easily from the outside but there isn’t a way to check
or transform the assigned values. Take a look at this
assignment:
 

MyProduct.price = -20;

A mistake like this one would
mean that your company sells a lot of products fast and has really
happy customers – customers that receive 20 bucks with every
purchase. Your company wouldn’t be able to do that for
long!

Years of experience in object oriented programming and
design taught us to separate the inner state of an
object from its outer interface. You usually want
to make attributes private and provide some getter- and
setter-methods.

Getters and setters

ES5 provides a great concept for accessing
properties with getters and setters. The sad news is that there is
no way to get them to run in older browsers – you can’t just use a
polyfill. So for the next two years or so, most of us don’t have
the luxury to use it. In the meantime, there are many approaches
you could use (see [Stefanov 2010]). All of them have their own
distinct set of advantages and disadvantages. There is no single
solution, so it comes down to a matter of taste. Here is what I
usually do:

Prefix attributes with an
underscore
, for example _price. This is just a convention
to mark the attribute as private. You should never call them from
outside the object. Violations to this rule are usually easy to
spot. There are also more sophisticated approaches using
closure-based patterns to archive real privacy (for example. in
[Stefanov 2010]). My opinion is that they aren’t worth the effort,
most of the time.

Provide a setter method that starts with
“set”
, for example setPrice(value). There is no way in
older browsers to overwrite the assignment operator =. So this is
the next best thing. Java and C++ programmers are used to
it.

Provide a getter method with the name of
the original attribute
, for example price(). Many
programmers prefer prefixing the method with “get”. I think this
isn’t necessary in JS and just makes the code less readable – your
mileage may vary. 
Sometimes an attribute might be
for internal use only, or you want it to be ready-only. In this
case just leave out the appropriate methods. So listing 1.8 shows a
better implementation.

var myProduct = {
_price: 99.50,
_name: 'Grindle 3',
price: function() {return this._price;},
name: function() {return this._name;},
setPrice: function(p) {this._price = p;},
}; 

Solo object with getters and setters
(javascript_refresher/product_with_getters_and_setters.js). 
If
you want to check the price before setting it, you can now easily
do this:

setPrice: function(p) {
if (p <= 0) {
throw new Error("Price must be positive");
}
this._price = p;
} 

setPrice-method with check
(javascript_refresher/product_with_price_check.js).

The real ECMAScript5 implementation is even
nicer (listing 1.10). It has the added benefit of calling the
getters and setters implicitly, for example myProduct.price =
85.99. Finally, JS supports the uniform access
principle
! In this tutorial however, we will stick to the
first workaround mentioned since you can’t backport this language
feature.

var myProduct = {
...
get price() {return this._price;},
set price(p) {
if (p <= 0) { throw new Error("Price must be positive"); }
this._price = p;
},
... 

Prototypes

A real shop will have many products and you don’t want to
create them all from scratch. You will need a place where you can
put common structure and behaviour. The usual pattern in JS is to
create a parent object for this – a prototype of a
product, where all other products are derived from. With
Object.create you build new products from it.

var Product = {
_price: 0,
_name: '',
price: function() {return this._price;},
name: function() {return this._name;},
setPrice: function(p) {this._price = p;},
setName: function(n) {this._name = n;}
};
var product1 = Object.create(Product);
product1.setName('Grindle 3');
product1.setPrice(99.50);
var product2 = Object.create(Product);
product2.setName('yPhone 7');
product2.setPrice(599.99);

There is also the convention to start such a
prototype with an upper letter, like classes in more traditional
languages (i.e. var Product instead of var
product
).

Initializers

In order to set all attributes of a new product object to
their correct values, you would need to call all its settermethods
– a major inconvenience. You should build an initializer-method
instead. Such a method could be compared to a constructor- method
in other languages.

var Product = {
...
init: function(name, price) {
this._name = name;
this._price = price;
return this;
},
...
};
var aProduct = Object.create(Product).init('Grindle 3', 99.50);

Even
better, overwrite the create-Method of Product to
encapsulate creation and initialization.

var Product = {
...
create: function(name, price) {
return Object.create(this).init(name, price);
},
...
};
var aProduct = Product.create('Grindle 3', 99.50);

A
great advantage of the prototypical approach is the unification of
instantiation and inheritance. You don’t need anything special you
can just use Object.create for inheritance as
well.
 

var Product = {
...
};
var Book = Object.create(Product);
Book._author = null;
Book._numPages = null;
Book.setAuthor = function(author) {this._author = author;};
Book.setNumPages = function(num_pages) {this._numPages = num_pages;};
Book.author = function() {return this.author();};
Book.numPages = function() {return this.numPages();};

Book is a new object that is derived
from Product. Instead of setting specific values, like
name and price, it gets additional structure and
behaviour – author and numPages – with getters
and setters.

The downside is that calling Book
several times is redundant and the whole syntax is quite different
from defining the base object. Therefore, you usually build a small
extend function that makes inheritance a little more
convenient (listing 1.15). Again, you wouldn’t need this in real
ES5. The real Object.create allows for a second argument
containing the extensions.

tip: Alternative implementations of
Object.extend are available in jQuery
(http://api.jquery.com/jQuery. extend) and Underscore.js
(http://underscorejs.org/#extend). If you already have one
of these libs in your project, it makes sense to use them
instead.

Object.prototype.extend = function(props) {
for (var prop in props) { this[prop] = prop; }
return this;
};

You
can now refactor your code using the new extend
method.

var Product = {
_price: 0,
_name: '',
price: function() {return this._price;},
name: function() {return this._name;},
setPrice: function(p) {this._price = p;},
setName: function(n) {this._name = n;}
};
var Book = Object.create(Product).extend({
_author: null,
_numPages: null,
setAuthor: function(author) {this._author = author;},
setNumPages: function(num_pages) {this._numPages = num_pages;},
author: function() {return this.author();},
numPages: function() {return this.numPages();}
});
console.log(Product);
console.log(Book);

(javascript_refresher/product_inheritance_with_extend.js).

Inside prototypical inheritance

The objects and prototype concept has many
advantages over static class-based approaches, like:

  • Unification of inheritance and
    instantiation
    . You can use the same mechanism
    (Object.create) to inherit from prototypes or build instances from
    it (similar to class usage). Actually – it is the same
    thing.

  • Inheritance of values. You can
    inherit values from prototypes; there is no need to set defaults in
    a constructor.

  • Runtime modification of
    prototypes
    . There is no difference between run-time and
    compile-time in JS. You can modify prototypes during program
    execution, while more static languages only allow changes to
    classes before the compiler runs. This isn’t a direct advantage of
    prototypical inheritance it’s the dynamic nature of JS. There are
    even class-based languages available that allow for runtime
    modification of classes – Ruby or Smalltalk would fit the bill. But
    JavaScript’s objects-only-approach makes this much simpler.This is
    a big gain if you like to do any metaprogramming.

The
best advantage of the “objects only” approach is its simplicity.
Let’s take a look at the inner workings: First of all, you don’t
need any special handling for methods. Methods are just object
properties that happen to contain functions. So it doesn’t matter
if you look up a simple number or call a method. Now take a look at
how JS decides which method to call. Listing 1.17 demonstrates the
principle.

var Product = {
init: function(name) {
this._name = name;
return this;
},
_name: '',
name: function() { return this._name; },
setName: function(n) { this._name = n; }
};
var Book = Object.create(Product).extend({
init: function(name, author) {
Product.init(name);
this._author = author;
return this;
},
author: null,
setAuthor: function(author) { this._author = author; },
author: function() { return this.author(); }
});
var myBook = Object.create(Book).init('Lords of the Rings', 'J.R.R. Tolkien');
myBook.mostImportantHobbit = "Frodo"; 

If you try to get the value of
myBook.mostImortantHobbit, the JavaScript-engine just
takes a look at the myBookobject and returns the
value.

A look-up for myBook.name() requires more steps.
The JS-engine didn’t find the name-property on the
myBookobject, so it needs to look it up in its prototype
Book. It isn’t there either, so it follows up the
prototype-chain till it finds it. The property name
actually is available in Book’s prototype
Product. So JS interprets the parenthesis and calls the
function contained in name. The function gets executed in
the context of the myBook. Therefore this._name
refers to the value “Lord of the Rings”. Even if JS does
need to execute several steps, they are easy to understand. Always
follow the prototype-chain.

Instantiation and inheritance do not need to be
handled differently.

Other things to consider

In a real project there are many other things to
consider. You usually want to keep your code in namespaces. To
manage your namespaces and file dependencies you might want to use
a tool that provides AMD (Asynchronous Module Definition).

RequireJS
or curl
are popular ones.

You might even like to use one of the bigger
base frameworks like
Ember, Backbone or
AngularJS. I
won’t delve into these things here, since they are not necessary to
understand behaviour driven development. I urge you to really take
a look into better ways to structure you code bases. It can make a
big difference.

Alternate styles

JS is a very flexible language, supporting
various programming paradigms (at least functional and object
oriented). This allows for many different approaches to software
design and development. You might like a pure functional approach,
or do OOP with prototypes, or use a library for class-based
object-orientation instead. You might consider using mixings/traits
or other advanced constructs. Perhaps you will consider using a
preprocessor/transpiler like Harmonizr for writing
ECMAScript6/Harmony Code, or even trying out CoffeeScript. For the
purpose of this tutorial, it doesn’t matter. The behaviour driven
approach should work using any of these traits or
mixings.

So take my JS-style here with a pinch of salt; I kept it a
little bit simpler than in real projects. Consider it a vehicle to
carry you into the wonderful world of behaviour driven
development.

 

 



 



 

 

 








 



 

 




 

 



 


Author
Comments
comments powered by Disqus