Jos de Jong

a blog about programming and web development

Batteries Included

tl;dr The JavaScript community is doing a great job in creating an ecosystem of highly composable, configurable, and extensible components. Unfortunately, this has complicated usage of these components. It is time to focus on the user again. Deliver components with a good default configuration which matches the typical use cases, and ensure a gradual learning curve for more advanced usage of a component.

Latest years I see a trend in software libraries and frameworks that make me really happy: libraries have become more and more composable. npm modules in particular have always been small and composable. They support extension and customization via plugins. It’s what makes it possible to combine tools like Gulp, WebPack, Browserify, Rollup, Babel, Mocha, Ava, React, Redux, Angular and many more in so many different combinations and configurations. This is awesome.

At the same time I see another trend that concerns me. In order to achieve this high level of composability and extensibility, libraries sacrifice easy of use. Before you can use a tool, you need to gain a deep understanding of the tool’s configuration and ecosystem of plugins. Figure out how the configuration applies to your use case and how to combine it with other tools you’re already using. The learning curve of tools are steepening. An example is Babel: version 5 “just worked” right out of the box, but version 6 requires you to install and configure “presets” before the tool will actually do something. Another example is React, which is known for requiring a complicated setup before you can actually use it in your application (there is hope though).

Configurability does not necessarily yield a steep learning curve

Now you may think that more complicated setups are simply a consequence of the tools becoming more extensive. I challenge you to rethink this. I believe it’s possible to make a library both flexible as well as easy to use.

How?

The first step is to come up with a flexible, low level API for the library. The second step is to think deeply about the typical use cases for the library, and provide the library with the right default configuration, matching the needs of the largest part of your user base so that they don’t even have to do any configuration at all. The last step is to make it easy to update/extend the default configuration without having to write the configuration from scratch.

Libraries can work seamlessly out of the box. For example, Browserify automatically replaces node.js specific libraries with equivalents which work in the browser, you won’t even notice that you have node.js specific dependencies which do not naturally work in the browser. And Webpack will bundle code containing dependencies using different module systems (commonJS, AMD, UMD, ES6 modules, …) without the blink of an eye. Rollup on the other hand only supports ES6 modules out of the box, and is harder to use in a mixed environment. To be able to use CommonJS dependencies for example, you have to install and configure a couple of plugins. I think this is an extremely common use case, and hope that Rollup will support this automatically some day in the future. From a purist point of view you may say that it’s not a good idea to use mixed module systems and environments. But from a real world perspective it’s just that way it works in practice, so you may better accommodate for it. If you don’t, you saddle up a large portion of your users with the task to figure out how to solve this, again and again.

Boilerplates are no solution

To relief us from configuration pains, we’ve seen a lot of boilerplates and generators popping up last year. We all do it: once we have a configuration that works, we copy it for a next project so we don’t have to reinvent the wheel again. If we have a nice base setup, we can share it in the form of a boilerplate.

The problem with boilerplates is that they don’t really solve the issue. They only postpone it. In first instance you have a working setup without any effort, but as soon as you have to change something or need to upgrade dependencies, you will still need to gain a full understanding of the setup and you have to understand why of the creator of the boilerplate did certain configuration in specific ways. This may be even worse than starting from scratch. My experience is that it’s better to swallow the bitter pil immediately, just learn to understand the tools, and set up everything yourself.

Configuration done right

A strong example of a library which got configurability right is hammer.js, a touch library for the browser. It comes with batteries included. Typically you don’t have to do any configuration to get going. From the hammer.js docs:

It’s easy to use, just include the library and create a new instance.

var hammertime = new Hammer(myElement, myOptions);
hammertime.on('pan', function(ev) {
  console.log(ev);
});

By default it adds a set of tap, doubletap, press, horizontal pan and swipe, and the multi-touch pinch and rotate recognizers.

This default configuration will probably serve 80% of the use cases, and these users do not need deep knowledge of the library before being able to use it.

If you have to make slight changes to the configuration, you can do so without losing the default configuration:

The pinch and rotate recognizers are disabled by default because they would make the element blocking, but you can enable them by calling:

hammertime.get('pinch').set({ enable: true });
hammertime.get('rotate').set({ enable: true });

Enabling vertical or all directions for the pan and swipe recognizers:

hammertime.get('pan').set({ direction: Hammer.DIRECTION_ALL });
hammertime.get('swipe').set({ direction: Hammer.DIRECTION_VERTICAL });

Now we’ve caught say 90% of the use cases, and the users still have to do hardly any configuration for it, nor do they need to gain a deep understanding of the library.

If needed, you can go deeper and do advanced configuration or completely replace the default configuration:

You can setup your own set of recognizers for your instance. This requires a bit more code, but it gives you more control about the gestures that are being recognized.

var mc = new Hammer.Manager(myElement, myOptions);

mc.add( new Hammer.Pan({ direction: Hammer.DIRECTION_ALL, threshold: 0 }) );
mc.add( new Hammer.Tap({ event: 'quadrupletap', taps: 4 }) );

mc.on("pan", handlePan);
mc.on("quadrupletap", handleTaps);

This ultimate configurability serves 100% of all use cases. It requires more effort and knowledge of the library, but gives you all flexibility you may ever need.

Conclusion

Today’s tools do a great job in offering flexible and configurable API’s. This is not a matter of course, and I have great respect for the people managing to build such versatile tools working so nicely together in so many different environments.

I think though that we can go a step further in reaching out to the user. We have to provide a seamless out of the box experience for the typical use cases, without sacrificing configurability or flexibility. The API of a library should be “layered” and offer a gradual learning curve rather than a steep one:

  • For typical use cases you can use the library right out of the box without having to do configuration.
  • Applying some basic configuration should be easy and should not require to gain a deep knowledge of the library.
  • For advanced use, the library allows to configure it’s low level components as desired.

When writing a library, try to understand typical use cases of the library and streamline the API for these cases. Listen to feedback of users on how they actually use the library and what their needs and concerns are. Make life as easy as possible for the users of your library. Don’t forget: without them your library has no reason to exist.

Static Typing: The Good Parts

tl;dr So far I’ve been hesitant to embrace static type checkers like TypeScript. It’s because I associated static type checking with the restrictions and interoperability issues that I know from Java and C++. However, it turns out that TypeScript is different: it uses a structural type system rather than a nominal one, which eliminates these downsides. It gives us a way to describe data types without sacrificing flexibility, interoperability, or scalability.

An uneasy feeling

Sometimes I have the feeling that I’m supposed to be averse of static typing in order to be a proper JavaScript citizen. I regularly hear people bragging about not needing it at all. And I have to say, I barely miss static type checking in JavaScript either: the cons are way bigger than the pros. Still, I miss static typing every now and then. That made me wonder, what is it about static typing that I miss?

The smell of static typing gives me an uncomfortable feeling. It reminds my of my hard-core Java time which was a continuous fight against the system: trying to get classes to play nice together. In Java, a lot of time goes into bookkeeping of classes and marshalling between them rather than developing actual application logic. So far I have been hesitant to embrace static type checkers like TypeScript or Flow which are built on top of JavaScript. I was afraid that the down sides of static typing would leak back into my applications again.

My first thought was: when I feel I need static typing in my application… it’s probably a code smell. It means that the application has grown to large and complicated to easily keep in my head. I can “solve” this by using a statically typed language which allows me to reach a higher level of complexity before my head explodes. Or I can acknowledge that the application is just too complicated and refactor it into smaller, easier to understand chunks.

However, there is more to it. Static typing and dynamic typing are typically pitched against each other as two opposites. You have to choose one or the other. However, I’m convinced that there are parts of static typing which are harmful and parts that are useful. Let’s figure this out.

The bad parts

Let me try to explain the problem with static typing with a Java example. Suppose we create a function which calculates the distance between two points:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Point {
  double x = 0;
  double y = 0;

  public Point (double x, double y) {
      this.x = x;
      this.y = y;
  }
}

static double distance (Point a, Point b) {
  double dx = b.x - a.x;
  double dy = b.y - a.y;
  return Math.sqrt(dx * dx + dy * dy);
}

We can use it like:

1
2
3
4
// OK
Point a = new Point(0, 0);
Point b = new Point(3, 4);
double d = distance(a, b);

Instead of a class Point we could better define it as an interface, that makes the distance function more flexible as we can create multiple classes implementing the same interface. In Java you can’t define properties on an interface though, only methods, so we have to define getters getX() and getY() on the interface and the implementing classes:

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
interface Point {
  double getX()
  double getY()
}

class Point2D extends Point {
  double x = 0;
  double y = 0;

  public Point (double x, double y) {
      this.x = x;
      this.y = y;
  }

  double getX () {
      return this.x;
  }

  double getY() {
      return this.y;
  }
}

// OK
Point2D a = new Point2D(0, 0);
Point2D b = new Point2D(3, 4);
double d = distance(a, b);

However, suppose we are using an external library which deals with points too. It will probably have it’s own classes and/or interfaces for points, like:

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
class ColoredPoint {
  double x = 0;
  double y = 0;
  String color = "black";

  ColoredPoint (double x, double y, String color) {
      this.x = x;
      this.y = y;
      this.color = color;
  }

  double getX () {
      return this.x;
  }

  double getY() {
      return this.y;
  }

  string getColor() {
      return this.color;
  }
}

// FAIL
ColoredPoint a = new ColoredPoint(0, 0, "red");
ColoredPoint b = new ColoredPoint(3, 4, "blue");
double d = distance(a, b);

We know this class is compatible with our Point class. But the compiler doesn’t agree. We will have to write code to convert a ColoredPoint into Point, else the distance function doesn’t accept it:

1
2
3
4
5
6
7
8
Point2D convertToPoint2D (ColoredPoint point) {
    return new Point2D(point.getX(), point.getY())
}

// OKISH
ColoredPoint a = new ColoredPoint(0, 0, "red");
ColoredPoint b = new ColoredPoint(3, 4, "blue");
double d = distance(convertToPoint2D(a), convertToPoint2D(b));

Another common case is that we’re just dealing with JSON data fetched from a server or database:

1
2
3
4
5
// FAIL
JSONArray points = new JSONArray("[{\"x\":0,\"y\":0},{\"x\":3,\"y\":4}]");
JSONObject a = points.getJSONObject(0);
JSONObject b = points.getJSONObject(1);
double d = distance(a, b);

From a logical point of view you could argue that something like this could work. But from a Java point of view you of course know that it won’t. Java strongly discourages working with “unstructured” data like JSON objects or arbitrary maps. The normal way of doing things is to parse JSON into Java classes like our Point2D.

Wrapping up, you will probably say that I just shouldn’t do such things in Java. You are right, Java isn’t made for that. What I observe here though is:

  • Java cannot deal with data in a flexible way, it can only handle Java classes with methods (having data encapsulated). In practice, the most straightforward solutions are often to operate on data directly in a functional way, without class ceremony. Java is no good fit there.
  • Java has serious cross-cutting concerns, which strongly hinders its scalability. If you have two different libraries each having their own classes and interfaces dealing with similar entities (like Point), they can’t work together. You will have to do quite some plumbing to convert from one type to the other everywhere the libraries have to work together.

If you look at the original goal: a function which calculates the distance between two points {x,y}, you see that we have to jump through a lot of hoops and have to deal with serious limitations. This demonstrates the bad parts of static typing: it harms interoperability and scalability.

The good parts

The good part of static typing in my opinion is that data types describe the intent of functions. They describe the input types that a function expect, and the output type that a function will return. This is very helpful and convenient, especially when working on a large application with a large team. For me, the most value is in communicating interfaces of functions and components between developers, not in statically analyzing correctness of an application or detecting type related bugs.

Let’s see how the same code example we did for Java works out in TypeScript:

1
2
3
4
5
6
7
8
9
10
interface Point {
  x: number
  y: number
}

function distance(a: Point, b: Point) {
  const dx = a.x - b.x
  const dy = a.y - b.y
  return Math.sqrt(dx * dx + dy * dy)
}

We don’t need getters and setters in JavaScript, and can keep the interface a simple, straightforward data structure instead. Of course we can use getters and setters and other methods when needed, but we’re not restricted here. You will see the impact of of using a simple data structure later on.

Next, we can create a class that implements the Point interface:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Point2D implements Point {
  x: number
  y: number

  constructor (x: number, y: number) {
    this.x = x
    this.y = x
  }
}

// OK
const a = new Point2D(0, 0)
const b = new Point2D(3, 4)
const d = distance(a, b)

But we can also use a class that implicitly implements the Point interface, without even knowing it. There are no interoperability issues, the following class ColoredPoint is compatible with the interface Point:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Note that the class ColoredPoint is totally unaware of `Point` and `distance`
class ColoredPoint {
  x: number
  y: number
  color: string

  constructor (x: number, y: number, color: string) {
    this.x = x
    this.y = x
    this.color = color
  }
}

// OK
const a = new ColoredPoint(0, 0, 'red')
const b = new ColoredPoint(3, 4, 'blue')
const d = distance(a, b)

We can also use plain data:

1
2
3
4
// OK
const a = {x: 0, y: 0}
const b = {x: 0, y: 0}
const d = distance(a, b)

The reason that our function distance works with both Point2D, ColoredPoint, as well as with plain objects is because TypeScript uses a structural type system:

Type compatibility in TypeScript is based on structural subtyping. Structural typing is a way of relating types based solely on their members. This is in contrast with nominal typing.

Not only TypeScript uses structural typing, similar initiatives like Flow, rtype (and JSDoc for that matter) do the same. This is awesome! This is the best of both worlds: we can communicate interfaces with our fellow developers, get warnings when trying to call functions in incompatible ways, without sacrificing flexibility, interoperability, or scalability.

You might wonder why languages like Java don’t use structural typing since nominal typing causes such interoperability issues. Well, the answer is simple: it’s way more expensive to deep compare classes property by property than it is to compare a single memory pointer. Since Java has runtime type checking, the performance penalty is just too big. Languages like TypeScript only do type checking at compile time, so it’s a non-issue for them.

Conclusion

The experience I have with statically typed languages such as Java and C++ is that it gets in your way. It restricts you, forces you to write lots of boilerplate for simple classes and conversions between them. The reason is that these languages use a nominal type system, which compares classes by name. TypeScript on the other hand uses a structural type system, which compares types by property. This does not cause interoperability issues between similar data types, and provides what we need most: a way to communicate the interface of our functions.

Of course there are more reasons to prefer a statically typed language. One is that “it saves you from a lot of bugs”. Well, I don’t recognize that advantage: as soon as you unit test your code, static type checking becomes redundant. More on this in a article published yesterday by Eric Elliot: The Shocking Secret About Static Types.

I’m no longer in doubt whether I can happily use a static type checker like TypeScript without being dragged back into the restrictive, limiting environment that I know all too well from statically typed languages like Java. TypeScript and it’s companions offer the best of both worlds.

Architectural Changes in math.js V2

tl;dr Math.js v2 has been released a week ago. It has a completely reworked, modular architecture which allows creating custom builds. All functions have been rewritten into typed-functions. This takes away a lot of overhead for type checking and type conversions. These changes create a lot of flexibility in both extending and consuming the library.

A week ago math.js v2 has been released, a big milestone! You can download it here. Math.js is an extensive math library for JavaScript and Node.js. It features a flexible expression parser and offers an integrated solution to work with numbers, fractions, big numbers, complex numbers, units, and matrices. It has been around for two and a half years now and has a steadily growing community around it and number of dedicated contributors.

Math.js v2 has a completely reworked architecture, and it adds support for fractions, sparse matrices, a linear equation solver, improved LaTeX support, and more. Currently there are contributors working on algebraic differentiation and derived units. A special thanks to Favian, Max, Rogelio, and Eric, who have put a lot of effort in the library lately.

Growing pains

As you can imagine, the library is growing. The point where it becomes too large to just mindlessly bundle it with your application comes closer. You typically only need a small part of the library, and it’s just a waste of CPU, memory, and KB’s when you need to bundle the complete library with your application. The architecture of math.js v1 however wasn’t suitable for custom bundling. It was also missing ways to optimize functions for known input types (very important for matrix operations). Lastly, dealing with new data types and conversions between data types was quite cumbersome.

For this reason the architecture of math.js v2 was drastically changed. The main architectural changes are related to modularization, dynamic type checking, and lazy loading. These changes will be covered in the in the next sections.

Modularization

To enable custom loading and custom bundling, a modular structure and explicit dependencies are required. This wasn’t trivial to achieve. Math.js does not consist of a set of isolated functions like say lodash. There are a couple of challenges here:

  • The functions are not static but need access to a configuration object. This means that the functions need to be created via a factory function, and need to be loaded via some loader which passes the config object to the function. This makes it impossible to just reference individual functions like mathjs/lib/arithmetic/add: the functions must be constructed via a loader.

  • The architecture of v1 had a shared math namespace containing all functions. This was done for a couple of reasons: there where circular references between functions, functions needed access to a shared configuration, and some functions depended on other functions in the namespace. Problem was that this shared namespace resulted in implicit dependencies, which makes it impossible to determine dependencies when bundling a subset of the functions. In v2, this shared namespace is removed and the circular references are resolved. A function has to load it’s dependencies explicitly. This allows to bundle only a subset of the available functions and data types.

  • The most difficult issue is the following. There are currently about ten different data types, and each function contains an implementation for each data type. Suppose you only need one or two of these data types, how can you exclude the other data types and exclude their implementations from all individual functions? We do not have a solution for this yet. Possible directions for solutions are:

    • Smart dead-code elimination of bundlers/minifiers, possibly using conditional compilation.
    • Writing a browserify transform or webpack loader which is capable of removing code related to excluded data types. This may be relatively easy because of the easily recognizable structure of typed-functions.

  • Math.js v1 contained a couple of large helper files. If you only need one of the functions in a helper file, you need to bundle the whole file. In v2, most helper files are split into one-file-per-function. This gives a more fine grained way to define dependencies, and allows to bundle only the utility functions that are actually used.

Dynamic type checking logic

Each function of math.js handles multiple data types like numbers, complex number, and matrices. In v1, these functions consisted of a single function body, which did type checking of the input types, and evaluated accordingly (see for example exp.js of v1). Problems with this approach are:

  • all type checking and conversion logic has to be written explicitly in the functions themselves. This gives quite some code overhead, and distracts from the actual function logic.
  • it is also a “closed” solution: no easy way to extend existing functions with support for new data types.
  • it is not possible to access low level implementations of a function handling a specific data type (like add for numbers). This is a necessity for performance optimizations with for example matrix operations.

In v2, functions are written as typed-functions using the typed-function library. See for example exp.js of v2). Using typed-function, functions can be defined as a set of signatures such as a function add having signatures add(number, number) and add(unit, unit). typed-function dynamically constructs the functions from the given signatures. Conversions from non-supported types is done automatically where applicable. Typed functions can be extended at run time with more signatures. Individual signatures can be addressed, allowing for performance optimizations when an input type is known beforehand. For example when you have a matrix containing just numbers, there is no need to type check every entry when performing an operation on the matrix.

The typed functions in v2 give us a lot of flexibility and decoupling, and ensures that when writing new functions, you only have to care about the implementation logic, not about type checking or type conversion logic.

Lazy loading

A third chane worth mentioning is lazy loading of functions. Loading all functions and all data types in memory costs time and, well, memory. In v2, functions and data types are by default lazy loaded: only as soon as you use a function, it will be loaded. This is achieved by using Object properties which replace their value with the lazy-loaded function on the first read. The result is a much faster loading library.

Conclusion

All in all I’m very happy with what we have achieved with v2. It was a bumpy road and a lot of boring refactoring. And there have been difficulties getting a good performance with typed-functions. But it turns out that the final v2 has even better performance than v1 in most cases, and the lazy-loading solution ensures that loading times remain limited: v2 loads about as fast as v1, whilst the library has grown considerably. It was definitely worth it.

There is still a lot of work to do regarding modularization. There is a lot to be optimized there. And while it’s awesome that we can finally do custom builds, one thing I don’t quite like is the need to write your own custom index file for custom bundling. Ideally, users should not have to bother about custom bundles: this should be done automatically by our bundling and minifying tools. I’m following initiatives like rollup by Rich Harris with great interest.

Math.js v2 takes away the bottlenecks for further growth, and gives a lot of flexibility for both extending as well as consuming the library. The future looks bright.

A Broader View on Isomorphic JavaScript

tl;dr In order to ease full stack JavaScript development, we need to take away the hurdles keeping these worlds separated. We need unified, isomorphic solutions for common functionality like module loading, networking, background processes, logging, and others.

Ever had to use statements like the following?

1
2
3
4
5
6
if (typeof window !== 'undefined') {
  // browser
}
else {
  // node.js
}

It’s a simple check to see whether a script is being executed in in a browser, and if not, assume that it’s a node.js process. I noticed that I need them more and more. I mostly develop libraries. As soon as I need functionality which is not standard available in both browser and node.js, like fetching urls, I have to create two different implementations and switch depending on the environment. It’s annoying and I don’t yet have a seamless solution for dealing with environment specific code.

There has been quite some some discussion lately about isomorphic JavaScript. Most discussion focuses on client or server side rendering, spurred by the recent popularity of React. Isomorphic JavaScript however is a much broader topic. It’s basically about writing code which can run in different environments such as the browser and node.js. In this article we will have a look at isomorphic JavaScript in a broader sense, and explore ways to deal with environment specific code in a seamless way.

Types of isomorphic code

JavaScript can run in different environments. One can think of client-side in the browser, server-side with node.js, on mobile devices using Cordova or PhoneGap, and on microcontrollers using Espruino. These environments have in common that they all support the JavaScript language. What they don’t have in common is environment specific functionality like the DOM and AJAX calls in the browsers, http servers and disk access in node.js, and access to mobile phone sensors in Cordova.

Spike Brehm distinguishes two types of isomorphic modules in this talk Master Class: Isomorphic JavaScript: environment agnostic or shimmed per environment.

  • Environment agnostic modules. These modules use only pure JavaScript functionality, and no environment specific properties like window and process. Examples are lodash, async, moment.js, numeral.js, and math.js.
  • Modules shimmed per environment. They offer a single API, and different implementations per environment. For example superagent, socket.io, debug, and pubnub.

Environment agnostic modules just work fine everywhere. Shimmed modules however require selecting the right implementation depending on the current environment. This is no problem when the module is consumed by an application. In that case it’s clear in which environment the application will run, like server side or client side. But when the module is consumed by another module, this choice can’t be made. For example a library for currency conversion (which makes network requests to a REST API), or a library using a proper debug library. The consuming module will have to distribute implementations for the different environments too. This results in a cascading effect, forcing all modules down the chain to create builds for various environments.

Shimmable functionality

In the previous section we discussed isomorphic modules offering a single API and different implementations per environment. This is only possible when the underlying functionality is available on each of the targeted environments. Let’s for now focus on the browser and node.js. In both, networking is a core functionality: the browser offers AJAX technology, and node.js has HTTP (and other protocols) in it’s genes. Both environments offer similar functionality, but with totally different API’s.

The following table shows an (incomplete) list with similar functionality available on both browser and node.js:

Functionality Browser Node.js
Module system none CommonJS
HTTP requests XMLHttpRequest (AJAX) http
Sockets WebSocket net
WebRTC WebRTC, peer.js node-webrtc
Background processes Web Worker child_process
Rendering DOM React, jsdom, PhantomJS
Debugging Web Console: Chrome, FireFox console, Winston, Bunyan

JavaScript land still lacks de facto abstractions on top of these overlapping functionalities, allowing to use the same API’s in both browser and node.js environments.

Notable here is the approach of browserify, which offers browser shims for many node.js specific modules like http and console. In practice though, the size of these shims can be quite large, which can be a serious problem for browser applications.

The browser and node.js worlds are currently still largely separated. There is a lot of room to bring them together on multiple levels, easing full stack JavaScript development. One step in the right direction is taken by npm for example, which encourages us to use npm for both front-end and back-end development, instead of using different package managers for different environments. An other important step is a universal module system for JavaScript, available in both node.js and the browser: ES6 modules. The third step is up to us module developers: build more isomorphic libraries which can be used in both browser and node.js without any hassle.

How to distribute isomorphic libraries?

There are basically two ways for distributing isomorphic libraries:

  1. Distribute different implementations per environment. The library consumer will have to select the right implementation depending on the environment.
  2. Distribute a single, universal implementation, which automatically detects the environment at runtime and loads the needed environment specific code.

The problem with the first approach is that it does not solve the problem but passes it on to the library consumer. This is fine when consumed by an application, but not when consumed by an other library. This library in turn has to check the environment, load the correct implementation of the consumed library, and has to distribute multiple versions of itself too. This results in a cascading effect.

The problem with the second approach is that the isomorphic library will contain the code for all supported environments. For node.js modules this is no big deal, but for the browser it’s important to minimize the amount of bundled code. It’s simply not acceptable to send precious kB’s over the wire containing unused, node.js specific code.

The only scalable, long term solution here is the second one. The exposure of environment specific code should be minimized. Library consumers should not have to bother about which implementation to pick, nor should they be bothered with distributing their own library in an isomorphic way due to isomorphic dependencies. This means we have to tackle the problem of distributing bloated application code containing code for multiple environments. We need build tools which can strip away non-relevant, environment specific code, like removing node.js specific code when bundling a browser app.

Tooling and conventions

In order to facilitate universally usable isomorphic libraries, two things are needed:

  • Tooling to detect the current environment at runtime.
  • Tooling to strip node.js specific code from application bundles when redundant.

Environment detection

In order to be able to let an isomorphic library switch to the right implementation, the library needs a way to detect in which environment it is running. This does not need to be very complicated. There may exist already exist solutions for this without me knowing it. We need detection and handling of environments. It could look like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
environment.isBrowser = function () {
  return typeof window !== 'undefined';
};
environment.isNode = function () {
  return typeof window === 'undefined' && typeof process !== 'undefined';
};
environment.isWebWorker = function () {
  return typeof self !== 'undefined' && typeof postMessage === 'function';
};
// ... detect whether running in a node.js child_process
// ... detect whether running a native web application like Cordova
// ... detect whether running on desktop or on a mobile device
// ... detect what type of browser (Chrome, FF, IE, ...)
// ... detect the browser version or node version

This module should of course be published as an UMD module. Suppose we have an http library with an implementation for the browser (myModule.browser.js) and node.js (myModule.node.js), the module could expose it’s main file, index.js, like:

1
2
3
module.exports = environment.isNode()
    ? require('./myModule.node.js')
    : require('./myModule.browser.js');

Bundling for the browser

Suppose that modules are distributed as a single, universal implementation, containing multiple implementations for different environments. When bundling an application for use in the browser, the parts of the code not relevant for the browser (i.e. implementations for node.js) should be removed.

Tools like browserify, webpack, and uglifyjs are typically used for bundling and minification of browser apps. When bundling an application, it is possible to configure specific modules to be excluded from the bundle. This mechanism could be used to exclude environment specific modules without forcing the end-user to specify them one by one. When all environment specific code uses a suffix, it would be easy to filter away these files from an application bundle. Files could be named like:

1
2
3
4
5
// apply suffixes for files only relevant for a specific environment:
myModule.node.js      // node.js, io.js
myModule.browser.js   // browsers: Chrome, FF, IE, ...
myModule.native.js    // native web apps, Cordova, PhoneGap, ...
// ... more

To bundle an application with browserify, all you have to do is ignore all *.node.js files:

1
browserify myApp.js --outfile ./dist/myApp.js --exclude **/*.node.js

Note that such a solution will only work if every isomorphic module uses the same environment suffixes. There is a convention needed to let this be successful.

Conclusion

There is a lot going on in the JavaScript world. Innovation is taking place at an incredible speed. It’s hard to keep up with the latest trends. With the rise of node.js, JavaScript is becoming more and more ubiquitous. Two worlds, client and server side, are both powered by JavaScript. But common functionality such as networking requires the use of environment specific modules. Code cannot just be executed in both environments, which causes a split between the two worlds.

In order to ease full stack JavaScript development, we need to take away the hurdles keeping these worlds separated. We need to come up with unified, isomorphic solutions for common functionality like module loading (ES6 to the rescue), networking, background processes, logging, and others.

There are opportunities here. JavaScript is already going full speed. Let’s ignite the after burners and go crazy.

Reusable Software? Just Don’t Write Generic Code

It may be the holy grail of programming: writing reusable code. Not getting stuck by inventing the wheel again and again, but moving forward and building on top of what has been done. Looking at what we do today, we still haven’t really figured this out.

So you are writing a software library. You had a great idea for a simple, broadly applicable solution. You have cooked up a nice API and are happy with the result. Then, new features are needed. The library grows and grows, and becomes extremely versatile. To account for more and more specific cases though, the API grows at a disproportional rate. Due to this feature creep, soon there isn’t much left from your initial, beautiful API. At some point it becomes almost too complicated to work with the library due to all configuration options and edge cases.

Then, a new, fresh alternative arises and moves your library into oblivion. This new library is awesome. It doesn’t suffer from a bloated API, it just works. It does more or less the same as your library but is faster and easier to use. Over time though, this new library will go through the same cycle as yours. It gets bloated too and will be replaced with something fresh at some time.

What went wrong?

Generic solutions

In the quest for writing reusable software, it’s a common mistake to make software too generic. To build a single, uber flexible, monolithic solution which is applicable in an extremely broad range of use cases and environments. Being generic is a basic requirement for reusable software. However, making software too generic causes it’s usability to suffer.

When a piece of software grows too large, it becomes bloated. Besides having a negative impact on the performance, the software typically becomes more complicated to use. The component will have a more extensive API and configuration. This requires more knowledge on the clients side, and makes debugging harder as more things can go wrong. Developing and debugging the component itself becomes harder as one needs to account for more and more edge cases. Summarizing, we can say:

Maximizing genericity complicates use

Besides negatively affecting the usability, being too generic can also hurt the reusability. Having a broader API and requiring more configuration results in a higher “contact surface” or coupling between the component and the application. This makes it harder to move the component to an other application for reuse.

Making your software too generic can make it too complicated to use. This can result in the software not being used at all, defeating the original goal of writing reusable software.

Reusable software

How to write reusable software then? Don’t write a single monolithic solution that will solve all problems. Instead, write small, composable, focused components. Components that just do one thing and stick with it (single responsibility principle). Components that are loosely coupled and have a concise API. This is one of the basic fundamentals in software engineering:

Reusable software requires loose coupling and strong cohesion

Writing small components will give your software a high chance of survival: all individual components are easy to use and understand, and are usable on their own in various use cases. When one of the component gets outdated, it can be replaced relatively easy as the components doesn’t have a high coupling with each other.

It’s hard to find the right boundaries and granularity for components. You don’t always get it right the first time. And when software grows over time, it will be necessary to reorganize, split, and refactor components in order to keep them focused. Don’t be afraid of refactoring. This is necessary to keep your software healthy in the long run, as opposed to killing it off because of overweight.

A great source of inspiration to me is the Node.js community, which seems to have small, composable components in their DNA. It’s like LEGO. It’s the Unix philosophy:

Favor composability over monolithic design

The flexibility and non-strictness of JavaScript helps a lot in this regard. It’s interesting to see the recent interest in functional and reactive programming in the JavaScript community. These paradigms can help a lot in writing loosely coupled, reusable code. Also, the trend towards micro service architectures looks promising.

Pitfalls

There are a couple of common patterns which are good in itself, but can easily be used the wrong way, adversely affecting the (re)usability of code. Let’s have a closer look at two of them: abstraction layers and inheritance.

Abstraction layers everywhere

An important ingredient for reusability is separating interface from implementation. That way, implementations can be replaced without the need to change the clients code. The Gang of Four writes in Design patterns:

“Program to an interface, not an implementation.”

Abstracting from implementations is a great solution when applied in the right cases. For example when using an ODBC driver to communicate with different types of SQL databases without having to write database specific code.

Especially in the Java world, I see a tendency to overuse and misuse this type of abstraction via interfaces. It’s as if some Java programmers don’t dare to make any concrete choice, and want to be able to replace everything without having to change anything in their code. Therefore, they introduce lots of abstractions and plenty of configuration. This results in very generic code, not bound to specific implementations. It may look like a great, generic, reusable solution. In practice however, these solutions are easily too complicated to be usable at all.

As Mark Seeman puts it in his blog Interfaces are not abstractions:

“Do you extract interfaces from your classes to enable loose coupling? If so, you probably have a 1:1 relationship between your interfaces and the concrete classes that implement them. That’s probably not a good sign, and violates the Reused Abstractions Principle (RAP).”

Do not introduce an abstraction layer unless it is clear that you will have multiple implementations (YAGNI principle).

Excessive use of inheritance

Inheritance is a great way to extend a class with extra functionality. In the Java community, inheritance is used excessively. Java offers a single inheritance model, where classes can only inherit from a single super class. It’s not uncommon to see inheritance levels of six or even more classes, which is absurd. De Gang of Four describes the danger of overusing inheritance in Design Patterns:

“Because inheritance exposes a subclass to details of its parent’s implementation, it’s often said that ‘inheritance breaks encapsulation’.”

Inheritance causes a high coupling, as the superclass exposes it’s internals to subclasses, and the subclasses are depending on external functionality offered by the superclass. This makes it hard to change the superclass without breaking the functionality of its subclasses.

Daniel Pietraru clearly explains the difficulty with inheritance in No, Inheritance is not the way to achieve code reuse:

“Inheritance, while a very powerful tool, it is very hard to use right. While the rule of thumb – use inheritance for ‘is a’ relationships and composition for ‘has a’ relationships – is very true, applying it in non trivial situations is difficult and wanders close to philosophy. Think about this question: ‘Is an CircusDog a Dog or maybe CircusDog is just a role a Dog plays?’.”

In general, inheritance should be used only when: – One class is an extension of another class, reusing most of the code of this class and adding some new features to it. – Two or more classes are very similar and share a large part of code, which can then be moved into a superclass used by all of them.

Conclusions

Writing reusable code is not about developing generic, monolithic all-rounders. The key to writing reusable code is to write focused, composable components with a high cohesion and loose coupling.

Keep your code sanitized. Replace outdated components. Don’t be afraid to refactor when needed. Be careful to use patterns like interfaces and inheritance proportionally, do not overuse them. Strive for writing focused components with a low complexity: easy to understand and easy to maintain.

The Art of Creating Simple but Flexible APIs

A while ago I read the blog post Ranging Near and Far by Scott Sauyet. On Echo JS, Scott titled a link to this blog “Choosing simple APIs over flexible ones”. This title suggests that you have to choose between either simple or flexible APIs, which is a false dilemma. This got me thinking: What makes a good API?

Flexibility

Scott discusses the API of the range function of Ramda compared to that of Underscore. Where Underscores range supports optional start (defaulting to zero), custom step size, and a negative step, Ramda’s range “only” supports a step size of 1 and does not allow to omit the start value. While Underscores implementation is more flexible, Scott argues that Ramda’s more limited implementation may be the better choice because of its simplicity. Scott suggests that it is way more complicated to use Underscores range because of it being more flexible. Scott has an argument here, but there are more factors determining how easy it is to use an API.

Simple != limited

It is important to distinguish simplicity from being limited. Simplicity is the opposite of complexity. The complexity of an API can be measured by the cognitive load it requires to use the API. This cognitive load is determined by:

  • Compactness
    Count the number of functions and the number of parameters per function. This may be the hardest to get right. You have to find the right primitives to cover the APIs functionality in a compact way. The functions should be as “orthogonal” to each other as possible, not overlapping in functionality.

  • Verbosity
    Common scenarios should be easy to do, verbosity should be minimal there. Ideally, the verbosity and complexity should grow linear when using more advanced features.

  • Consistency
    All functions of the API should have consistent naming, and the function signatures should be consistent.

  • Appropriate function naming
    Shorter function names are easier to remember, though too short function names can become meaningless. Finding good names may be one of the most difficult things in software development and it’s importance should not be underestimated.

  • Adhere to common practice
    The API should ideally work similar to other (comparable) APIs where the audience is familiar with.

  • The number of different ways you can call an individual function
    The less different signatures a function accepts, the easier it is to recall it’s functioning.

The importance of these factors depends on the application and the situation. In established environments, adhering to common practice is very important, even at the expense of consistency. In others cases, consistency or compactness may be decisive. Together, these factors determine the complexity of the API as a whole, and thus how easy it will be for a user to work with it.

Practical tips

Creating simple, powerful APIs requires a lot of practice. There is no magic formula, but here are some practical tips:

  • Limit the number of parameters of a function to 3 or maximum 4, use an object if you have more
    If you have to pass more than 4 parameters to a function, it’s not easy to see which argument corresponds to which parameter. You can accidentally forget one argument, causing all arguments matching the wrong parameter. Take a at the signature of the CreatWindowEx.aspx) function of the C++ Win32 API, which requires 12 (!) parameters:

      // BAD: way too many parameters
      HWND WINAPI CreateWindowEx(DWORD dwExStyle, LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam);
    

    Instead of having an endless list with parameter, pass a single object with named parameters instead. Take a look at the ajax function of jQuery:

      $.ajax({
        type: 'POST',
        url: '/rest/user',
        data: { name: 'John', location: 'Boston' },
        dataType: 'application/json'
        success: function () {...},
        error: function () {...},
        // ... and much more (optional) parameters ...
      });
    

    This function has 30+ parameters, but this is no problem at all: normally you only need to provide a few of them. Passing an object holding all parameters has a couple of advantages:

    • By looking at the code, you immediately see which parameter the arguments represent.

    • No need to pass null or undefined for optional parameters. Instead, most parameters are optional and have a good default value, so for common scenarios you will have to provide only a few parameters.

  • Support granularity in options
    Sometimes a specific feature has a set of options related to just this feature. These options can be put in a nested object. For example, one parameter can support both a boolean to enable/disable the feature as a whole, or accepts an object allowing to specify detailed options for this feature.

      // completely disable a feature
      simulation.run({
        animate: false
      });
    
      // enable a feature, use default configuration
      simulation.run({
        animate: true
      });
    
      // enable a feature, custom configuration
      simulation.run({
        animate: {
          duration: 3000,
          renderer: 'webgl',
          ...
        }
      });
    

    Or another example:

      // specify one color for all headers
      draw({
        color: 'gray'
      })
    
      // specify different colors for individual components
      draw({
        color: {
          h1: 'gray',
          h2: 'darkred',
          h3: 'gray',
          default: 'black'
        } 
      })
    
  • Too long function names may indicate a lack of abstraction
    If you find yourself giving functions long names, and cannot shorten them without loosing their meaning, this may be a sign that you have to rethink your API. It can be the case that the API has too many functions and needs to be split out in multiple small APIs on different layers:

      // BAD: a verbose API due to lack of abstraction
      app.createUser(...)
      app.updateUser(...)
      app.deleteUser(...)
      app.createProduct(...)
      app.updateProduct(...)
      app.deleteProduct(...)
      ...
    
      // GOOD: split in multiple smaller (and trivial) APIs
      app.user: User
      app.product: Product
    
      User.create(...)
      User.update(...)
      User.delete(...)
    
      Product.create(...)
      Product.update(...)
      Product.delete(...)
    

    It may also be the case that functions can be bundled together into a single one with an extra option:

       // BAD: too specific functions
       app.createCustomer(...)
       app.createEnterpriseCustomer(...)
       app.createStudentCustomer(...)
    
       // GOOD:
       app.createCustomer({
         type: 'normal'    // Choose from 'normal', 'enterprise', 'student'
         // ... other arguments
       })
    
  • Create an open, flexible API It’s tempting to create “controlled” APIs where you control exactly what a user can input. Trying to control this easily results in a limited, closed API. For example the following function may look easy and quite flexible:

      customers.find({
        name: string, 
        profession: string, 
        city: string
      })
    

    But this API is limited to a few hardcoded properties. The following approach is much more flexible, and probably easier to remember:

      // functional approach: callback function to filter customers
      customers.find(function (customer) {
        // ... full freedom to match a customer against any criteria
        return customer.name == 'John';
      });
    

    Note that this second approach requires Customer to have a public API, which may be a good thing anyway.

  • Adhere to common practice
    If you create a function range(start, end), it is a good idea to exclude end. If you create string or array manipulation functions, it’s a good idea to keep the indexes zero-based. Why? Because all existing (JavaScript) native functions and modules do it like that. You will cause a lot of trouble for your users when deviating from these kind of common practice.

  • Internal and external API
    Typically, a module exposes a small part of the internal API as public API. If you see that the public API is totally different from the API used internally, you may need to rethink the API. Users will start asking for features resembling the internal API that you use yourself. Users want to be just as close to the metal as you yourself.

  • Prevent feature creep
    All modules start out with a cozy and simple API. But as the module matures, the API grows, and there is the danger of “feature creep”. In the end, an API may be so bloated that it’s hardly usable for the average user. To prevent this, at some point the module needs get an extensible architecture: A limited core, enriched with a set of extensions. This extensibility allows users to build custom solutions for their specific needs on top of it, instead of demanding all kind of exotic features to be built in the main product.

  • Write documentation and examples
    By writing docs you will see whether the API is consistent and easy to explain. Writing examples helps a lot in figuring out whether your API works as nicely as you thought beforehand. Main purpose of docs and examples are of course getting your users up and running with your software as smoothly as possible.

  • Look at APIs of popular modules Study the APIs of popular modules to see how they do things and why. One of the reasons they have become the most popular of their kind will be that they have a great API.

Conclusion

The complexity of an API can be measured by the cognitive load it requires to use the API. Factors determining the cognitive load are compactness and consistency of the API, verbosity in common use cases, right function naming, and whether they follow common practice. Depending on the goals of a library, authors may come to different conclusions for similar functionality, like different choices made for the range function by either Ramda and Underscore.

Learning to write APIs which are both simple and flexible requires a lot of practice and takes a life time. Learn from the APIs of popular modules. Pay attention to details in your own APIs. Keep rethinking your API, keep trying to get things more and more logic, consistent, and concise. Watch for feature creep. Aim for an open, extensible API.

Shaped by the Language You Use

A few months ago I did an astonishing discovery, namely how strong your solutions are shaped by the programming language you use, the language that lives in your head. The interesting thing is that I already knew this. But despite that, I hadn’t expected this to be so incredibly influencing until I saw such a clear case of this in my own work.

The right tool for the right job

First a short explanation of my programming background. I’ve experience with various Basics, C++, Java, Python, JavaScript, Matlab, and others. Experience with procedural languages, object oriented languages, prototypal languages. Strict and loosly typed languages. Compiled languages and scripting languages. Desktop, web, server, mobile. I have explored quite some corners of the programming universe, and the more I learn, the more I discover just how little I know…

When gaining experience with different languages, you discover that each language has its strong and weak sides. There is not a single language which is the ultimate solution for everything. That’s why programmers tell you to ‘use the right tool for the right job’ rather than strive to find that one super-language. Which language is the best choice for a certain project depends on things like functional requirements, platform support, team experience, and more.

So far so good.

Consequences of choosing a language

The choice for a programming language is quite determinative for how the application code will be structured. The language may be procedural, object oriented, event driven, prototype-oriented, functional, etc. Every language has its own paradigms, patterns, and best practices.

For example the strict nature of Java encourages you structure your code very well, create abstraction layers and use patterns like getters/setters and interfaces. This helps in keeping large projects scalable and maintainable directly from the start. On the other hand, the focus on structure has annoying side effects: lots of classes consisting mainly of empty getters and setters, over-abstraction which makes it hard to understand what is actually going on, a lot of marshalling of objects, etc. All of this can cause a lot of overhead over the actual contents of an application. it can make an application rigid and adjustments cumbersome.

The opposite of the Java may be JavaScript, which is extremely unstructured and dynamic by nature. This encourages you to program in a flexible, defensive, and robust way, acting friendly and forgiving for (partially) wrong inputs. JavaScript applications are typically built up in a loosely-coupled and modular way, perfectly fitting in the continuously changing, dynamic environment of today’s world. On the other hand, the lack of support for structure can easily result in archaic and unmaintainable code. A lot of discipline is required from the programmer to create and guard the needed structure and abstractions.

It is best to adhere to a language’s best practices. When working in a team, one need to agree on code style and structure to ensure consistent code, and need to document the code. This helps making the application understandable and maintainable by others than just you.

The choice of language plays an important role in how your application will be structured. However, the choice of language may influence a lot more than just that.

Shaped by your language

Where it is really becoming interesting is when realizing that a language not only is a matter of differing syntax, organization, library support, and tooling. It also strongly influences the way you solve problems and the type of solutions that you see.

You are not using a programming language ‘just’ to express your logic and your solutions. Rather, the solutions that you come up with are influenced and limited by the language that lives in your head. If you are used to an object-oriented language, you will think in a different way than when you are used to functional languages. These and other paradigms all offer a different solution-space. Some problems are easily described in an object-oriented way, others by taking an event-driven or functional approach.

How influencing a language can be became clear to me while developing a math application in my spare time. This application is basically capable of parsing and evaluating expressions. It supports complex numbers, matrices, units, and other advanced data types. I have built this application first in a Basic language, then in C++, then in Java, and finally in JavaScript.

The third iteration of the application, written in Java, had become really neat. It was well structured and had logical abstractions. All data types where classes extending a single base class MathObject. Functions too where created as classes extending a specific base class MathFunction. The function classes had an eval method with a specific signature, accepting instances of MathObject as arguments. Implementing a new function was really easy and robust: just implement eval functions for the supported data types, unsupported types where automatically dealt with by the extended base class. The expression parser generated a node tree linking these functions and arguments together. It was a closed and well controlled solution.

But then I decided to rewrite the whole application in JavaScript. Now that is quite a different story. JavaScript encourages you to create an open solution rather than closed, controlled solution. JavaScript is no strictly typed language, and you can call any function with any type and number of parameters. You can’t control that. At first I thought this would complicate the application, having to do a lot of type checking in every function. But it turned out to give amazing opportunities. Rather than creating my own data types, I let the functions accept both JavaScript’s primitives (Booleans, Numbers, Strings, and Arrays), as well as advanced data types (such Matrix and Complex). Having first class functions available was really an enormous advantage.

This open nature of JavaScript gave a great synergy between my application and JavaScript itself. The Java application was built on top of Java in a kind of closed, sandboxed environment, only accepting my own data types. The JavaScript version on the other hand was seamlessly integrated with JavaScript itself, embracing JavaScripts own data types and first class functions. This resulted in strongly reduced complexity, and an amazingly open solution, which because of this openness can be integrated seamlessly with other applications and libraries (no marshalling horror…).

I was really perplexed to see how influential a language can be on the architecture of an application. I have been thinking: what did I do wrong with the Java version? Well, I did too much in an object oriented fashion. And I wanted to control everything with my own classes. This object-oriented paradigm is the core of what Java is, but it turns out not to be the right solution for everything. Now, with this lesson learned, could I rewrite the application in Java with the simplicity it has in JavaScript? I think for an important part: yes. This is mainly a matter of thinking outside of the (Java) box, and not primarily about a limitation in the language itself (though I really miss lambdas…). A language seriously influences your way of thinking.

Conclusion

There are many programming languages available. Non of them is perfect, each has their strong and weak sides. When starting a project, it is important to choose the right tool for the job: the language which best fits given functional requirements, platform support, and team experience.

The choice of language does not only determine syntax and tool chain though. It also strongly influences the way you solve problems and the type of solutions that you see.

When you are familiar with one language and one way of working, you may be blind for other types of solutions, which might have resulted in much simpler solutions. Even when you are familiar with multiple languages it may be the case that you – like me – always tend to stick to a few familiar patterns.

Be aware of the fact that the language that lives in your mind plays an important role in how you solve problems. Improve yourself by learning new languages, paradigms, and patterns. Dare to experiment, take time to build and compare prototypes following different paradigms and see how that works out for your problem. Every now and then this will lead to surprising results. It’s just awesome to see a complicated problem being reduced to an elegant, straight forward solution when applying a well suited paradigm!

Multithreading Is Today’s GOTO

Ask any programmer to the worst bug he ever encountered and you will very likely hear a terrible story concerning multithreading and data locks. Or maybe an issue around memory corruption or memory leakage. Two topics which are apparently hard to master for us programmers.

The latter case, memory corruption, is becoming less and less of a problem, as most modern languages come with automatic memory management. Most people see this as a step forward: it saves us a lot of trouble and results in more robust applications. Multithreading on the other hand is seen as something obvious and essential. Even more, programming languages which don’t support multithreading are seen as inferior and immature.

Why is it that we hold on so strongly to this multithreading paradigm while it gives us so much trouble? Are we too proud to acknowledge that we are not capable of taming this multithreaded beast?

What is wrong with multithreading

I work a lot with Java. Java is very proud on the solutions it offers for concurrency, multithreading, and resource locking. And yes, they work great… if you apply them correctly and consistently everywhere in your application. And that is where the fundamental problem with multithreading lies: when you write code, it is not thread-safe by default. You have to take explicit actions to make your classes robust against a multithreaded environment. And when doing maintenance in a later stage, you need to be careful to keep everything thread-safe. Making a class thread safe requires extra effort and worsens performance, so there is no incentive to apply thread-safe patterns by default.

Doing multithreading right requires in-depth knowledge of all components that you interact with. In large, real-world applications, it can be hard to figure out which code and which third party libraries are thread-safe and which don’t. It isn’t trivial to make the whole thread-safe without introducing dead locks or other issues.

Multithreading is very error prone. It goes wrong unless you take careful safety measures. And when it goes wrong, it’s incredibly hard to debug. Multithreading is easy in theory, but practice shows differently.

The case for singlethreaded applications

When starting to program JavaScript, coming from a Java or C background, you may notice a deafening absence of complexity. Part of this is because JavaScript is singlethreaded. You just don’t-have-to-worry about data corruption as your application just can’t manipulate the same data simultaneously from multiple threads – there are no multiple threads. It’s an incredible relief not having to reckon with these issues. Instead, you can focus on the actual logic you want to build around your data.

Why is it that JavaScript is so strong in dealing with asynchronousity? Common JavaScript and Node.js patterns use asynchronous callback functions, timeouts, and alike. The reason that this works so easy and naturally is because JavaScript is singlethreaded. It wouldn’t have worked if JavaScript had been multithreaded. That would result in a terrible mess of locks on the data shared between all these callbacks. This may be the reason why these kind of powerful concurrency patterns are not used a lot in languages like C++ and Java: these languages just aren’t very suitable for asynchronous programming.

The point here is: a singlethreaded application just works without you having to take safety measures to protect your data. You can’t screw it up. You can do as complicated things as you like, even so complicated that you don’t understand it yourself anymore. But you simply can’t get your data corrupted.

Yeah very funny, but I just need multithreading

It’s just plain stupid to have an application doing all work in a single thread. Any single CPU-heavy request will completely block the application. You remember these websites where you press a button and the complete browser freezes because JavaScript needs to do some work?! That’s thanks to JavaScript being singlethreaded you know…

Well, what you need isn’t multithreading per se. What you do need are solutions for concurrency. However there are other models to deal with concurrency besides multithreading and resource locking. Typical models used in JavaScript and Node.js are:

  • Message passing between isolated processes. JavaScript supports web workers in the browser to do CPU intensive tasks in the background. In Node.js you typically spawn child processes which interact with the main process via message passing. Note that the client/server model itself is a message passing solution as well: the client offloads work to the server side, and they interact with each via other HTTP requests.

  • Splitting a long running computation in small pieces. To keep a singlethreaded application responsive, you can partition long running computations into many small parts. The parts are executed one by one with a short timeout between them, to give the application space to process other events. The size of the parts can be determined by a fixed amount of work, or by a maximum amount of time which the calculation may block the application.

These solutions require a different way of thinking and modelling than multithreading and resource locking. My experience though is that modelling your application in separate, isolated parts (or as actors) results in a very clear and natural separation of concerns. This is beneficial to the overall architecture of your application.

How to utilize multi-core processors then?

One concern with single-threaded applications is that they can’t utilize a multi-core processor. This is a currently active discussion: what programming paradigms are suitable to utilize multi-core architectures? And no, multithreading is not the solution. Multithreaded applications don’t magically solve the multi-core dilemma. The solution involves modelling your application in a way that allows for parallel processing.

I don’t have a ready made solution for this multi-core problem. I’m convinced however that dealing with multi-cores should be abstracted away from the developer. Similar to GPU’s which do most graphics processing in parallel without us having to worry about that. All the developer should have to worry about is modelling his application in a parallelizable way, and the programming language should ideally facilitate this. Not you, but the virtual machine running your application should worry about the (multi-core) hardware.

An analogy with the beloved GOTO statement

There have been long and heated discussions in the past on whether the GOTO statement is good or bad. It’s incredible powerful, and quite a logic statement for everybody with a background in assembly. At the same time, using GOTO can very easily lead to spagetti code. Nowadays, GOTO is considered harmful by most, but it wasn’t at that time. Luckily, smart people came up with a completely different paradigm: structured programming. Modelling your application in separate subroutines. This offered a solution on a different abstraction level than the GOTO statement. One which was even more powerful, and made the GOTO statement redundant.

I believe that you can compare multitreading with the GOTO statement. At least how multithreading is implemented right now. It solves a serious need: we need solutions for concurrency. However, it is not the right solution for the problem. It introduces so many troubles that, as with GOTO, we can consider this a harmful paradigm which must be avoided. We are a little bit late to fulfill Steve Yegge’s prediction #3, but better late than never.

We should start thinking about better solutions for concurrency instead of multithreading. No, maybe not. The solutions are probably already there. Obviously, they will require a completely different way of modelling our applications. But all we have to do is realize that multithreading really sucks, stop torturing ourselves, and start using some of the other excellent solutions out there.

Details Matter

This is a theme which pops up again and again at the software projects I am working on. I really liked this blog by Jeff Atwood in this regard, explaining all your app is, is a collection of tiny details. Software which has not taken care of details right can be extremely annoying, and vice versa, an application having its details right can be real joy to work with.

This article explains the importance of paying attention to details in application development. This holds true for different different application levels. The article discusses this in two sections:

  • The first section explains the importance for the end users of your applications, and gives some practical tips to help you to achieve a better end user experience.
  • The second section focuses on developing usable software libraries. This highlights the need to write readable and well documented code.

End user experience

A decade ago people where used to adapting themselves to the vagaries of software applications – they had no choice. This is kind of the world up-side down: computers and applications should make peoples life easier and more fun, rather than get into their way and regularly raise their irritation level to dangerous heights.

Nowadays people have more choice, for example when it comes to smartphone apps. The barrier to install and remove apps is very low, and the selection is huge. If your app doesn’t work exactly as a user wants or expects, it will be immediately replaced by some other app who better understands what the user wants. Users are very critical in that, which is healthy. This forces app builders to deliver quality if they want to attract a large user base.

Now what kind of details am I talking about? Well, consider your own experience with applications. Both desktop, web, and mobile apps. What kind of things annoy you in the applications that you use? Here a list with examples of details that strongly influence the user experience. They are all very logic, but I see these kind of details being overlooked a lot, even in professional applications.

  • Feedback. When pressing a button, you want immediate feedback that the application is working on it. Pressing a button and having the application “do nothing” or even block completely is a terrible user experience. Most applications do not need to be blazing fast and be finished without missing a beat, but it is very important that they inform the user being busy. For actions that really take a lot of time, the application should also inform the user of the progress of the action.

    When developing an application, you typically work in a development environment with fast hardware and a fast internet connection. It is important to anticipate which actions may get slow when in a real world environment without fast hardware, fast internet, and with loaded servers. To be robust against this, it is wise to always give the user immediate feedback. Disable the clicked button, inform the user via a “loading…” message, and perform actions in an asynchronous, non-blocking way such that the user interface stay responsive all the time.

  • Navigation. Applications are often build with one type of navigation in mind. However, more and more people are using differing devices to work with the same applications. Especially websites should reckon with this and make it easy to navigate in different ways: mouse, touch, keyboard. Keep in mind to have scrolling work smoothly both for touch as well as using the mouse wheel. Built in shortcut keys, so you can navigate with arrows for example. Things like quick keys can make it much more comfortable and efficient for users who use your application intensively.

  • Loosing data. What is more annoying than filling out a large form, press the “Submit” button, getting back some weird error, and… having to fill out everything again? Or losing data from a document which you where editing when the application crashes, or when your internet connection goes down at an unfortunate moment. And what about accidentally doing something in an app and having no way to undo the action?

    I suppose everyone has encountered these situation. We are getting better at this though: more and more web applications take care of this now. Forms stay neatly filled and more and more applications automatically save your input, no longer relying on you pressing the “Save” button every now and then. A user should never have to worry about losing data. It is necessary to take this into account when designing your application.

  • Documentation. Ideally, an application is self explanatory. A new user immediately knows how to use the application. Mobile applications typically have limited functionality, leaving no doubt on how to use the application. For larger applications, it is important to provide users with documentation in the form of tooltips explaining the behavior of buttons and menu items, helping the user along the way. As a last resort, an application should always have documentation explaining the functionality and the workflow in detail.

  • Design. Design is not directly influencing the functionality which your application offers. It plays a large role though in how a user feels about using the application. Ensuring the application looks good makes the user feel that this is a professional, robust application. Which is probably is, because you appear to care for details.

All of these points of attention may sound trivial, so why don’t we just apply this? Well, because it takes more time and is more complicated to reckon with all of this when building an application.

Keep in mind though that you build an application to serve the user. Force yourself to put a little more effort in ensuring a good user experience. This can really make the difference, resulting in lots of users actually enjoying using your application.

Developer experience

On a different level, developers themselves are also encountering user experience issues when working with libraries and frameworks.

Most programmers don’t like commenting code and documenting their applications. It is boring and takes a lot of time. However, in order to make your work usable for others, either as code or in the form of a library or framework. You really need to pay attention to this.

  • Structure. Your code should be well structured and neatly commented. Regularly take time to clean up redundant parts of the code. Ensure your API’s stay consistent. Don’t be afraid to refactor code to improve readability and clarity. Don’t use dirty tricks which are hard to understand for others. Keep in mind that you only write the code once, but it will be read often. Spending a little extra time to make your code better readable and maintainable will most likely pay of, not only for others but also for yourself.

  • Documentation. The more developers use your work, the more it will pay of to spend some effort on documenting your library. Suppose you don’t document your work. Then each developer starting to use your library may have to spend a couple of hours (and a lot of frustration) to dig in your undocumented code and search the web for examples and help. When spending a few hours to document your code, you will save each of these developers a couple of hours work. This, ultimately, will save us together a lot of time which we can spend doing actual work.

    And no, now and then exporting your code as JavaDoc is not enough. Good documentation consists of the following parts:

    • A high level overview of how your library works, how all parts fit together, explaining the flow of the program.
    • A set tutorials, helping a developer to get up and running with your stuff.
    • A set of examples, demonstrating how to use your library in practice.
    • Detailed documentation describing the API’s of your library. These docs should be easy to generate when you neatly document your code.

  • Setup. A library or framework will not gain much traction when the process to get it up and running is a 14 step process which takes hours and requires a lot of knowledge and pre-conditions. It should be a no-brainer to get your library up and running. If not, developers will give up and find themselves an alternative which actually does come with good documentation and an easy setup. Writing a getting started tutorial helps a lot making clear what an installation exactly needs.

    When your library is complicated to get up and running, this may be a sign that something is wrong. If that is the case, take a step back and figure out what makes it so complicated. Eliminate these complex requirements and ensure a smooth first experience with your software.

You can be a brilliant programmer and write genius pieces of code. However, if you don’t make your work accessible and usable for others, your code will most likely have a limited use, and will die as soon as you’re no longer in the neighborhood to baby-sit and maintain it. Put a little extra effort in documenting your code and make it easy for other developers to get started with your code. This will drastically increase the applicability of your code, and makes the life of developers much more fun.

I’m sure you prefer to use applications and libraries which are well documented and supported, so take these as an example when writing your own.

Welcome!

Welcome at my blog. I just installed it freshly using octopress. Like everybody, I’m very unique and have the world a lot of interesting things to tell ;–). So here we go.