Driven

Black Box Driven Development in JavaScript

Sooner or later every developer finds the beauty of the design patterns. Also, sooner or later the developer finds that most of the patterns are not applicable in their pure format. Very often we use variations. We change the well-known definitions to fit in our use cases. I know that we (the programmers) like buzzwords. Here is a new one – Black Box Driven Development or simply BBDD. I started applying the concept before a couple of months, and I could say that the results are promising. After finishing several projects, I started seeing the good practices and formed three principles.

What is a black box?

Before to go with the principles of the BBDD let’s see what is meant by a black box. According to Wikipedia:

In science and engineering, a black box is a device, system or object which can be viewed in terms of its input, output and transfer characteristics without any knowledge of its internal workings.

In programming, every piece of code that accepts input, performs actions and returns an output could be considered as a black box. In JavaScript, we could apply the concept easily by using a function. For example:

var Box = function(a, b) {
    var result = a + b;
    return result;
}

This is the simplest version of a BBDD unit. It is a box that performs an operation and returns output immediately. However, very often we need something else. We need continuous interaction with the box. This is another kind of box that I use to call living black box.

var Box = function(a, b) {
    var api = {
        calculate: function() {
            return a + b;
        }
    };
    return api;
}

We have an API containing all the public functions of the box. It is identical to the revealing module pattern. The most important characteristic of this pattern is that it brings encapsulation. We have a clear separation of the public and private objects.

Now that we know what a black box is, let’s check out the three principles of BBDD.

Principle 1: Modulize everything

Every piece of logic should exist as an independent module. In other words – a black box. In the beginning of the development cycle it is a little bit difficult to recognize these pieces. Spending too much time in architecting the application without having even a line of code may not produce good results. The approach that works involves coding. We should sketch the application and even make part of it. Once we have something we could start thinking about black boxing it. It is also much easier to jump into the code and make something without thinking if it is wrong or right. The key is to refactor the implementation till you feel that it is good enough.

Let’s take the following example:

$(document).ready(function() {
    if(window.localStorage) {
        var products = window.localStorage.getItem('products') || [], content = '';
        for(var i=0; i<products.length; i++) {
            content += products[i].name + '<br />';
        }
        $('.content').html(content);
    } else {
        $('.error').css('display', 'block');
        $('.error').html('Error! Local storage is not supported.')
    }
});

We are getting an array called products from the local storage of the browser. If the browser does not support local storage, then we show a simple error message.

The code as it is, is fine, and it works. However, there are several responsibilities that are merged into a single function. The first optimization that we have to do is to form a good entry point of our code. Sending just a newly defined closure to the $(document).ready is not flexible. What if we want to delay the execution of our initial code or run it in a different way. The snippet above could be transformed to the following:

var App = function() {
    var api = {};
    api.init = function() {
        if(window.localStorage) {
            var products = window.localStorage.getItem('products') || [], content = '';
            for(var i=0; i<products.length; i++) {
                content += products[i].name + '<br />';
            }
            $('.content').html(content);
        } else {
            $('.error').css('display', 'block');
            $('.error').html('Error! Local storage is not supported.');
        }
        return api;
    }
    return api;
}
 
var application = App();
$(document).ready(application.init);

Now, we have better control over the bootstrapping.

The source of our data at the moment is the local storage of the browser. However, we may need to fetch the products from a database or simply use a mock-up. It makes sense to extract this part of the code:

var Storage = function() {
    var api = {};
    api.exists = function() {
        return !!window && !!window.localStorage;
    };
    api.get = function() {
        return window.localStorage.getItem('products') || [];
    }
    return api;
}

We have two other operations that could form another box – setting HTML content and show an element. Let’s create a module that will handle the DOM interaction.

var DOM = function(selector) {
    var api = {}, el;
    var element = function() {
        if(!el) {
            el = $(selector);
            if(el.length == 0) {
                throw new Error('There is no element matching "' + selector + '".');
            }
        }
        return el;
    }
    api.content = function(html) {
        element().html(html);
        return api;
    }
    api.show = function() {
        element().css('display', 'block');
        return api;
    }
    return api;
}

The code is doing the same thing as in the first version. However, we have a test function element that checks if the passed selector matches anything in the DOM tree. We are also black boxing the jQuery element that makes our code much more flexible. Imagine that we decide to remove jQuery. The DOM operations are hidden in this module. It is worth nothing to edit it and start using vanilla JavaScript for example or some other library. If we stay with the old variant, we will probably go through the whole code base replacing code snippets.

Here is the transformed script. A new version that uses the modules that we’ve created above:

var App = function() {
    var api = {},
        storage = Storage(),
        c = DOM('.content'),
        e = DOM('.error');
    api.init = function() {
        if(storage.exists()) {
            var products = storage.get(), content = '';
            for(var i=0; i<products.length; i++) {
                content += products[i].name + '<br />';
            }
            c.content(content);
        } else {
            e.content('Error! Local storage is not supported.').show();
        }
        return api;
    }
    return api;
}

Notice that we have separation of responsibilities. We have objects that play roles. It is easier and much more interesting to work with such codebase.

Principle 2: Expose only public methods

What makes the black box valuable is the fact that it hides the complexity. The programmer should expose only methods (or properties) that are needed. All the other functions that are used for internal processes should be private.

Let’s get the DOM module above:

var DOM = function(selector) {
    var api = {}, el;
    var element = function() {}
    api.content = function(html) {}
    api.show = function() {}
    return api;
}

When a developer uses our class, he is interested in two things – changing the content and showing a DOM element. He should not think about validations or change CSS properties. In our example, there are private variable el and private function element. They are hidden from the outside world.

Principle 3: Use composition over inheritance

One of the popular ways to inherit classes in JavaScript uses the prototype chain. In the following snippet, we have class A that is inherited by class C:

function A(){};
A.prototype.someMethod = function(){};
 
function C(){};
C.prototype = new A();
C.prototype.constructor = C;

However, if we use the revealing module pattern, it makes sense to use composition. It is because we are dealing with objects and not functions (* in fact the functions in JavaScript are also objects). Let’s say that we have a box that implements the observer pattern, and we want to extend it.

var Observer = function() {
    var api = {}, listeners = {};
    api.on = function(event, handler) {};
    api.off = function(event, handler) {};
    api.dispatch = function(event) {};
    return api;
}
 
var Logic = function() {
    var api = Observer();
    api.customMethod = function() {};
    return api;
}

We get the required functionality by assigning an initial value to the api variable. We should notice that every class that uses this technique receives a brand new observer object so there is no way to produce collisions.

Summary

Black box driven development is a nice way to architect your applications. It provides encapsulation and flexibility. BBDD comes with a simple module definition that helps organizing big projects (and teams). I saw how several developers worked on the same project, and they all built their black boxes independently.

View full post on Mozilla Hacks – the Web developer blog

VN:F [1.9.22_1171]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

Integrations Manager for Tech Driven Social Media firm in NYC!

CyberCoders New York, NY
Job description: …proven track record in designing engaging product offerings, have web and/or software development experience, experience creating complex wireframes…for executive management- Interact with Software Development teams, marketing teams, sales and operations teams and customers… View full post on Dice.com – Web Marketing

View full post on WebProJobs.org

VN:F [1.9.22_1171]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

Web Developer – ASP.NET – C# – PHP – Technology Driven Company

FL-Tampa, Web Developer – ASP.NET – C# – PHP – Technology Driven Company Our client delivers IT solutions to Technology providers nationwide! As a rapidly growing company our client is seeking a Web Developer for its Tampa, FL location to join its growing internal development team. We are the premier solutions provider to the small and medium sized business community. We develop software solutions to help c View full post on Monster Job Search Results jt:(Web Developer)

View full post on WebProJobs.org

VN:F [1.9.22_1171]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)

Python Developer – Back-end Engineer – Internet Driven Co

CyberCoders Burlingame, CA
Job description: …database design and python experience, please read on!What you need for this position:- Strong Web 2.0/Back-end Javascript programming experience- Strong system programming and design skills in server & client side environment- Experience… View full post on Dice.com – web

View full post on WebProJobs.org

VN:F [1.9.22_1171]
Rating: 0.0/10 (0 votes cast)
VN:F [1.9.22_1171]
Rating: 0 (from 0 votes)