Building Coreisma

| Comments

A while back, I watched Scalable JavaScript Application Architecture by Nicholas Zakas. It describes an architecture made up of isolated modules communicating through a central sandbox. These concepts resonated with me. So I decide to write this basic architecture as fun exercise. Turns out, it wasn’t difficult to implement.

The result is Coreisma.

Coreisma is a lightweight module manager for javascript. It provides a clear way to encapsulate javascript snippets into modules, facilitates communication between modules through event notifications, and exposes shared code in through extensions.

In this article, I’d like to share the steps I took to build it.

Core Philosophies

I believe that good software is written deliberately. Meaning the choices that a programmer chooses should come from a set of philosophies. For Coreisma, I these philosophies to:

  1. Create a simple architecture pattern; not another framework
  2. Not tie myself to a particular framework (ie. jQuery, Prototype, YUI)
  3. Use TDD to ensure test coverage.

The Small Steps

Coreisma starts, as all very abstract cores should, very small. I simply provided a means to extend the object itself. Pass a json object or more powerfully a function that receives Coreisma itself.

1
2
3
4
5
6
7
8
9
10
11
12
13
var Coreisma = {
  extend: function(extension) {
    var extensionMethods = (typeof extension === 'function') ? extension(this) : extension;

    for (var property in extensionMethods) {
      if (extensionMethods.hasOwnProperty(property)) {
        Coreisma[property] = extensionMethods[property];
      }
    }

    return extensionMethods;
  }
};

Then, using this extend function, I exposed a more developer-friendly way to add an extension. I boringly called this function addExtension.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Coreisma.extend(function(core) {
  var extensions = [];

  var addExtension = function(extensionFunction) {
    if (arguments.length > 1 && typeof arguments[0] !== 'function') { extensionFunction = arguments[1]; }

    var extension = (typeof extensionFunction === 'function') ? extensionFunction(core, core.hub) : extensionFunction;

    core.extend(extension);

    extensions.push(extension);

    return extension;
  };

  return {
    addExtension: addExtension
  };
});

I wanted a way to name extensions. It isn’t retained or used in any way but it is a nice way to briefly describe what the extension does. Maybe one day this will allow for some simple self documentation.

Likewise, addExtension stores all extensions in a, you guessed it, “extensions” private variable.

addExtension passes core and a hub to an extension. At first hub is undefined, but coreisma wouldn’t be useful without it, so I figure it is a safe assumption that some “hub” will be there.

I probably should have broken the next extension up into three separate extensions: addHub, addModule and getModule, and finally start and stop of Coreisma. I believe that the root of this was because I was TDDing. I could not seem to think of a way to test addHub without starting Coreisma. Seems like a good candidate for a refactor, but for now here is the “Hub” portion of Coreisma.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Coreisma.addExtension("Hub", function(core) {
  var addHub = function(hubFunction) {
    core.hub = (typeof hubFunction === 'function') ? hubFunction(core) : hubFunction;
  };

  var addModule = function(moduleName, moduleFunction) {
    if (core.hub) { core.hub.register(moduleName, moduleFunction); }
  };

  var getModule = function(moduleName) {
    return (core.hub) ? core.hub.find(moduleName) : {};
  };

  var start = function() {
    core.hub.broadcast('startup.modules', core.hub);
  };

  var stop = function() {
    core.hub.broadcast('shutdown.modules', core.hub);
  };

  return {
    addHub: addHub,
    addModule: addModule,
    getModule: getModule,
    hub: {},
    start: start,
    stop: stop
  };
});

Despite the name “Hub” of the previous extension, we haven’t defined a working hub yet.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
Coreisma.addHub(function(core) {
  var modules = {},
      callBacks = {};

  var broadcast = function(eventName, data) {
    var eventCallBacks = callBacks[eventName];

    for (var i in eventCallBacks) {
      if (eventCallBacks.hasOwnProperty(i)) {
        eventCallBacks[i](data);
      }
    }
  };

  var listen = function(eventName, module) {
    if (!callBacks[eventName]) { callBacks[eventName] = []; }

    callBacks[eventName].push(module);
  };

  var register = function(moduleName, moduleDefinition) {
    var module = (typeof moduleDefinition === 'function') ? moduleDefinition(core, core.hub) : moduleDefinition;

    modules[moduleName] = module;

    if (typeof module.init === 'function') { listen('startup.modules', module.init); }
    if (typeof module.shutdown === 'function') { listen('shutdown.modules', module.shutdown); }
  };

  var find = function(moduleName) {
    return modules[moduleName];
  };

  return {
    listen: listen,
    broadcast: broadcast,
    register: register,
    find: find
  };
});

The Hub exposes four functions: register, find, listen, and broadcast. They do what you expect them to do.

  • register makes a module known. It passes the core and hub to the module to work with and automatically sets up a modules init and shutdown functions

  • find retrieves a module by name.

  • listen setups up a callback when a certain event happens.

  • broadcast declares that a certain event has happened to all listeners.

Wrapping up

A scalable javascript architecture brings stability and standardization to any project. Coreisma is my attempt to implement the ideas from Nicholas Zakas. I am proud of how straight-forward Coreisma turned out.

At Benefit Data Trust we have be been using Coreisma in production as a trial for months now. As we start to migrate all of our javascript to use coreisma, I suspect best practices and patterns will emerge. We will be able to distinguish what should be an extension. Or standardize the format for data passed between listener and broadcasts.

There is room to grow with Coreisma but I think this spunky architecture has a bunch of potential.

FREE-style Programming

| Comments

After solving a problem that has perplexed me for hours, I often take a few moments to sit back and bask in the bliss of a problem well-solved. But sometimes, my joy fades when I realize how little progress I made towards finishing the feature I started. I got distracted. I started out on track; but somehow, my focus shifted away from the goal—implementing the feature.

Most distractions have good intentions behind them. Sometimes I see a way to use the coding pattern I recently read about and decide to experiment. Other times I find a piece of code that I intended to refactor but never got around to; thinking it will only take a minute, I jump into that refactor. And still other times, I get distracted by formatting details, eliminating whitespace, converting a css file to sass, or attempting to make some method run more efficiently. While these are all great areas to focus on, they’ve ultimately prevented the feature from functioning sooner.

How can I complete the feature I began and still ensure my code is clean and well factored?

The State of the Code

Some the most fundamental programming techniques in the Ruby community have a side-effect of preventing distractions. Pair programming utilizes a second programmer’s perspective to discourage distractions. And yet still pair programmers may wander off together. Test Driven Development sets a rigid cycle of “red-green-refactor” to keep the focus on the task at hand. But the direction of building code is still at the programmer’s discretion. Regardless of the technique, a programmer needs a guide to remain on track.

FREE-style programming aims to be such a guide for programmers. It walks a programmer through an ordered code state.

  • Functional: Proven to work as expected.
  • Readable: Does what it says.
  • Easy to change: SOLID, documented, adaptable and extensible.
  • Efficient: Performs at the highest possible level.

This acronym gives an order to the state of the code while implementing a feature. First, you should focus on making sure to solve the problem you set out to address. For me, this is passing the acceptance test and its underlying unit tests. Next, a programmer should aim to make the code readable: DRY-ing up the code, creating small private methods doing the work called from the public methods, renaming methods to clarify what it does, or even refactoring to extract method into a class. Once it is readable, the code should become easy to change. This could be done by breaking the more complex classes into meaningful, smaller, reusable ones or by adhering to “open for extension, closed for modification”. Finally, the code should become efficient. The emphasis here is on execution performance.

When to shift to the next code state

A critical awareness is knowing when to move to the next code state. When is the code functional enough to move to readable? Or when does a program benefit from becoming more readable even though it is not yet completely functional?

Knowing when to progress is a developed skill. There is no absolute signal to tell us when to stop, go, or proceed with caution. The time to move forward is when you feel that the code stage is complete. When you sense this feeling, transition to the next code state.

Sometimes I do break this rule by taking little excursions to make the code readable without first making it completely functional. I do this only out of necessity, however. I make small adjustments to the readability of the code so that I can understand it enough to implement the next function. The F-R transition is the only time I consider moving backward. I only progress to “Easy to change” and “Efficient” stages after the code is fully Functional and Readable.

What kind of programmer are you?

In my experience, programmers are divided by what they prefer to focus on. Many are driven to make their programs function. These people are often task-oriented and they become annoyed when there are lists of stories that need to be addressed. Others, like me, are distracted by how the pieces fit together. The details of a program’s implementation feel more important than its execution. A common worry among these programmers is to commit the perfect solution the first time. Lastly, some programmers focus foremost on performance of their code. A performance-focused programmer will tinker with a single method or construct for even the slightest gains in speed, but later must re-tune the methods to meet the additional requirements.

We need all types of programmers. It would take a tremendous amount of time to get an application running if there wasn’t a drive to get features working. However, a system becomes a tangled mess if it is not cultivated. If the time required to insert a new feature into a system becomes less profitable than the feature itself, we stop implementing features. So we need the sustaining programmer to keep the system from grinding to a halt. But sometimes code can function and read well but still not be efficient. That’s when the performance programmer shines—taking the proven-complete, well-designed code and optimizing it to work faster.

A Balanced Approach

Building a software system is difficult. The demands of adding a new feature now often cause shortcuts that inhibit the development of future features. And yet, taking the time to clean up code distracts from adding features. True success of a system relies on a balanced approach to coding.

Using the FREE-style guide gives this balanced approach. Start by proving a feature is Functional. Then change the names, formatting, and method size to make it Readable. Afterward, isolate code that relates to each so that it is Easy to change. And lastly, look to improve the overall performance through efforts to make it more Efficient.

By following the FREE-style guide, I’ve been able to identify and re-focus when I get distracted. I’ve been more productive, while simultaneously writing lasting code. I hope it will help you, too.

Nothing to Say

I feel like I have nothing to say.
So, why start a blog?
To make sure I at least have a voice.