Mainstay Monday: SOLID - Single Responsibility Principle

Jul 27, 2015

This post is part of a series on the SOLID programming principles.

Starting this post and for the following four Mainstay Monday posts, I am going to go through the SOLID principles as put forth by Bob “Uncle Bob” Martin and Michael Feathers. SOLID is a foundational set of principles to allow programmers to evaluate their code by and refactor to in order to reduce bugs and increase stability. Originally SOLID was presented as a tool for object oriented design (OOD), but I contend that many of the principles apply to the functional paradigm as well.

The first principle of SOLID is the Single Responsibility Principle. As the name states, single responsibility is a heuristic we can use to evaluate whether code we wrote is trying to accomplish too many different tasks. When code does too many things at once it allows bugs to creep in undetected. Following is a function that, at first glance, looks pretty small and innocuous, but actually tries to accomplish several different tasks at once.

function returnAdder(){
	
	let latestSum = 0;
	
	return function addStuff(a, b){
		if(typeof a !== 'number' || typeof b !== 'number' || isNaN(a + b)){
			throw new Error('Something isn\'t a number, yo');
		}
		
		latestSum = a + b;
		
		return latestSum;
	}

}

Just as a brief review of what is happening here, we have a state variable captured in a closure, called latestSum. The returned function does a little validation, a little arithmetic and a little state modification. For 4 lines of executable code, that’s actually quite a bit going on.

Let’s do some refactoring and tease apart each of the different actions we’re performing and create separate functions for each. This may not immediately seem like the best way to go about things, but it will make our issues a little more transparent. Here’s a new, refactored function that does the same job.

function returnComplexAdder(){

	let latestSum = 0;

	function storeLatestSum(sum){
		latestSum = sum;
	}
	
	function validateArguments(a, b){
		let aIsValid = typeof a === 'number' && !isNaN(a),
		    bIsValid = typeof b === 'number' && !isNaN(b);
			
		return aIsValid && bIsValid;
	}

	function add(a, b){
		return a + b;
	}
	
	return function composedAdder(a, b){
		if(!validateArguments(a, b)){
			throw new Error(`Either ${a} or ${b} is not a valid number.`);
		}

		storeLatestSum(add(a, b));
		return latestSum;
	}
	
}

Composed adder is a little cleaner now. Each of the things it used to handle directly have been abstracted away and then reintroduced as function calls. Now our function is a little less explicit about the discrete steps needed to accomplish the work, and our adder function can be considered more of an execution layer which merely combines the steps needed to fully process our request.

As it turns out, however, a big mess of functions like this can turn ugly in a heartbeat. Beyond the obvious trend toward one or more pyramids of doom, we are handling a memory state in a rather sub-optimal way. When state and functions that modify that state live closely together it can sometimes be helpful to collect the entire block of data and functions into an object which manages its own state.

When we create a class around this concept of an adder with a persistent memory, we can make nearly a one-to-one conversion from a functional form to an instantiable object. Let’s refactor and take a look at the resulting object.

class memAdder{
	constructor(){
		// Since the world can access this and we haven't done anything yet
		// we want to use a non-number falsey value that accurately describes
		// the current state of our object.
		this.latestResult = null;
	}
	
	storeLatestResult(result){
		this.latestResult = result;
	}
	
	validateArguments(a, b){
		let aIsValid = typeof a === 'number' && !isNaN(a),
		    bIsValid = typeof b === 'number' && !isNaN(b);
		
		return aIsValid && bIsValid;
	}
	
	add(a, b){
		a + b;
	}
	
	computeAndStore(a, b){
		if(this.validateArguments(a, b)){
			throw new Error(`Either ${a} or ${b} is not a valid number.`);
		}
		
		this.storeLatestResult(this.add(a, b));
		return this.latestResult;
	}
}

Aha! Once we have made the transition to an object oriented paradigm, it becomes clear that we are still, in fact, not adhering to the single responsibility principle. Our object, memAdder, is still doing all of the same things our original function was doing. This is why our function looked so messy, we kept all the clutter!

As people who know me understand, I am a proponent of “everyday functional programming.” This means that doing things in a purely functional way in theory sounds wonderful, but sometimes objects happen. The beautiful thing that can happen, however, is sometimes we start looking at a big, ugly object and then functions happen.

Let’s use a modified strategy/factory pattern returning functions instead of objects to abstract away all of our validation and computation logic and leave the object managing the thing objects manage best: state. When we do this, we can fall back to our preferred pure functional approach for the grunt work, which will be selected and managed at runtime based on user need, meanwhile we have an object that can compose functions on the fly and maintain a running memory of the latest computation peformed.

//IIFE ALL THE THINGS!
let arithmeticValidatorFactory = (function(){
	
	function numberValidator(a, b){
		let aIsValid = typeof a === 'number' && !isNaN(a),
		    bIsValid = typeof b === 'number' && !isNaN(b);
		
		return aIsValid && bIsValid;
	}
	
	function getValidator(key){
		let validators = {
			default: numberValidator
		};
		
		return Boolean(validators[key]) ? validators[key] : validators['default'];  
	}
	
	return {
		get: getValidator
	};
	
})();

//IIFEs keep the global space clean and happy
let arithmeticFunctionFactory = (function(){
	
	function zeroFunction(){
		return 0;
	}
	
	function add(a, b){
		return a + b;
	}
	
	function getFunction(key){
		let arithmeticFns = {
			addition: add,
			default: zeroFunction
		};
		
		return Boolean(arithmeticFns[key]) ? arithmeticFns[key] : arithmeticFns[default];
	}
	
	return {
		get: getFunction
	};
	
});

class memComputor{
	constructor(method, validator){
		this.compute = method;
		this.validator = validator;
		this.latestResult = null;
	}
	
	setLatestResult(result){
		this.latestResult = result;
	}
	
	computeAndStore(a, b){
		if(!this.validator(a, b)){
			throw new Error(`Either ${a} or ${b} is not an acceptable argument.`);
		}
		
		this.setLatestResult(this.compute(a, b));
		return this.latestResult;
	}
}

As we can see, the new object memComputor has been reduced to a single responsibility. Hooray! That’s what we set out to do. memComputor is instantiated with a computation method and a validator, so it contains no computation or validation logic of its own. ComputeAndStore does exactly that. It takes the desired functionality, composes it on the fly, fails the attempt if it is invalid, otherwise the computation is performed and the output is stored and returned.

Meanwhile on the factory front, we have all of our actions lined up. We declare the methodology we need, receive functions and we have a pair of pure functions that are reliable, bug-free, or as close as we can make them, and ready for injection into our state-management object.

It seems like a lot of code to, ultimately, do a simple addition problem. If the goal were addition, I would agree. Ultimately, however, what we really built here was the foundation for a system to manage expensive actions that we might want to perform once and then reference again and again, like the union or intersection of a large list of data, perhaps.

To sum up everything we’ve gone over, the Single Responsibility Principle is a heuristic tool for evaluating whether a block of code, object-oriented or functional, is performing the correct actions to accomplish a single goal or if the code is taking on too much and should be refactored to solve the problem in a more granular way.

With many programming problems, identifying the right granularity can be difficult, but by using some of the well known and battle tested tools and solutions like the single responsibility principle. By adding SOLID principles to your arsenal of tools, your programming will get better and your ability to solve even greater and more complex problems will become a question of breaking them down into the right pieces.

Contracts for Better Code

Jul 22, 2015

With programming languages which have a greater draw for classically trained computer science types, there is a common discussion of contracts and data expectations. Contracts are so inherent in the code that it’s hard to see a declaration without one. Type systems emerge from the idea of contracts and every function, constructor and return path comes with an expectation that is defined and declared in the code.

Javascript, being dynamically typed and a little loose with the morals, attempts to sidestep contracts altogether. Function arguments are little more than a strong suggestion to the programmer, and every function returns something even if that something is merely the undefined type. Contracts are just not something we do.

Here’s an example of exactly how squirrely Javascript can really be.

function addBasic(a, b){
    return a + b;
}

function addArguments(){
    let a = arguments[0],
        b = arguments[1];

    return a + b;
}

function addSuggestion(a, b){
    let _a = Boolean(a) ? a : 0,
        _b = Boolean(b) ? b : 0;

    return _a + _b;
}

Obviously each of these functions does essentially the same thing, but in the last example a and b are nothing more than a suggestion of how you could use the function. You could run addSuggestion() and get 0 or you could run addSuggestion(1, 2) and get 3. There’s no requirement that you actually adhere to the contract at all.

You are doing it wrong.

There, I said it. Mucking about with all of these bits and pieces that may or may not exist and allowing programmers to play fast and loose with your carefully constructed function is just plain wrong. I makes me want to take a shower. It’s like the midnight movie on the horror channel: gross.

Rule number one of contract club: You ALWAYS talk about contract club.

If someone created a contract in their function they are setting expectations. If you don’t play by the rules someone set in the function, you should not expect the function to work properly. It’s just that simple. The contract is there to save you from yourself.

At this point, I think I should mention, I understand that Javascript doesn’t support function overloading, so you can’t create optional variations on a function and the loose requirements around the contract are there so you can get something akin to overloaded functions.

To this I say hogwash!

Actually that’s not true. Optional arguments are good, however it is better if we use them in a safe way. Overloaded functions, even in languages that allow them, can get dangerous. It’s preferable to write code that says what it means and does what it says. Let’s take a look.

function buildBasicUrl(hostname){
	return 'http://' + hostname;
}

function buildBasicPathUrl(hostname, path){
	return buildBasicUrl(hostname) + path;
}

function buildProtocolSpecificUrl(hostname, path, protocol){
	return protocol + '://' + hostname + path;
}

function buildPortSpecificUrl(hostname, path, protocol, port){
	return protocol + '://' + hostname + ':' + port + path;
}

function buildUrl(hostname, path, protocol, port){
	let url = '';
	
	if(Boolean(port)){
		url = buildPortSpecificUrl(hostname, path, protocol, port);
	} else if(Boolean(protocol)){
		url = buildProtocolSpecificUrl(hostname, path, protocol);
	} else if(Boolean(path)){
		url = buildBasicPathUrl(hostname, path);
	} else {
		url = buildBasicUrl(hostname);
	}
	
	return url;
}

That may not be the most beautiful code I’ve written, but it illustrates the importance of what I am saying. Here we can see that there is a function, buildUrl, which takes four parameters. Hostname is required, but all of the rest are optional. Once we get to the specific implementations of what we are actually doing, the contract becomes a firm handshake and it’s backed by the interpreter threatening to throw an error if something goes wrong. Mind you, the interpreter is going to just concatenate a whole bunch of undefined values, but that’s beside the point. You won’t get what you want if you don’t meet the contract.

So, there is another side to the contract that is also illustrated here. Regardless of what happens, you can guarantee you will always, ALWAYS get a string back when you run buildUrl. This is the promise made by the person who wrote the code before you came along. So, on the one hand, you must meet the requirements of the contract in order for the function to properly execute. On the other hand, you are allowed righteous indignation when you expect a string and you get a boolean or something else.

Return types are contracts.

When you, as the developer, write a function and claim you are returning a specific type, understand that the next person will hunt you down with hungry dogs if you promise a string, but sometimes return an object. What is returned is really, REALLY important. People rely on it. Imagine if this happened:

/*
 * I solemnly swear I always return an array.
 */

function listify(a, b, c, d){
	let finalArray = [a, b, c, d];
	
	if(finalArray.contains('foo')){
		finalArray = null; //This will totally never happen
	}
	
	return finalArray;
}

function removeVowels(value){
	return value.replace(/[aeiou]/gi, '');
}

let myListNoVowels = listify('foo', 'bar', 'baz', 'quux').map(removeVowels);

//BANG! BOOM! EXPLOSIONS! GUNFIRE! STACKTRACE!!!!

I mean, that was downright malicious. Who goes around saying they are returning an array and then they return null. That’s seriously sadistic. What’s worse is, if listify was buried somewhere in a library and all you had was the crummy documentation they wrote, you would never be able to figure out what you are doing wrong to cause listify to return null.

I dunno, it just blows up sometimes.

The short version of this post goes a little like this: When you write a function, you are writing a contract. That is a contract you are required to honor and you can, almost always, expect the programmer who uses your function to adhere to that contract.

The longer sum-up goes more like this: A contract is a guarantee. The guarantee that is given states expectations for what the user will do and it provides assurances about what the user will get in return. Contracts revolve around data, and everything is data. This means that regardless of what you are writing or what you expect, in Javascript, you should always say what you mean and do what you say.

By providing a strong contract for the user to rely on, you are making the world a little better place to live in. You are giving guarantees when so many programmers around you might not. Best of all, when you write a good data contract in your functions you can come back after a year of looking at something completely unrelated and get back up to speed almost instantly on what goes in and what comes out. Doesn’t that sound like better code? It does to me.

Mainstay Monday: Solving Problems With Recursion

Jul 20, 2015

If you have been writing Javascript for any amount of time, you’re sure to be familiar with standard loop structures. For and while blocks are part and parcel of the modern programming experience. On the other hand, if you haven’t done a data structures and algorithms course, you may not be familiar with the term recursion. Recursion is another methodology for handling repeated behavior, but it is useful for a completely different set of problems.

Before we start looking at the kinds of problems recursion is useful for handling, let’s discuss what it is. Recursion is the process of calling a function from within that same function to perform the operation again. Typically this is done with some reduction, modification or subset of the original data. A great, and simple example of a recursive algorithm is the Greatest Common Devisor (GCD) algorithm.

In order to understand what we are looking at with recursion, let’s first take a look at an iterative solution to our GCD problem. Euclid would tell us this is the most inelegant solution he’d ever seen to solve this problem, but he’s not here, so we can do what we want.

function gcd(a, b){
    //Let's not modify our original vars
    let _a = a,
        _b = b,
        temp;

    while(_b !== 0){
        temp = _a;
        _a = _b;
        _b = temp % _b;
    }

    return Math.abs(_a);
}

This function will find the GCD every time, but there is a lot of variable manipulation. With the variables being swapped around so much, it becomes difficult to follow what this function is really doing. Nonetheless, there are benefits to writing out GCD function this way that we will discuss in a moment. Now, let’s take a look at the recursive GCD function.

function gcd(a, b){
    return b !== 0 ? gcd(b, a%b) : a;
}

This second function actually accomplishes the same task as the original, but in a single line of executable code! Clearly recursion can provide a simpler, terser way of framing certain kinds of problems. In this case, we solve one step of the problem and then let the recursion do it over and over until we get an answer. This shorter syntax comes with a cost: memory.

Our while loop, though a little harder to read, takes up, effectively, a constant amount of memory and processing cycles. When you enter the function, variables are declared, memory is allocated and then the loop works within the constraints of the variables we define. Our recursive function operates differently.

Let’s add an array into our first function and watch what happens when we push values into it while we are computing everything. This will give us some insight into what is happening in memory as our recursion is working.

function gcd(a, b){
    let memory = [a, b],
        _a = a,
        _b = b,
        temp;

    console.log(memory);

    while(memory.length > 0){
        
        if(_b !== 0){
            temp = _a;
            _a = _b;
            _b = temp % _b;
            memory.push(_b);
            console.log(memory);
        } else {
            memory.pop();
            console.log(memory);
        }
    }
    return _a;
}

gcd(150, 985);

// [ 150, 985 ]
// [ 150, 985, 150 ]
// [ 150, 985, 150, 85 ]
// [ 150, 985, 150, 85, 65 ]
// [ 150, 985, 150, 85, 65, 20 ]
// [ 150, 985, 150, 85, 65, 20, 5 ]
// [ 150, 985, 150, 85, 65, 20, 5, 0 ]
// [ 150, 985, 150, 85, 65, 20, 5 ]
// [ 150, 985, 150, 85, 65, 20 ]
// [ 150, 985, 150, 85, 65 ]
// [ 150, 985, 150, 85 ]
// [ 150, 985, 150 ]
// [ 150, 985 ]
// [ 150 ]
// []
// 5

This is just a rough approximation, but you can see how more and more memory gets allocated to handle the recursion. We can generally consider this kind of behavior in our programs bad. As the algorithm finishes up, we can see the memory allocation is 8 integers.

The size of an integer lives somewhere between 2 and 8 bytes, so let’s call it 4 bytes and meet in the middle. This means that just the storage for the numbers we were computing took up 32 bytes. That may not seem like a lot, but considering our original algorithm took about 12 bytes, this is a pretty substantial overhead.

Fear not! All is not lost.

Okay, so recursion may not be the most efficient kid on the block, but sometimes it actually, really makes sense. Suppose we had a tree that you really, REALLY need to search and find something. You could write an iterative solution to search the tree, but that involves trickery we don’t have time for in this post. Instead, let’s suppose the tree is several layers deep and each layer contains several intermediate nodes. Here’s what our algorithm might look like:

// A predicate function is a function which tests a value and returns true or false
function searchTree(rootNode, predicate){
    let children = Boolean(rootNode.children) ? rootNode.children : [],
        childCount = children.length,
        found = predicate(rootNode) ? rootNode : null;

    for(let i = 0; i < childCount && found !== null; i++){
        if(predicate(children[i])){
            found = children[i];
        } else {
            found = searchTree(children[i], predicate); // Recursion!
        }
    }

    return found;
}

As you can see, we search the tree one edge at a time. We travel from node to node, moving up and down the levels until we find the element we want. If a matching element doesn’t exist in the tree, then we return null and accept our fate.

Wrapping this all up, there are always many ways to skin the proverbial cat and with each solution, there is a cost and a benefit. Recursion is an excellent way to solve some particularly tricky problems, but it comes with a cost, specifically memory and efficiency. Even with the drawbacks, sometimes it just makes more sense to use recursion and reduce the problem down to something more manageable.

We can consider looping to be a lightweight, electric chainsaw. It will cut just about anything you put in front of it, but it can make a mess. By that same notion, recursion is a scalpel. It’s not the right tool for every job, but when it’s handled with care, it can perform delicate surgery and remove warts from some of the trickiest problems in your code.

Dependency Injection Without A Framework (Or Pain)

Jul 15, 2015

If you’ve come from one of those big name, big OO frameworks, you are probably used to the idea of an Inversion of Control (IoC) container and dependency injection. If you have worked with Angular, you’re probably familiar with their dependency injection system. That’s all great, but what if you aren’t one of those people?

As it turns out, dependency injection (DI) just isn’t that hard to wrap your head around. When you talk to someone who has worked with one of the big DI systems like AutoFac or Spring, it can sound like DI is an enormous deal and could take years of practice and experience to get comfortable with. Here’s a little secret: there’s no magic. It’s not hard.

First, let’s talk about what DI is; it’s injecting stuff into your environment that you depend on. Dependency. Injection. That’s it.

You’re welcome.

Seriously, though, let’s have a little look at what DI looks like in a very hand-wavy kind of way with a class in ES6.

class Widget{

    constructor(componentFactory, widgetizer){
        this.componentFactory = componentFactory;
        this.widgetizer = wigetizer;

        this.context = {};
    }

    build(){
        let processedContext = this.widgetizer.processContext(context);
        //Here we do some stuff, maybe
        return this.componentFactory.create(processedContext);
    }

    setContextValue(key, value){
        this.context[key] = value;
    }

}

Obviously we know nothing about compontentFactory or widgetizer, but that’s alright. All we really care about is that we know widgetizer has a method that processes a context and componentFactory has a create method that takes a processed context. The black boxes that are these objects really doesn’t matter at this point in the application. All that matters is the API.

Most of the time when people see this kind of implementation, they construct each of the dependencies one of two ways. Either they instantiate the objects inside of their class or they instantiate their objects as they construct their class. To this I say ‘gross.’ The practice is so bad I can’t bring myself to give an example.

Instead, here’s how we are going to do this. We’re going to use the factory pattern and create objects as we need them. Once we have a factory, we can build new widgets without breaking a sweat. Here’s what that would look like.

var widgetFactory = (function(){
    var componentFactory = new ComponentFactory(),
        widgetizer = new Widgetizer();

    function build(){
        return new Widget(componentFactory, widgetizer);
    }

    return {
        build: build
    };
})();

//Somewhere in the code
let myWidget = widgetFactory.build();

The code is so simple it practically writes itself. What’s even better, if you are writing unit tests (you should be testing all the f**king time) then the setup for your tests becomes so easy even a junior Wordpress developer could figure it out. Here’s a little Jasmine for flavor:

describe('Widget', function(){
    var testWidget;

    beforeEach(function(){
        var componentFactory = { build: function(){ return {}; } },
            widgetizer = { processContext: function(){ return {}; } };

        testWidget = new Widget(componentFactory, widgetizer);
    });
});

Your unit test setup is seriously only 8 lines of executable code. Let me repeat that… EIGHT LINES. Since the instantiation of your dependencies is completely disconnected from the instantiation of your object, you can easily swap them out for testing, or replacement with a new, better version, or… whatever. There is no need to hunt down every place you instantiated your dependencies because, if they have dependencies of their own, you can just build factories for them, too.

Now, I will say that all of the factories of factories of factories is going to get a little heavy and become a burden on your immortal soul, but that’s okay. I have another trick up my sleeve for you. Let’s create a registry and automatically handle factories out of a central object. Automatic factory… AutoFac… hmm.

Public Service Announcement: Before we start into the next part, I want to make this clear – If you aren’t using a framework, you’re building one.

Anyway, let’s build our registry.

//This quick hack is probably not safe for production code.
//Always understand and test code before you use it.
var objectRegistry = (function(){
    let registrations = {};

    function register(key, definition, dependencies){
        if(registrations[key] !== undefined){
            throw new Error(`${key} already exists in object registry.`);
        }

        registrations[key] = {
            definition: definition,
            dependencies: dependencies
        };
    }

    function build(key){
        let dependencyInstances = [null], //Trust me, you need this
            definition = registration[key].definition,
            dependencyList = registration[key].dependencies
            dependencyLength = dependencyList.length;

        for(let i = 0; i < dependencyLength; i++){
            let dependencyInstance = build(dependencyList[i]);
            dependencyInstances.push(dependencyInstance);
        }

        return new (definition.bind.apply(definition, dependencyInstances));
    }

    return {
        register: register,
        build: build
    };

})();

Creating a whole registry system really wasn’t so bad. A little bit of recursion and line of slightly tricky Javascript later, you have a registry and object factory all set. Let’s take a look at what our registration and instantiation code would look like now.

objectRegistry.register('ComponentFactory', ComponentFactory, []);
objectRegistry.register('Widgetizer', Widgetizer, []);
objectRegistry.register('Widget', Widget, ['ComponentFactory', 'Widgetizer']);

//You want a widget? You got a widget.
let myWidget = objectRegistry.build('Widget');

A little recap, dependency injection is nothing more than providing your object with instances of the dependencies it needs. If your system is simple and your dependency tree is flat, you can easily get away with a factory to manage your dependency needs. If your system is more complex, you may need to create a registry to handle your components and the dependency tree. For better or worse, your dependencies are going to be complicated at that point anyway so avoid the pain.

The moral of this story is simple: never manage your dependencies along side the code that depends on them. Use factories to make your life better. If you take care of your dependencies, they will take care of you, so manage them wisely and profit.

Mainstay Monday: Managing Type Coercion

Jul 13, 2015

If you are new to programming and, especially, to a dynamically typed language like Javascript you are likely not familiar with type coercion. The best way to think about type coercion is, when dealing with two values of different types, the two variables will be normalized to a single variable type for the sake of comparison or other common interaction. The important thing to understand with type coercion is the language interpreter or just in time compiler (JIT) will guess what the type is that you meant to work with and do the “right thing” with it.

Let’s take a look at what type coercion looks like in Javascript.

//Equality
5 == '5'; //true -- presumably '5' is converted to a number
'5' == 5; //also true -- presumably 5 is converted to a string
true == '5'; //true -- 1 is converted to boolean true
true == 10; //true -- 10 -> boolean

true == 'foo'; //false -- string doesn't coerce
false == 'foo'; //false -- as you can see, 'foo' isn't true or false

//Concatenation (or not)
console.log("The answer is " + 55); //55 is converted to a string and concatenated
1 + '2'; //12 -- 1 is converted to a string
5 - '1'; //4 -- '1' is converted to a number

//Inequality
1 < '2'; //true -- '2' is converted to a number
'3' > 2; //true -- '3' is converted to a number
1 < 'foo'; //false
1 > 'foo'; //false

//Arithmetic
5 + 2; //7 -- although under the covers this is actually 7.0
10 + 8.123; //18.123 -- 10 is immediately converted to a floating point number
0x0F + 3; //18 -- Hexidecimal number is converted directly to number type

//Other oddities
1 == true && -1 == true; //true, and
null == false; //true
'abc'.indexOf('e'); //-1, NOT null, so
'abc'.indexOf('e') == true; //true, but we wanted
'abc'.indexOf('e') >= 0;

As you can see, there isn’t a particularly hard and fast rule that one type is always converted to another. More importantly, you can see that the most common cases are strings to and from numbers and vice versa. Numbers coerce to booleans, but strings don’t. For concatenation numbers coerce to strings. For equality it’s unclear which direction the coercion goes and for inequality, strings are coerced to numbers as long as they convert cleanly.

Type coercion is intended to be a convenience feature in Javascript so new programmers don’t need to understand value types deeply enough to perform typecasting. Unfortunately the confusion that comes with type coercion mitigates any benefit even the beginner programmer would gain from it, since it is relatively unpredictable.

Managing Expectations

Since type coercion is unpredictable, we should manage values ourselves and try to be as explicit as possible so we always get results back that we expect. We don’t want addition to concatenate our members if one is accidentally a string. We don’t want to coerce boolean values to numbers or the other way around since the only number that evaluates to false is 0 and there are many times we get values which mean something failed, but the coercion would make them true.

We, basically, don’t want the language to guess what we mean because it is likely to guess wrong. Let’s have a look at some of the things we can do to help improve the reliability of our applications and manage the type coercion that happens with our values throughout our source code.

First, let’s take a look at triple-equals (===). Performing a value conversion at comparison time has two pitfalls. The lesser of the two is, it’s slow. It’s not slow in the way that an O(n^4) algorithm is slow, but it is slower than comparing values directly without conversion. Let’s take a look:

1 == '1'; //true -- We saw this above.
true == 'true'; //false -- a string cannot convert directly to a boolean
-1 == true; //false
1 == true; //true -- true and 1 cross-convert to be equivalent

//Let's normalize.
1 === '1'; //false -- a number is never equal to a string
true === 'true'; //false -- a boolean is never equal to a string
-1 === true; //false -- a boolean is never equal to a number
1 === true; //false -- same as above

We can see how eliminating coercion from our comparison operations, we get a normalized, type-safe experience while programming. This provides guarantees we otherwise could never get. If the code is changed, potentially in an unstable way, issues will start to emerge that will give us more immediate insight into what is happening.

Let’s have a look at another method for handling type differences: typecasting. Typecasting is something that is very common in strongly typed languages, but is often overlooked in dynamically typed languages like Javascript because it is not immediately obvious why it could be valuable. Let’s compare some of the common ways people manage type differences and how typecasting can help normalize your code and eliminate hacks to get around a common problem.

//Numbers
1*'4' + 1; //5 -- This feels like a hack
+'4' + 1; //5 -- This looks like a mistake

//Typecasting to numbers instead
Number('4') + 1; //5

//Booleans
!'foo'; //false -- strange feeling, but it works
!!'foo'; //true -- Gross. It's hacky and I'm just as guilty as anyone of doing this
!!''; //false -- What does not-not empty string even really mean?

//Typecasting to booleans instead
Boolean('foo'); //true
!Boolean('foo'); //false
Boolean(''); //false

//Strings; Yes, I have seen this example in the wild
'' + 1234; //'1234' -- This relies on that weird coercion we were talking about

//Typecasting to strings instead
String(1234); //'1234'

Typecasting might take a few more keystrokes than one of the hack methods, but it does two things for us that other methods don’t provide. First, typecasting is declarative of intent. By using Boolean or Number, you know precisely what you should be expecting. You will also, get a highly normalized, safe value back. The second thing typecasting offers is a 100% guaranteed type safe expression every time. This means that every comparison, computation, concatenation, etc, will produce a predictable result. Predictability is stability.

Before we finish up, let’s take a look at a couple of other built-in functions that are useful for handling common conversion cases. These functions are specifically for managing number and string outputs. These three functions are parseFloat, parseInt and toString.

ParseFloat takes a single value parameter. ParseInt takes two mandatory values, the value to parse and a radix. A radix is the base the original number is in, which is important for handling things like binary, octal and hexadecimal strings. ToString is a function that exists on the prototype for just about every object in the Javascript ecosystem. Let’s take a look at what

parseFloat('123.45'); //123.45
parseFloat('0xFF'); //0 -- x and F are not valid numbers in decimal floating point
parseFloat('0107'); //107 -- Octal string is resolved as a decimal

parseInt('1234', 10); //1234 -- base 10 numbering; the most common output
parseInt('0xFF', 16); //255 -- Hexadecimal string
parseInt('0107', 8); //71 -- Octal string
parseInt('101', 2); //5 -- Binary string

['a', 'b', 'c'].toString(); //'a, b, c'
1234.toString(); //'1234'

What is happening in Javascript is this, there are language features, i.e. type coercion, that were introduced to make it friendly for people who might not be strong programmers, or may not be programmers at all. Now that Javascript has taken hold as the language of choice for many different applications and we begin solving real problems with focus on real programming, this kind of low-entry-barrier kind of behavior is not preferable.

Like many other high-level, application type programming languages, Javascript has means to handle types with grace and stability. The concept of a type-safe comparison, i.e. triple-equals (===), gives us type guarantees for a variety of conditional cases. Typecasting allows us to explicitly declare the manner in which we intend to use a value, affording us stability when operating with unexpected type variances. Finally, build-in conversion functions and methods allow us to convert a value, store it and use it in a predictable way. This conversion gives us guarantees around the type of a variable as we develop.

The important take-away here is using type coercion is, at best, an unstable way to write programs which could introduce bugs that are difficult to identify and, at worst, a hack that makes code obscure and difficult to maintain. Instead of using type coercion, prefer stable, predictable methods for guaranteeing type and maintain type safety in your programs.

Blog Post Notes