TypeScript for quality of web code

In this blog post, I shall discuss the programming language TypeScript as a way to improve the quality of web code. I shall illustrate this with a demo project on GitHub, a simple web application that visualizes Conway’s Game of Life with rules that can be chosen by the user. The web application is hosted here, in case you want to play with it. Instructions for building this project from source follow later in this post.

Start page of our GameOfLife demo
Start page of our GameOfLife demo (I never said I was a GUI designer)
Output from our TypeScript demo
Output from our TypeScript demo
Output with alternative rules
Output with alternative rules

TypeScript emerged from Microsoft and is open source. There is increasing support for it, for example in Microsoft Visual Studio, and in the Atom editor. (Visual Studio in particular has its “Intellisense” technology working for TypeScript, as well as some basic refactoring.) Also, Google and Microsoft will apparently write Version 2 of the important AngularJS framework in TypeScript, see this blog post by a Microsoft Employee. Moreover, a top computer scientist, Phil Wadler has come up with an interesting research grant on improving TypeScript. (Incidentally, Phil Wadler is from my own academic field, programming language theory, and became a Professor at the School of Informatics of Edinburgh University soon after I left there having finished my PhD.)

Still, this blog post isn’t specifically about TypeScript. TypeScript just acts as a representativ of any decent, statically-typed language that compiles into JavaScript.

Disclaimers

First, I am not a web programmer. (I design business software on the .NET platform.) In this post I consider quality measures that are common for other languages and transfer them to the JavaScript technology stack.

Second, to those who know my academic background: I’m still interested in programming language theory. But I’m untheoretical here on purpose, since I think this topic is best presented as software engineering.

Thanks

I would like to thank my employer Interflex Datensysteme GmbH & Co. KG for admitting much of this work on our “Innovation Fridays”.

Overview of this post

Prelude: the unique rôle of JavaScript

Ways of maintaining code quality

Test-driven design (TDD)

Static type system

Quality-oriented build process

TypeScript

The type system

Module systems, and using libraries

Test-driven design with TypeScript

Our build process

 

Prelude: the unique rôle of JavaScript

Remarkably, JavaScript is so far the only programming language that can be run straight away by almost every computer user. (Since we all have web browsers.)

The beginnings of JavaScript are humble compared to the present. Quoting Wikipedia:

Initially … many professional programmers denigrated the language because its target audience consisted of Web authors and other such “amateurs”, among other reasons. The advent of Ajax returned JavaScript to the spotlight and brought more professional programming attention. The result was a proliferation of comprehensive frameworks and libraries, improved JavaScript programming practices, and increased usage of JavaScript outside Web browsers, as seen by the proliferation of server-side JavaScript platforms.

One should also mention the ever-faster JavaScript engines, for example the V8 engine of Google’s Chrome browser.

All statistics point in the same direction: JavaScript has become the most used programming language. Even, technologies around JavaScript still make it into the charts, like “Node.js” and AngularJS and  in the StackOverflow survey shown in a picture here.

Language in 2015 popularity according to a StackOverflow survey
Popularity of technologies according to a 2015 StackOverflow survey

This blog post focuses on languages that can replace JavaScript as a source language, to improve quality and productivity in larger applications, while staying inside the JavaScript technology stack. So we are talking about web programming, and programming in server-side JavaScript frameworks like “Node.js”.

There are two basic approaches to replacing JavaScript as a source language:

  1. Avoid JavaScript completely, and make browsers understand some improved language. This is what Google tried with its Dart language.
  2. Translate some improved language into JavaScript with a source-to-source compiler, a so-called transpiler. One tends to start with a language that is somewhat similar to JavaScript, like CoffeeScript or TypeScript. Often, the JavaScript produced by a transpiler can be easily matched with the source code.

(Incidentally, CoffeeScript is probably the most popular JavaScript replacement, and definitely worth a look. However, it is lacks static types, and thus doesn’t meet my quality demands. For an interesting discussion of TypeScript vs. CoffeeScript, see here.)

Google’s original Dart-approach was good in that it avoided the legacy language JavaScript completely, ultimately resulting in better machine code. But other companies did not adopt Dart, and in mid 2015 Google changed its strategy to compiling Dart into JavaScript! (See this news item.)

(For completeness, it should be mentioned that JavaScript is also increasingly used as a transpiler target for non-web languages like C and C++. For an overview, see here. But that’s not the focus of this post.)

Ways of maintaining code quality

Every software engineer who took part in a major, long lived software project knows: it is hard to maintain enough code quality so that the development doesn’t bog down, because of bugs, illegible code, unwieldy integration processes, and a resulting fear of change.

To maintain code quality,  software professionals have developed various best practices, a few of which I shall now discuss.

Test-driven design (TDD)

One very important quality measure is test-driven design (TDD): here, one writes unit tests that, when executed, test the behavior of code units. Ideally, all features of all code units are covered by such tests. The current stage of the software (the “build”) is only deemed okay if all test succeed. Unit tests are only used by the developers, and never shipped to the customer.

Static type system

Unit test are one way to catch programming mistakes early. There is another kind of error protection, so obvious that it’s easily overlooked: a static type system. For example, an ill-typed Java program won’t even compile. In some cases, the type error will even be shown in the editor before compilation. Type systems that work by just looking at the code (as opposed to running the code) are called static.

JavaScript has a type system, but it finds errors only when the code is run. Such type systems are called dynamic. Unlike static type systems and unit tests, a dynamic type system on its own is no safeguard against releasing broken software. Because we may never run the code path with the type error before the software is shipped. This argument alone shows that JavaScript’s lack of a static type system is a problem for code quality!

Also, people who code e.g. in C, C++, Java, C# often rely on the static type system without thinking. So it is a grave matter that this safety net of static types, which is standard in large parts of the software industry, is missing from the widely-used JavaScript!

Adding a static type system to JavaScript is the main benefit of TypeScript. More on that soon.

Quality-oriented build process

In the scope of this post, by “build process”, I mean the procedure that does two things: (1) turn the source code (which will be TypeScript + Html + Css) into executable code (which will be JavaScript + HTML + CSS). And (2) run all quality checks, ranging from linters to unit tests. (A linter is yet another kind of static code check, which checks for dubious coding patterns beyond type errors, see this Wikipedia article.)

The build process has clearly a lot to do with quality and productivity. It must be fast, hassle free, and ensure quality. We shall spend some time discussing the build process of our TypeScript demo.

TypeScript

Roughly speaking, TypeScript is a JavaScript dialect with static types. I shall now describe the most important aspects of language. (For an even deeper introduction, see www.typescriptlang.org.)

The type system

Basic types

Firstly, TypeScript has some basic types, among them number, boolean, string, and array.

It is great to have such types, since they rule out mistakes, oversights in particular, that might result in long debugging sessions otherwise.

But it must said that these types have deficits: first, they all allow null values. (In Java, say, strings can also be null, but that’s a questionable aspect of Java.) Worse, values of basic type can also be undefined. With numbers, there are more problems: a value of type number can be Infinity, -Infinity, or NaN (“Not a Number”, behold the irony). Also, TypeScript has no type for integers.

Basically, these basic types of TypeScript are static versions of the corresponding dynamic types of JavaScript. That’s much better than nothing, but not as good as one could hope. It is is worth pondering how TypeScript’s basic types could be improved, but we must leave that to further work, like Phil Wadler’s aforementioned research grant.

For completeness, it should be mentioned that the basic types also include an enum type, an any type, and a void type.

Classes and interfaces

Classes in TypeScript look quite similar to those of Java. Here is an example:

class Person {
    private name: string;
    private yearOfBirth: number;
    constructor(name: string, age: number) {
        this.name = name;
        this.yearOfBirth = age;
    }
    getName() { return this.name; }
    getAge() { return new Date().getFullYear() - this.yearOfBirth; }
} 

However, JavaScript’s approach to object-oriented programming is prototype based. Accordingly, the TypeScript transpiler translates the above class into JavaScript by using a well known pattern:

var Person = (function () {
    function Person(name, age) {
        this.name = name;
        this.yearOfBirth = age;
    }
    Person.prototype.getName = function () {
        return this.name;
    };
    Person.prototype.getAge = function () {
        return new Date().getFullYear() - this.yearOfBirth;
    };
    return Person;
})();

TypeScript also knows interfaces, for example:

interface IPerson {
    getName(): string;
    getAge(): number;
}

Now an instance of Person can be used whenever a function expects an IPerson:

function showName(p: IPerson) {
    window.alert(p.getName());
}

showName(new Person("John Doe", 42));

Note that, unlike in Java, Person need not implement IPerson explicitly for this to work. So we have structural typing here.

Of course, a class can extend a parent class:

class Resident extends Person {
    private address: string;

    constructor(name: string, age: number, address: string) {
        super(name, age);
        this.address = address;
    }
}

Here, TypeScript generates the following code, where __extends is defined elsewhere in the output file by a five-liner:

var Resident = (function (_super) {
    __extends(Resident, _super);
    function Resident(name, age, address) {
        _super.call(this, name, age);
        this.address = address;
    }
    return Resident;
})(Person);

So the benefits of TypeScript classes and interfaces should be clear now: firstly, they increase readability compared with JavaScript. Secondly, as in other programming languages, classes and interfaces (1) help catch errors during compile time, (2) guide code design, and (3) help different teams negotiate code contracts.

Generic types

Generic types, also called generics, are types that depend on types. Like Java, C#, and many other languages, TypeScript has generics:

On the one hand, there is the build-in type Array<T>, which has as values the arrays whose elements are of type T. So we have Array<number>, Array<string>, and so on. TypeScript also understands the popular notation T[] as a shorthand for Array<T>.

On the other hand, we can define our own generics, as classes or interfaces. For example, our demo project has an interface Seq<T> for arbitrary enumerable collections, not just arrays. Our Seq<T> is in the same spirit as the IEnumerable<T> interface known to C#-programmers. We shall explain Seq<T> more in the next paragraph.

Function types

Here is our aforementioned generic interface Seq<T> for arbitrary enumerable collections. We use it here as a realistic example to motivate function types.

interface Seq<T> {
    filter(condition: (element: T) => boolean): Seq<T>;

    map<TOut>(transform: (element: T) => TOut): Seq<TOut>;

    // some stuff we leave out in this blog post

    toArray(): T[];
}

The filter() function is meant for transforming a sequence into a shorter one by leaving only those elements that satisfy a given condition. Here, the argument condition of the filter function has the function type (element: T) => boolean. That is, condition is a function that takes a value of the type T and produces a boolean, which decides whether the value should be in the sequence returned by the filter function.

I leave it to the reader to discover the intended meaning of the map function.

Our Seq interface enables very elegant, type safe method chaining, for example

var seq: Seq<number> = ... // instance of some implementing class
seq.filter(elmt => elmt > 42).map(elmt => elmt * 2).toArray();

The method chain above starts with some sequence seq, transforms it into a sub-sequence that consists only of the elements greater than 42, multiplies every element of that sub-sequence by two, and transforms the resulting sequence into an array. The terms elmt => elmt > 42 and elmt => elmt * 2 are anonymous functions of type (element: T) => boolean. The latter, for example, is the function that multiplies its input by two.

If you know C#, you have probably figured out by now that our Seq<T> yields an analogue to LINQ.

It should be clear now that function types can be very useful, in particular together with generics.

Incidentally, JavaScript itself provides anonymous functions. But they have a terrible syntax: for example, the JavaScript counterpart of elmt => elmt * 2 is

function (elmt) { return elmnt * 2; }

Streamlining the syntax for anonymous functions is a simple, yet very important feature of TypeScript.

This ends our discussion of TypeScript’s type system. There is much more to say – see the TypeScript handbook.

Module systems, and using libraries

I shall first illustrate the importance of module systems by describing two problems they solve. Then I shall discuss actual module systems first for JavaScript, and then for TypeScript.

Namespaces

Providing namespaces is an obvious benefit of a module system: in larger projects, there are often multiple functions, classes, or interfaces with the same name. For example, there might be multiple classes called Provider or Parser or Service, or multiple functions called create. Each occurrence of such a class or function will occur in some larger code unit. For example, one code unit for Database access, one for business logic, and so on. Any module system worth the name will allow for naming these larger units, for example Database and BusinessLogic, and allow the elements in those units to be addressed by their qualified names, for example Database.Service and BusinessLogic.Service.

Maintainable extensibility

This is a crucial point, which is strangely absent from most discussions of module systems. JavaScript is a great for illustrating this: major web applications tend to comprise many JavaScript files. These files must be loaded into the browser. The old-fashioned way to do this is to include, in the main HTML page, one script tag for every needed file. So the main HTML page will contain code like this:

<script src="AjaxUtils.js"></script>
<script src="MathFunctions.js"></script>
<script src="Graphics.js"></script>
// and much more

This may look harmless at first. But it is a grave problem for medium-sized or large projects: there can be hundreds of required JavaScript files, and they can form a complex dependency tree, for example

A.js needs C.js
B.js needs C.js
C.js needs E.js and F.js

Some files, like “E.js” and “F.js” are conceptually of no concern to the top level HTML page. Still, they must be loaded somehow. Now imagine the specialist responsible for the library “C.js” replaces the library “E.js” by an alternative one called “E2.js”. Then that person would have to insure that the main web page is changed to load “E2.js” instead of “E.js”. Now imagine an open-source project with tens or hundreds of developers world-wide. Then the script tags in the main HTML would become an unmaintainable editing bottleneck, since every developer would have to change this central registry based on their “private” needs.

A module system removes the need to maintain a “central registry” of code units, typically by introducing a syntax of import statements by which each module describes what it needs from other modules. For example, a TypeScript file in our demo starts like this:

import Arrays = require("./Imports/Core/Arrays");
import Interface = require("./Interfaces");
import TypeChecks = require("./Imports/Core/TypeChecks");
import Array2D = Arrays.Array2D;
import RectRenderingContext = Interface.RectRenderingContext;
import Renderer = Interface.Renderer;
import checkDefinedAndNotNull = TypeChecks.checkDefinedAndNotNull;
import checkInt = TypeChecks.checkInt;

export function create(context: RectRenderingContext, pointSize: number): Renderer {
 return new RectRenderer(context, pointSize);
}

class RectRenderer<T> {

In this example, we signal with import-statements that our code relies on three other files. This is achieved by the import statements with the require keyword. Besides, we give short names to some elements from those three files. That is achieved by the import-statements with out the the require keyword. Then follow the definitions contributed by the current module: the export keyword signals that the function create will be visible from other modules. By contrast, the class RectRenderer has no export keyword, so it is not visible from other modules.

Module systems for JavaScript

JavaScript per se has no module system yet. External parties introduced two competing standards for JavaScript module systems: (1) CommonJS, whose dominant implementation is “Node.js”, and (2) Asynchronous Module Definition (AMD), whose dominant implementation is “RequireJS”. Having to choose between these two gives everyone a headache. This resulted in a recent standardization of a module system within Version 6 of the ECMAScript scripting language specification.

For a nice, quick overview of the current status of JavaScript module systems, see this post by Dr. Axel Rauschmayer.

Finally, another party introduced a module system definition called UMD (Universal Module Definition) that tries to reconcile AMD and CommonJS, see this GitHub link.

I hope the module situation for JavaScript will stabilize soon to one decent, easy-to-use system. And I suspect that will be the module system specified in ECMAScript 6.

Module systems for TypeScript 

There are two different aspects: first, the syntax TypeScript offers for writing modules. Second, how the transpiler translates TypeScript modules into their JavaScript counterparts.

Let’s start with the second aspect: the TypeScript transpiler provides a command-line switch --module for the choice of the JavaScript module system. For example, the shell command tsc --module amd ...  will call the transpiler and tell it to produce JavaScript that runs with RequireJS. Besides amd, there is also an option commonjs. More recently, there appeared an options umd and system. The meaning of amdcommonjs, and umd should be clear from the above discussion of JavaScript module systems. Strangely enough, I could not find any documentation on the system option. It might stand for the ECMAScript 6 standard.

Our demo happens to use AMD. I don’t feel strongly about that choice. Technically, that choice is defined in our Gruntfile.js, which defines the build command(s). The build process passes certain definitions from Gruntfile.js, including the amd option, as command-line options to the transpiler.

Now for the other aspect, the syntax TypeScript offers for writing modules. I shall only give the big picture here, not least because the precise syntax might change or be extended as TypeScript embraces the ECMAScript 6 standard. There are two fundamentally different ways to write modules: the first way used to be called external modules, and is just called modules from TypeScript 1.5 onward. The second  way used to be called internal modules and is just called namespace from TypeScript 1.5 onward. Quoting very recent information from the TypeScript handbook on GitHub:

We just alluded to “internal modules” and “external modules”. If you’re vaguely familiar with these terms, it’s important to note that in TypeScript 1.5, the nomenclature has changed. “Internal modules” are now “namespaces”. “External modules” are now simply “modules”, as to align with ECMAScript 6’s terminology.

Additionally, anywhere the module keyword was used when declaring an internal module, the namespace keyword can and should be used instead.

The first way, modules in the new terminology, means that one file corresponds to one module. By default, elements in that module are not visible from other modules, unless marked with the export keyword. The import statements in the file indicate which elements from other modules are needed. How all of this is translated into JavaScript is governed by the aforementioned command-line option that picks the JavaScript module system.

The second way, namespaces, removes the one-to-one correspondence between files and modules: there can be different namespaces within one file, and namespaces that stretch across several files.

While I think namespaces are good to have, our demo does not use them.

To all who want to create a TypeScript project, I recommend to think about modules early: (1) let the difference of modules and namespaces sink in. (2) Have a closer look at the different JavaScript module systems. (3) Keep in mind that the module situation may change, hopefully stabilizing along the lines of ECMAScript 6.

Using JavaScript libraries from TypeScript

There are many great libraries written in JavaScript. How do we use them from TypeScript? Luckily, there is a mechanism analog to the way C programs can be compiled against native libraries by using header files: for a JavaScript module, one can create a so-called ambient declaration. This is a TypeScript file that represents the public elements of the JavaScript module, without the implementation. Typically, the file ending is “.d.ts".

Our demo project is well suited for demonstrating this, since it has both a Core library, which contains basics like Array2D<T>, and the actual GameOfLife application. Building the latter does not imply building the former. Instead, GameOfLife imports the JavaScript “binaries” yielded by Core, together with their ambient declarations.  For example, Core has the aforementioned class Array2D<T>, in a TypeScript implementation file named “Arrays.ts“. Building Core yields a JavaScript file “Arrays.js“. Since our build of Core uses a command-line switch --declaration, it also emits an ambient declaration file “Arrays.d.ts“:

export declare class Array2D {
    height: number;
    width: number;
    constructor(height: number, width: number, initialValue: T);
    set(row: number, column: number, value: T): void;
    get(row: number, column: number): T;
}

When the build for GameOfLife encounters an import like this

import Arrays = require("./Imports/Core/Arrays")

it will be satisfied with “Arrays.d.ts” instead of “Arrays.ts“. However, we must ensure that during run time the file “Arrays.js” is found.

TypeScript’s ambient declaration syntax goes way beyond our Array2D example. For more, see this page on libraries in the TypeScript handbook.

Crucially, there is a repository containing TypeScript ambient declarations for a great number of libraries. That repository is called DefinitelyTyped.

Test-driven design with TypeScript

Test-driven design involves writing tests for code units, module by module, class by class, and function by function. Each test, when run, can succeed or fail. The tests should cover as much functionality as possible. If tests fail, the software cannot be released.

Overview of test frameworks

Many programming languages have third-party test frameworks, that is, libraries with primitives for writing unit tests. Such primitives are mostly assertions, for example for checking that two values are equal. In contrast to a mere assertion library, a test framework has also ways to mark a class or a function as a test.

A well known Java test framework is JUnit. For Microsoft’s .Net framework, there is for example the Microsoft Unit Test Framework, or the third-party framework NUnit.

JavaScript too has unit test frameworks, among them Jasmine, QUnit, and Mocha. There is also the assertion library Chai.

Jasmine, QUnit, Mocha, and Chai are also available in TypeScript, because they are covered by the aforementioned DefinitelyTyped repository! We see here how elegantly TypeScript continues to use JavaScript technology.

An example unit test file

Our demo happens to use the QUnit test framework, since QUnit has a wide adoption and I like its style. I shall now discuss an example of unit tests, namely the file “Sequences_ArraySeq_test.ts” from our demo. Don’t read the file just yet, since it’s best to start the discussion in the middle.

import Sequences = require("Sequences");
import TypeAssertions = require("TypeAssertions");
import assertDefinedAndNotNull = TypeAssertions.assertDefinedAndNotNull;
import createArraySeq = Sequences.createArraySeq;

let seq: Sequences.Seq<number>; 
let functionName: string;
let name = (testCaseName: string) => "ArraySeq, " + functionName + ": " + testCaseName;

QUnit.testStart(() => {
 seq = createArraySeq([0, 1, 2, 3]);
});


functionName = "constructor";

test(name("Argument is defined"), () => {
 assertDefinedAndNotNull("seq", createArraySeq)();
});


functionName = "filter";

test(name("Argument is defined"), () => {
 assertDefinedAndNotNull("condition", seq.filter)();
});

test(name("function works"), () => {
 const result = seq.filter(n => [1, 3].indexOf(n) >= 0).toArray();

 deepEqual(result, [1, 3]);
});

// ... more test here

First, there is the line

/// <reference path="Imports/QUnit/qunit.d.ts" />

This tells the TypeScript transpiler where to find the ambient declaration for the QUnit library. Unlike a module import, this line generates no JavaScript. It is only there to satisfy the TypeScript compiler. When the tests are run, the file “qunit.js" is loaded by the test runner Karma, which I shall discuss later in this post.

Our test file uses three kinds of elements from QUnit. First, the function test that declares a single test. Second, the function deepEquals for comparing two values including nested properties. Third, the function testStart, for declaring code that runs before each test. QUnit has several other features not used in our test file, but our file contains enough QUnit to convey the spirit of that framework.

The test function of QUnit takes two arguments: the name of the test, and the body of the test, whose execution is delayed by an anonymous function. The name function is provided by me for convenience, to help us group our tests: first the name of the tested class, then the name of the tested function, and finally the test case.

The most straightforward test is probably this one:

test(name("function works"), () => {
    const result = seq.filter(n => [1, 3].indexOf(n) >= 0).toArray();

    deepEqual(result, [1, 3]);
});

We are testing the filter function of our ArraySeq class here. Our ArraySeq was created with the values 0, 1, 2, 3 in the testStart function. We apply our filter function with a predicate that yields true only for 1 and 3. Finally we check that the result of the filtering, when turned into an array, is equal to [1, 3].

Then there are tests like this:

test(name("Argument is defined"), () => {
    assertDefinedAndNotNull("condition", seq.filter)();
});

This tests checks that our filter function throws an ArgumentException on an argument which is null or undefined. Similar checks also occur in Java or C# unit tests, but only for null, since Java and C# have no undefined. Our ArgumentException here is a class defined in the module Exceptions of our Core project.

Since many unit tests check how a testee reacts to bad arguments, I provided an assertion library, TypeAssertions, which contains the above assertDefinedAndNotNull and some other assertions.

There is also a production-code library TypeChecks that complements TypeAssertions. For example, TypeChecks contains a function

checkDefinedAndNotNull(argumentName: string, value: any)

That function, when put in the first line of another function f, will throw an ArgumentException for argumentName if value is null or undefined.

Unit tests for gaps in the type system

Types that admit null values are problematic. The first person to admit this is inventor of null references, the famous computer scientist Tony Hoare (Wikipedia entry here). Speaking at a conference in 2009, he apologized for inventing the null reference (see here for the video):

I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn’t resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years.

JavaScript makes things worse by allowing undefined besides null. Sadly, this carries over to TypeScript, which has a static type undefined.

Worse, JavaScript and TypeScript have no integer type, only number. Not only can a value of type number be an non-integer number; it can also be nullundefinedInfinity, -Infinity, or NaN.

Now imagine we have a TypeScript project, and we want to ensure the same code quality as in Java, for example. Whenever a TypeScript function is meant for an integer argument, the type system can only ensure the argument is a number. So we are forced to add run-time checks that the argument is integer! (Our demo has such checks, using the checkInt method from our TypeChecks module.) Worse, for each argument intended to be integer, we need an extra unit test to check that an exception is thrown for a non-integer! (Our demo has such tests, using the assertInt method from our TypeAssertions module.)

So we see, in quantitative way, how gaps in a type system force us into more coding. And the type system of TypeScript has gaps.

Still, having static types at all is very helpful, since without them we would need even more run-time checks and unit tests! And we can address the remaining gaps with libraries containing run-time checks, plus libraries containing test assertions.

Our build process

The build process turns source code into executable code, and run quality checks. Build tools abound, and vary strongly between platforms. One example is the make command from the Unix world. Another is Microsoft’s msbuild.

The JavaScript world has several alternative build tools. I tried Gulp and Grunt. Grunt is a modern “task runner”, which works nicely as a build tool. Gulp is an even newer build tool, which follows a different paradigm. I tried Gulp first, and initially it worked well for me. Then I ran into an exotic problem with a particular gulp plugin. (Most Gulp users probably don’t have that problem, or know a solution or workaround.) Opportunistically, I tried Grunt instead, which worked well. And I just stuck with that. (I lacked the energy for trying more build systems, but feel free to argue for another one in the comment section.)

“Node.js” as a build platform

While I don’t feel strongly about Grunt vs. Gulp, they have something important in common: they run under “Node.js”. Importantly, “Node.js” can be (easily) installed on various operating systems, including Windows, Mac OS, and Linux. So, we can define a uniform build process for all operating systems supported by “Node.js”!

Even better, Grunt and Gulp are available via the package manager of “Node.js”, npm (Node Package manager). Better still, all our build tools are available via npm.

In fact, our projects “Core” and “GameOfLife” each have a file “package.json” that lists all tools needed for that project.

The “package.json” file

Here is the “package.json” of our Core project:

{
  "name": "Core",
  "version": "0.0.0",
  "description": "All dependencies of the Core project ",
  "main": "index.js",
  "dependencies": {},
  "devDependencies": {
    "grunt": "0.4.5",
    "grunt-cli": "0.1.13",
    "grunt-contrib-jshint": "0.11.2",
    "grunt-grep": "^0.7.0",
    "grunt-jscs": "1.8.0",
    "grunt-karma": "0.12.0",
    "grunt-newer": "1.1.0",
    "grunt-tslint": "2.4.0",
    "grunt-typescript": "0.6.2",
    "karma": "0.13.3",
    "karma-chrome-launcher": "0.2.0",
    "karma-firefox-launcher": "0.1.6",
    "karma-ie-launcher": "0.2.0",
    "karma-junit-reporter": "0.3.3",
    "karma-phantomjs-launcher-nonet": "0.1.3",
    "karma-qunit": "0.1.5",
    "karma-requirejs": "0.2.2",
    "load-grunt-tasks": "3.2.0",
    "qunitjs": "1.18.0",
    "requirejs": "2.1.19",
    "time-grunt": "1.1.1",
    "tslint": "2.4.0",
    "typescript": "1.5.3"
  },
  "scripts": {
    "build": "grunt build",
    "testPhantomjs": "grunt test:phantomjs",
    "testChrome": "grunt test:chrome",
    "buildPhantomjs": "grunt buildAndTest:phantomjs",
    "buildChrome": "grunt buildAndTest:chrome"
  },
  "repository": {
    "type": "git",
    "url": "https://github.com/cfuehrmann/GameOfLife.git"
  },
  "keywords": [
    "key1",
    "key2"
  ],
  "author": "Carsten Führmann",
  "license": "LicenseToDo",
  "bugs": {
    "url": "https://github.com/cfuehrmann/GameOfLife/issues"
  },
  "homepage": "https://github.com/cfuehrmann/GameOfLife"
}

(The “package.json” of “GameOfLife” is almost the same. The reason why I have two “package.json” files, instead of one for both projects, is: I intend to split the projects in two GitHub repositories, since “Core” is to be used by other projects besides “GameOfLife”.)

Let’s discuss our “package.json” file, since it provides a great start for understanding the build process. The devDependencies section lists the tools we need. Most importantly,

  • grunt, the task runner that acts as our build tool
  • typescript, the TypeScript transpiler
  • karma, our test runner
  • tslint, a TypeScript linter

Besides these main packages, there are some Grunt plugins that enable Grunt to use other packages: grunt-karma, grunt-typescript, and so on. And there are some packages that enable Karma to use other packages: karma-chrome-launcherkarma-qunit, and so on.

The meaning of the scripts section will become clearer soon.

Versioned installation of all tools with a single command

Here is a great benefit of having all tools run under “Node.js”: when we run

npm install

from the command prompt, from inside the Core directory, all packages described in “package.json” are automatically installed from the npm repository on the web! (That might take a minute or two.) The packages are put in a subdirectory “node_modules” of the Core project.  Similarly for the GameOfLife project.

Because our “package.json” file contains the package versions, it defines our tools completely and precisely!

Take a minute to ponder the elegance of this “Node.js” setup:

  1. Every programmer on Windows, Linux, and Mac OS can pull our project from GitHub and build it.
  2. The only prerequisite is “Node.js” and npm.
  3. All build tools, in the correct version, can be installed with a single command.
  4. But the build tools don’t clog our GitHub repository – they come directly from npm.

Local vs. global installation of npm packages

The “npm install” command described above, when run from e.g. the Core directory, installs the packages locally in that directory. This implies for example that we can not open a command prompt and run the TypeScript transpiler by entering typescript, even though we installed that npm package. We could run typescript in this simple way if we had installed typescript globally, which is also possible with npm.

Indeed, many JavaScript projects require globally installed tools. I decided against that. Thus, I view the tools as an integral part of the project. This has a advantages: (1) Different projects on a developer’s machine can use different versions of the same tool. (2) Even if the developer has only one project on their machine, they could still use the wrong version of a tool, but our setup rules that out.

Now I can also explain the scripts section in our “package.json” file. We have seen that we can’t simply run our tools from the command line; but npm knows how to do that! For example, the command grunt is unknown at the command prompt, but Grunt can still be run by “npm grunt” entered from the Core directory. Then npm runs the Grunt version installed in the local directory. The elements in the scripts section are aliases for commands to be run via npm. For example,

npm run build

translates into “grunt build“, using the local Grunt with the target “build”.

The Gruntfile

Above, we have seen how to obtain the our build tools. Now we shall discuss the definition of the build process. Since we use Grunt, that build definition comes as a “Gruntfile.js”.

Our Core project and our GameOfLife project each have their own build process and thus their own “Gruntfile.js”, since as mentioned above we treat Core as an independent library. Because the two build processes are very similar, so we focus on the Core project here. Here is its “Gruntfile.js”:

module.exports = function (grunt) { 

    require("load-grunt-tasks")(grunt); 
    require("time-grunt")(grunt); 

    grunt.initConfig({

        typescript: {
            base: {
                src: ["*.ts"],
                dest: "BuildOutput",
                options: {
                    module: "amd",
                    noImplicitAny: true,
                    target: "es5",
                    declaration: true
                }
            }
        },

        jscs: {
            options: {
            },
            files: {
                src: ["*.js"]
            }
        },

        tslint: {
            options: {
                configuration: grunt.file.readJSON("tslint.json")
            },
            files: {
                src: ["*.ts"]
            }
        },

        jshint: {
            options: {
                jshintrc: true
            },
            files: {
                src: ["*.js"]
            }
        },

        karma: {
            chrome: {
                options: {
                    configFile: "karma.conf.js",
                    browsers: ["Chrome"]
                }
            },
            phantomjs: {
                options: {
                    configFile: "karma.conf.js",
                    browsers: ["PhantomJS"]
                }

            }
        }
    });

    grunt.registerTask("build", ["newer:jscs", "newer:tslint", "newer:jshint", "typescript"]);
    grunt.registerTask("test", function (browser) {
        grunt.task.run("karma:" + browser);
    });
    grunt.registerTask("buildAndTest", function (browser) {
        grunt.task.run("build");
        grunt.task.run("test:" + browser);
    });
};

First, consider the call

grunt.registerTask("build", ["newer:jscs", "newer:tslint", "newer:jshint", "typescript"]);

This defines the Grunt task build, that is, what the command “grunt build” does. (Recall from the previous section that we must actually type “npm run build” to invoke this.) That command will run the tasks jscstslintjshint, and typescript, in that order.

Unlike the top-level build task, the tasks jscstslintjshint, and typescript correspond to Grunt plugins that are listed in our “package.json” file and installed via npm. These tasks are configured in the “grunt.initconfig” section.

The tasks jscstslint, and jshint are linters, that is, early syntax and style checks. (Here tslint is the most important one, since we have a TypeScript project and not a JavaScript one. But we also have JavaScript files, like the “Gruntfile.js” itself, and those are checked by jscs and jshint.) The prefix newer indicates that a task should only run when its input file has changed. That prefix is not part of Grunt itself, but comes with the plugin grunt-newer listed in our “package.json” file. The reason why I (so far) use no newer prefix for the typescript dependency is: the TypeScript transpiler figures out by itself which files to transpile, by looking at dependencies. (I still need to look into this more closely.)

Now consider the call

grunt.registerTask("test", function (browser) {
        grunt.task.run("karma:" + browser);
    });

This is a generic task to run our test runner karma with a particular browser. For example, the command “grunt test:chrome” runs karma with the Chrome browser. This works because the “grunt.initConfig” section contains a task karma which has a subtask chrome which is configured to use Chrome.

For reasons explained in the previous section, we must enter “npm run testChrome” instead of “grunt test:chrome“. When we do this, a Chrome window pops up, and Chrome executes our unit test. The test results appear at the standard output. They are also written as an XML file into the directory “testResults”. This is configured in the file “karma.conf.js”, which is referred to in “Gruntfile.js”. Specifically, “karma.conf.js” configures a junitReporter with the output directory “testResults”. This works because the plugin karma-junit-reporter is listed in our “package.json” file.

Our “Gruntfile.js” also has a Karma subtask phantomjs. PhantomJS is a “headless” browser, meaning it opens no window. PhantomJS, being a big binary, is not listed in our “package.json” file. To use PhantomJS for our tests, it must be installed extra on the machine, just like Chrome.

Adding other browsers for testing is trivial, as long as they have a Karma plugin.

Finally, we have the obvious concatenation of the build task and the test task:

    grunt.registerTask("buildAndTest", function (browser) {
        grunt.task.run("build");
        grunt.task.run("test:" + browser);
    });

We call this via “npm run testChrome” or “npm run testPhantomjs“. This is what I do after changing source code.

So we see now how the quality checks I demanded are part of our build process: linter tasks before the transpilation, and a test task after the transpilation.

The BuildOutput directories

This is a detail that needs mentioning: our Core project and our GameOfLife project each have their own BuildOutput directory.

The BuildOutput directory of Core contains:

  1. All JavaScript files that result from transpiling Core.
  2. All ambient declaration files that result from transpiling Core. (As explained in the modules section, these are needed so that other TypeScript code can use Core.)

The BuildOutput directory of GameOfLife contains:

  1. All JavaScript files that result from transpiling GameOfLife.
  2. The JavaScript files imported from Core.
  3. The JavaScript files imported from third parties, here just “require.js”.
  4. Our HTML files and CSS files

The key feature of the BuildOutput directory of GameOfLife is that it can be used straight away for hosting. For example, the hosted version of the application is just a copy of that directory.

(For technical reasons, both BuildOutput directories also contain the JavaScript files that result from transpiling our unit tests. I am considering to change that.)

Open issues

Unit test frequently use mocking: the creation of replacement objects during a unit test, to check how they are used by the production code. For Java and .Net, for example, there are third-party mocking frameworks. Our GameOfLife demo didn’t compel me to use mocking, but mocking in TypeScript should be straightforward: for example, there is the mocking library typemoq. One should try this. (It is available via npm, like all our tools.)

Here is another gap in our investigation: as mentioned in the modules sections, frameworks and libraries must be usable from TypeScript, via ambient declarations. Our demo uses QUnit in this way. But there are many other frameworks, in particular frameworks for graphical user interfaces, that one may want to use from TypeScript. I have tried no such framework so far. This should usually work, since DefinitelyTyped has ambient declarations for many such frameworks. Still, when starting a TypeScript project, one should check if the frameworks one plans to use have well-maintained ambient declarations.

Stanford online quantum mechanics


In September 2014, I embarked on the Stanford online quantum mechanics course by Prof. David Miller, ‘Quantum Mechanics for Scientists and Engineers‘. Just when I thought “I’ve done it!”, a sequel was announced, from January to March 2015. It too seemed essential, and I decided to continue. Now that I’ve finished both courses, here is a quick review, including the overall syllabus, and an account of my personal experience.

Stanford online quantum mechanics Pulp-O-Mizer illustration

Syllabus of the Stanford online quantum mechanics courses

First course, September – December 2014:

  • Schrödinger’s wave equation
  • Diffraction by two slits
  • Particles in potential wells
  • Solutions of the time-dependent Schrödinger equation
  • The coherent state
  • Wave packets, group velocity
  • Quantum-mechanical measurement
  • Expectation values and operators
  • Time evolution and the Hamiltonian
  • The uncertainty principle
  • Dirac notation
  • Unitary and Hermitian operators
  • Angular momentum
  • Spherical harmonics
  • The hydrogen atom
  • Perturbation theory

Second course, January – March 2015:

  • Quantum mechanics in crystals: band structure etc.
  • Optical absorption in semiconductors
  • Electron spin
  • Quantizing the electromagnetic field
  • Fermions and bosons
  • Creation and annihilation operators
  • Spontaneous and stimulated emission
  • Mixed states and the density matrix
  • Quantum measurements and encryption
  • Quantum computing, teleportation and entanglement
  • Hidden variables and Bell’s inequalities
  • Interpretation of quantum mechanics

Delivery of the courses

Every week, there where video lectures, about 90 minutes in total. Most lectures were followed by a quiz, and at the end of each week came a graded test. The quizzes and the tests where multiple choice, carefully designed so that one couldn’t score highly just by guessing. Many of the questions were aimed at conceptual understanding. Quite a few others asked for results of calculations.

There were also ten optional, non-graded lectures on the background mathematics.

My personal experience with the courses

I’m sure the difficulty of these courses, and the workload, differ wildly depending on the students background. I can speak only of myself here. I have a good mathematical background, though I’m not specialized on the kind maths that prevails in physics, like differential equations, Taylor series, etc. I knew little about quantum physics before the course. But I had studied some classical mechanics.

As the syllabus shows, the course covers a lot of ground. I’m glad I had looked at classical mechanics before, that may have kept me anchored.

Most of the lectures where clear and as simple as the material permitted.

In a small number lectures, I struggled for orientation. This happened typically when there were references to other areas of physics I hadn’t looked at. For example I haven’t studied electromagnetism yet, and there were lectures about quantizing the electromagnetic field. While I could follow much of that, some notions meant little to me, like ‘magnetic dipole moment’. In those cases, I ended up understanding most of the maths, but lacking a clear understanding of the physical meaning. In particular, I sometimes could not envisage experiments that illustrate these concepts.

Despite these hiccups, I repeat that most of the lectures were clear and helpful.

Against to the large scope of the lectures, the quizzes and tests were short and easy. During my university life I have seen many lectures with simpler content and harder exercises. In some discussion, Prof. Miller mentioned that the main focus was on conceptual understanding. This explains why the exercises involve no very challenging calculations.

On average, I spent maybe six hours per week on the course.

Quantum mechanics vs. classical mechanics from a learning point of view

Independently of this particular course, I learned a lot about the didactic difference between classical mechanics and quantum mechanics:

In classical mechanics, one may encounter hard maths; but one has usually a clear idea of the real life phenomena. For example, it may be hard to calculate the trajectory of a bouncing elastic ball. Or there may be no analytic way to deal with the three-body problem. But these things can be pictured easily in the mind.

In quantum mechanics, the maths is not particularly hard, because it is based on linear algebra. But the wave nature of things can be disorienting. For example, an electron can be seen as a moving wave packet that results from a superposition of single-frequency waves. Each of those single-frequency waves moves at a certain speed, the ‘phase velocity’; but the whole electron is construed to move at a different speed, the ‘group velocity’, which results from the superposition. Also, the electron is not clearly localized in space. Now imagine a discussion of a crystal that contains many electrons. As you see, it’s easy for a beginner to get lost when trying to visualize these things. (Ultimately, electrons in a crystal are accounted for by a ‘band structure’, which is  very different from a bunch of classical particles moving about.)

Conclusion

So, was this course worth the extensive burning of midnight oil after my day job? Well, my motivation was to fill white spaces on my mental map of science, and to learn more about the inner workings of nature. I think this was mostly a success. Some things I understood very well, like the hydrogen atom. Others things I still need to understand better, like electromagnetic fields. But I have surely learned how quantum mechanics ticks. Now I only need to stay in touch with the material, lest it fade from my memory…

Parametric oscillator: a close look

This post contains my research notes about the parametric oscillator. Here is an introduction from Wikipedia (see references section):

“A parametric oscillator is a harmonic oscillator whose parameters oscillate in time. For example, a well known parametric oscillator is a child pumping a swing by periodically standing and squatting to increase the size of the swing’s oscillations. The varying of the parameters drives the system. Examples of parameters that may be varied are its resonance frequency \(\omega\) and damping \(\beta\).”

As that Wikipedia article shows, a certain coordinate change can eliminate damping. So we focus on the case where there is only a resonance frequency \(\omega\), which varies with time. That is, we consider the differential equation
\[\ddot{x}(t) + \omega(t)^2 x(t) = 0 \quad \]
where \(\omega(t)\) repeats itself after some time interval \(T\).

The main purpose of this post is to preserve what I learned, for my own future reference. I am bad at maintaining handwritten notes, so I am moving to a digital medium. On the off chance that this interests others, I put it on the web. This post contains some work of my own that goes beyond the material in the references section. Most or all of my findings are likely known by experts. The proofs are mine, and so are the mistakes.

Floquet theory

A suitable mathematical background for the parametric oscillator is Floquet theory (see references section). It deals with linear differential equations of the form

\[
\dot{x}(t) = A(t) x(t)
\]
where \( x:\mathbb{R}\to\mathbb{R}^n \), and the function \(A:\mathbb{R}\to\mathbb{R}^{n\times n}\) is periodic with \(T\). We could also consider complex numbers as the elements of \(x\) and \(A\), but we shall stick with the reals here, in accordance with the physics. We can write a parametric oscillator as a Floquet equation:
\[ \frac{d}{dt}
\left(\begin{array}{c} x \\ v\end{array}\right) =
\left(\begin{array}{cc}
0 & 1 \\
-\omega(t)^2 & 0
\end{array}\right)
\left(\begin{array}{c} x \\ v\end{array}\right)
\]
I encountered Floquet theory in the well-known “Mechanics” book by Landau and Lifshitz (see references section), which we shall call “the book” in this post. The book contains a chapter on parametric resonance, which deals with parametric oscillators and their resonance behavior. The book uses Floquet theory in specialized form, without calling it so. Part of my motivation here is to obviate the exact way in which that book chapter ties in with general Floquet theory.

The monodromy matrix

We shall now introduce the notion of monodromy, which is pivotal for Floquet theory. Let \(\Psi: \mathbb{R}\to \mathbb{R}^{n\times n}\) be a fundamental matrix for a Floquet differential equation. Then \(\Psi_T(t) := \Psi(t + T)\) is also a fundamental matrix, because \(A(t+T)=A(t)\). So we have \(\Psi(t + T) = \Psi(t) M\) for some invertible \(n\times n\)-matrix \(M\). This \(M\) describes the change of the solution after each period. It is called the monodromy matrix. Rightly so, since in Greek “mono” means “one” and “dromos” means “course” or “running”.

One checks easily that different \(\Psi\) for the same \(A\) can yield different \(M\). But:

Lemma: The monodromy matrix of a Floquet equation is determined up to isomorphism.

So see this, let \(\Phi\) be another fundamental matrix for \(A\). Let \(N\) be the corresponding monodromy matrix. We have \(\Phi(t) = \Psi(t) Q\) for some invertible \(n\times n\)-matrix \(Q\). So
\begin{align*}
\Psi(t) Q N &= \Phi(t)N = \Phi(t+T) \\
&= \Psi(t+T)Q = \Psi(t) M Q
\end{align*}
Because \(\Psi(t)\) and \(Q\) are invertible, we get \(N = Q^{-1} M Q \) □

Importantly, it follows that any two monodromy matrices have the same Jordan normal forms, and therefore the same eigenvalues.

Now recall that we assumed that the matrix \(A\) from our Floquet equation has only real entries. Naturally, we are only interested in real solutions \(\Psi\). So any resulting \(M\) too has only real entries.

Floquet’s theorem

Floquet equations cannot not generally be solved symbolically. However, Floquet’s theorem makes a useful statement about the solutions. The version of the theorem that interests me here is:

Theorem: Any fundamental matrix \(\Psi\) of a Floquet equation with period \(T\) has the form
\[ \Psi(t) = \Pi(t) e^{t B} \]
for some \(T\)-periodic matrix function \(\Pi\) and some matrix \(B\) of matching dimension.

Note that the statement employs the matrix exponential \(e^{t B}\) (see references section).

Proof: Because \(M\) is invertible, it has a matrix logarithm (see references section), that is, a matrix of which it \(M\) is the exponential. (Important properties of the matrix logarithm are: they exist for every invertible matrix; and as in the special case of scalar logarithms, they can be complex-valued even if the exponential is real-valued, and they are not unique. For example, \(i(2k+1)\pi\) is a logarithm of minus one for every integer \(k\).) Let \(B\) be a logarithm of \(M\), divided by \(T\). That is, \(e^{T B} = M\). Let \(\Pi(t) := \Psi(t) e^{-t B}\). To see that \(\Pi\) is \(T\)-periodic, consider
\begin{align*}
\Pi(t+T) &= \Psi(t+T) e^{-(t+T)B} \\
&= \Psi(t) M e^{-T B -t B} \\
&= \Psi(t) e^{T B} e^{-T B} e^{-t B} \\
&= \Psi(t) e^{-t B} = \Pi(t) □
\end{align*}

Applying the theorem to the oscillator

First we perform a coordinate change into the eigensystem of the monodromy matrix \(M\). This is tantamount to assuming that \(M\) is in Jordan normal form. As for any \(2\times 2\)-Matrix, the Jordan normal form is
\[ M =
\left(\begin{array}{cc}
\mu_1 & \delta \\
0 & \mu_2
\end{array}\right) \]
where the \(\mu_i\) are the eigenvalues and \(\delta\) is zero ore one. The book considers only the case where the two eigenvalues differ, and therefore \(\delta\) is zero. We shall also consider the case where \(\delta\) is one. This can happen, as we shall see later.

We shall now apply the Floquet theorem. First, we need a logarithm of \(M\). We shall deal first with the more difficult case where \(\delta\) is one, and therefore \(\mu_1=\mu_2=\mu\).

As explained in a Wikipedia article referenced below, the logarithm can be calculated as a Mercator series:
\[\ln (1+x)=x-\frac{x^2}{2}+\frac{x^3}{3}-\frac{x^4}{4}+\cdots\]

We have \(M = \mu(I + K)\) where \(I\) stands for the identity matrix, and
\[ K =
\left(\begin{array}{cc}
0 & 1/\mu \\
0 & 0
\end{array}\right)\]
Using the fact that \(K^n\) vanishes for \(n\) greater than two, we get
\begin{align*}
\ln M &=
\ln \big(\mu(I+K)\big) \\
&=\ln (\mu I) +\ln (I+K) \\
&= (\ln \mu) I + K-\frac{K^2}{2}+\frac{K^3}{3}-\cdots \\
&= (\ln \mu) I + K \\
&=
\left(\begin{array}{cc}
\ln\mu & 1/\mu \\
0 & \ln\mu
\end{array}\right)
\end{align*}
From the proof of the theorem, we know that we can choose \(B = T^{-1}\ln M\). Some calculation involving the matrix exponential yields
\[
e^{t B} =
\left(\begin{array}{cc}
\mu^{t/T} & \frac{t}{T}\mu^{t/T-1} \\
0 & \mu^{t/T}
\end{array}\right)
\]
Note that \(e^{T B} = M\), as required. Now suppose we have a fundamental matrix
\[
\Psi(t) =
\left(\begin{array}{cc}
x_1(t) & x_2(t) \\
v_1(t) & v_2(t)
\end{array}\right)
\]
When we spell out the Floquet theorem elementwise, and ignore the \(v_i\), we get:

Corollary: If \(\delta = 1\), there are \(T\)-periodic functions \(\pi_1\), \(\pi_2\) and \(\pi_3\) such that
\begin{align*}
x_1(t) &= \mu^{t/T} \pi_1(t) + \frac{t}{T}\mu^{t/T-1} \pi_3(t) \\
x_2(t) &= \mu^{t/T} \pi_2(t)
\end{align*}

If \(\delta = 0\), we get the result from the book:
Corollary: If \(\delta = 0\), there are \(T\)-periodic functions \(\pi_1\) and \(\pi_2\) such that
\[ x_1(t) = \mu_1^{t/T} \pi_1(t) \qquad x_2(t) = \mu_2^{t/T} \pi_2(t) \]

The calculation is much simpler than for \(\delta=1\). I leave it away here.

Possible eigenvalues

First, we observe, like the book:
Observation: The eigenvalues of the monodromy matrix \(M\) of a parametric oscillator are either real or complex conjugates of one another.
This follows simply from the fact that \(M\) has only real entries. Now the book deduces, for \(\delta = 0\), that the eigenvalues must be mutually reciprocal. We shall show this even for \(\delta = 1\):
Lemma: The product of the eigenvalues of the monodromy matrix \(M\) of a parametric oscillator is one.
Proof: Liouvilles formula (see reference section) entails for every fundamental matrix \(\Psi\) of a Floquet equation that
\[
\frac{d}{dt}\det\,\Psi(t) = \mathrm{tr}\,A(t) \cdot\det\,\Psi(t)
\]
Here \(\mathrm{tr}\) stands for trace, which is the sum of the diagonal elements of a matrix. For a parametric oscillator, that trace is zero. So \(\det\,\Psi(t)\) is constant. Because \(\Psi(t+T) = \Psi(t)M\), we have \(\det\,\Psi(t+T)=\det\Psi(t)\det M\). Since \(\Psi\) is constant, we have \(\det\,\Psi(t+T)=\det\Psi(t)\), and since \(\det\,\Psi(t)\neq 0\) we have \(\det\,M = 1\). The claim follows because the determinant is the product of the eigenvalues □

Combining the results of this section, we see that the eigenvalues are either reciprocal reals, or two non-reals on the complex unit circle which are complex conjugates of one another. When \(\delta = 1\), we know also that the two eigenvalues are the same, and so they are both one or both minus one.

Classification of possible behaviors

First, suppose that \(\delta = 1\). Then the eigenvalues are both one or both minus one.

If \(\mu = 1\), we have by an earlier corollary
\begin{align*}
x_1(t) &= \pi_1(t) + \frac{t}{T}\pi_3(t) \\
x_2(t) &= \pi_2(t)
\end{align*}
for \(T\)-periodic \(\pi_1\), \(\pi_2\), and \(\pi_3\), where \(x_1\) and \(x_2\) are coordinates which go along with the eigensystem of the monodromy matrix.

If \(\mu = -1\), we have
\begin{align*}
x_1(t) &= (-1)^{t/T} \pi_1(t) + \frac{t}{T}(-1)^{t/T-1} \pi_3(t) \\
x_2(t) &= (-1)^{t/T} \pi_2(t)
\end{align*}
Note that this entails that we have \(2T\)-periodic \(\rho_1\), \(\rho_2\), and \(\rho_3\) such that
\begin{align*}
x_1(t) &= \rho_1(t) + \frac{t}{T}\rho_3(t) \\
x_2(t) &= \rho_2(t)
\end{align*}

Now suppose that \(\delta = 0\). We concluded above that \(x_1(t) = \mu_1^{t/T} \pi_1(t)\) and \(x_2(t) = \mu_2^{t/T} \pi_2(t)\) for \(T\)-periodic \(\pi_1\) and \(\pi_2\).

If the eigenvalues are both one, we have \(T\)-periodic behavior, respectively. Note that in this case \(M\) is not just isomorphic to, but equal to the identity matrix. So any coordinate system is an eigensystem, that is, we can choose the \(x_i\) freely.

If the eigenvalues are both minus one, we have \(2T\)-periodic behavior. In this case \(M\) is not just isomorphic to, but equal to minus one times the identity matrix. So here too, any coordinate system is an eigensystem, so we can choose the \(x_i\) freely.

If the eigenvalues are other reals, the one whose absolute value is greater than one “wins” as \(t\) goes towards infinity. So the amplitude grows exponentially. If the eigenvalues are not reals, they are on the complex unit circle, and the amplitude has an upper bound.

Example: the Mathieu equation

The Mathieu equation is the parametric oscillator with
\[ \omega(t)^2 = \omega_0^2(1 + h \cos (\gamma t))\]
If this \(\omega(t)\) came from a child on a swing, it would be a strange child: one that stands and squats at a frequency \(\gamma\) independent of the resonance frequency \(\omega_0\) of the swing. Still, the Mathieu equation is important in physics.

Here is a graph showing the monodromy’s eigenvalues for the Mathieu equation with \(\omega_0 = 1\) and \(h = 1\). The vertical axis corresponds to \(\gamma\), which ranges from \(0.2\) to \(5\). Horizontally, we have the complex plane. For each \(\gamma\), the graph contains both eigenvalues of the corresponding monodromy matrix. I refrained from drawing the coordinate axes, to avoid clutter.

Parametric oscillator: a graph showing the eigenvalues of a Mathieu equation
The eigenvalues of a Mathieu equation as \(\gamma\) changes

The graph shows that, for every \(\gamma\), the eigenvalues are either (1) on a circle, which happens to be the unit circle, or (2) opposite one another on a perpendicular of the circle, actually, reciprocal reals. This agrees with our mathematical results about the possible eigenvalues. In case (1) we have no resonance. In case (2), we have resonance.

The greatest resonance is represented by the “face of the bunny”, around \(\gamma = 2\omega_0 = 2\), connected to the circle at \(-1 + 0i\). The second greatest resonance is represented by the bunny’s (uppermost) tail, around \(\gamma = \omega_0 = 1\), connected to the circle at \(1 + 0i\). This second greatest resonance corresponds to a normal child that stands and squats once during a period of the swing. The greatest resonance corresponds to an eager child that turns around at the apex, facing down again, and stands and squats again on the way back.

There are also resonances for smaller \(\gamma\), their connection points with the circle alternating between \(-1 + 0i\) and \(1 + 0i\).

It is worth noting that, for smaller \(h\), the resonance areas can shrink in such a way that only the bunny’s face at \(\gamma = 2\) remains, while all resonances at smaller \(\gamma\) vanish. That is: if the child’s standing and squatting have a small amplitude \(h\), the child needs to stand and squat more often to achieve resonance.

The transition into and out of resonance

Possible shapes of the monodromy matrix

As we have seen, the transitions into and out of resonance happen where the eigenvalues are both one or both minus one. This means that the Jordan normal form of the monodromy matrix is
\[
\left(\begin{array}{cc}
1 & \delta \\
0 & 1
\end{array}\right)
\qquad \mathrm{or} \qquad
\left(\begin{array}{cc}
-1 & \delta \\
0 & -1
\end{array}\right)
\]
where \(\delta\) is zero or one. So:

To fully understand the transitions into and out of resonance, we must know \(\delta\)!

From the start, I wondered about the case where \(M\) cannot be diagonalized, that is, \(\delta = 1\), since that was left aside in the book. Next, I was intrigued by the instantaneous ninety-degree turns where the bunny’s body meets the face or a tail. Those points turned out to be the only ones where \(M\) might be undiagonalizable. So I kept running into the question about \(\delta\).

I checked, with Mathematica, the bunny’s two transition points for the resonance at \(\gamma = 2\), and its two transition points for the resonance at \(\gamma = 1\). In all cases, we have \(\delta = 1\). So the question arises:

Is it true for all parametric oscillators that the monodromy matrix is undiagonalizable at all transitions into and out of resonance?

We shall now shed light on this question.

The meaning of diagonalizability and lack thereof

First, suppose that \(\delta = 0\). If \(\mu = 1\), we have, as observed above, two linearly independent solutions \(x_1(t) = \pi_1(t)\) and \(x_2(t) = \pi_2(t)\) where the \(\pi_i\) are \(T\)-periodic. Since every solution \(x(t)\) is a linear combination of those \(x_i\), it follows that every solution is \(T\)-periodic. So, for every initial phase \((x(t_0), v(t_0))\) at some \(t_0\), the corresponding solution is \(T\)-periodic. If \(\mu = -1\), we can deduce by a similar argument: for every initial phase \((x(t_0), v(t_0))\) at some \(t_0\), the corresponding solution is \(2T\)-periodic.

Now suppose that \(\delta = 1\). If \(\mu = 1\), we have, as observed above, two linearly dependent solutions \(x_1(t) = \pi_1(t)\) and \(x_2(t) = \pi_2(t) + \frac{t}{T} \pi_3(t)\) where the \(\pi_i\) are \(T\)-periodic. So the solution space, which is two-dimensional, has a one-dimensional subspace of \(T\)-periodic functions. All other solutions grow linearly with time. So for every \(t_0\), the (also two-dimensional) space of initial conditions at \(t_0\) has a one-dimensional subspace of \(T\)-periodic solutions. For all other initial conditions, the solutions grow linearly with time. For \(\mu = -1\), we get something similar: for every \(t_0\), the space of initial conditions has a one-dimensional subspace of periodic solutions, this time with period \(2T\). Again, all other solutions grow linearly.

In summary: for \(\delta = 0\), all solution are periodic, while for \(\delta = 1\) only some are periodic. In the latter case, we can destabilize a periodic solution by arbitrarily small changes of the initial conditions.

Undiagonizable examples

We shall now give a stringent example, more illuminating than the Mathieu equation, where \(\delta = 1\), that is, \(M\) cannot be diagonalized. Here \(\omega\) will be a certain rectangular pulse:
\[
\omega(t) =
\begin{cases}
1 & 0 \leq (t\!\! \mod T) < t_1
\\
\omega_{\mathrm{max}} & t_1 \leq (t\!\!\! \mod T) < t_2
\\
0 & t_2 \leq (t\!\!\! \mod T) < t_3 < \frac{\pi}{2}
\\
1 & t_3 \leq (t\!\!\! \mod T) < T
\end{cases}
\]
Here \(T\) is the period, which we must still determine. And \(\omega_{\mathrm{max}}\) is a value greater than one, which we must still determine. For the construction, we assume temporarily as initial conditions \(x(0) = 1\) and \(v(0) = 0\). That is, the solution is the cosine for \(0 \leq t < t_1\). We let \(t_2 = t_1 + \Delta t\) for a small \(\Delta t\). The \(\omega_{\mathrm{max}} > 1\) “accelerates the swing”, that is, the solution increases its descent more than a cosine while \(\omega_{\mathrm{max}}\) lasts. We choose \(\omega_{\mathrm{max}}\) in such a way that at \(t_2\) the solution’s first derivative is minus one. There it remains until \(t_3\) since \(\omega\) is zero there. We let \(t_3\) be the point where the solution is zero for the first time for positive \(t\). So, from \(t_3\), the solution is again a like cosine with amplitude one, but shifted a little to the left. We let \(T\) be the time, slightly less than \(2\pi\), where the solution is zero the second time for positive \(t\). Obviously, the solution is periodic with \(T\). It looks like a cosine, except that in the first quadrant there is a “fast forward” lasting from \(t_1\) to \(t_3\).

So, our constructed parametric oscillator has a periodic solution. But are all solutions periodic? No! We fine-tuned \(\omega(t)\) so that it would have a periodic solution specifically for the initial condition \(x(0) = 1\) and \(v(0) = 0\). As can be easily checked, that there are other initial conditions with non-periodic solutions. So, owing to earlier observations, the initial conditions with periodic solutions form a one-dimensional subspace. That is, the only periodic solutions arise from initial conditions that are scalar multiples of \(x(0) = 1, v(0) = 0\). The period of our \(\omega\) function happens to agree with that of the oscillator’s solution, so the eigenvalues are one. In summary, our constructed parametric oscillator has
\[
M = \left(\begin{array}{cc}
1 & 1 \\
0 & 1
\end{array}\right)
\]

Our constructed \(\omega\) supplies one impulse in the first quadrant of the movement. So four quadrants pass between impulses. Obviously, we could modify our construction to have an impulse in the first and third quadrant. Then two quadrants would pass between impulses. So the solution’s period would be twice that of \(\omega\), and the eigenvalues would be minus one. We could also modify our construction to have six quadrants between impulses (eigenvalues minus one), or eight (eigenvalues one), or ten( eigenvalues minus one), and so on.

Diagonalizable examples

First I conjectured, in this post, that there is no parametric oscillator with non-constant \(\omega\) that has \(M = \mathrm{Id}\) or \(M = -\mathrm{Id}\). My conjecture was inspired by the previous section. But John Baez proved me wrong.

First, an example where \(M = \mathrm{Id}\). Consider the following non-constant \(\omega\):
\[
\frac{\omega(t)}{2\pi} =
\begin{cases}
1 & 0 \leq (t\!\! \mod 0.75) < 0.5
\\
2 & 0.5 \leq (t\!\!\! \mod 0.75) < 0.75
\end{cases}
\]

The solution for \(x(0) = 0\) and \(v(0) = 1\) is composed of two sine curves of different frequency:

The solution for x(0) = 0 and v(0) = 1
The solution for x(0) = 0 and v(0) = 1

It is periodic, with period \(0.75\). The solution for \(x(0) = 1\) and \(v(0) = 0\) is composed of two cosine curves of different frequency:
 The solution for x(0) = 1 and v(0) = 0
The solution for x(0) = 1 and v(0) = 0

This too is periodic with period \(0.75\). Since the solution space is spanned by those two solutions, every solution is periodic with period \(0.75\). Since \(0.75\) is also the period of \(\omega\), both eigenvalues are one. So the monodromy matrix is the identity.

Now an example where \(M = -\mathrm{Id}\). Consider the following non-constant \(\omega\):
\[
\frac{\omega(t)}{2\pi} =
\begin{cases}
1 & 0 \leq (t\!\! \mod 1) < 0.5
\\
2 & 0.5 \leq (t\!\!\! \mod 1) < 1
\end{cases}
\]
The solution for \(x(0) = 0\) and \(v(0) = 1\) is composed of two sine/cosine curves of different frequency:

Solution for x(0) = 0 and v(0) = 1
Solution for x(0) = 0 and v(0) = 1

This is periodic, with period two. The solution for \(x(0) = 1\) and \(v(0) = 0\) too is composed of two sine/cosine curves of different frequency:
The solution for x(0) = 1 and v(0) = 0
The solution for x(0) = 1 and v(0) = 0

This too is periodic with period two. Since the solution space is spanned by those two solutions, every solution is periodic with period two. Since that is twice the period of \(\omega\), both eigenvalues are minus one. So the monodromy matrix is the minus identity.

References

  1. L.D.Landau and E.M.Lifschitz. Lehrbuch der theoretischen Physik I: Mechanik. Verlag Harry Deutsch, 14. Auflage.
  1. Wikipedia: Floquet theory
  2. Wikipedia: Liouville’s_formula
  3. Wikipedia: Matrix exponential
  4. Wikipedia: Logarithm of a matrix

An amateur’s foray into physics

It has long bothered me that I know so little about physics and the maths that goes along with it. There are some great popular-science books on physics, but I wanted to dig deeper. So I turned myself into a “self-taught undergraduate” last year (on a tiny, after-work time budget).

Like any university course in physics, I started with the sub-field of Classical Mechanics , which is concerned with the “set of physical laws describing the motion of bodies under the action of a system of forces” (Wikipedia).

So I bought some books (primarily the notorious Landau/Lifshitz) and began. Some of the exercises, even simple-looking ones, lead into remarkably big calculations. Even though I usually enjoy calculating, it felt like a chore sometimes, and I looked for a remedy. Luckily, we have computer algebra systems these days, and after some thought and trial I ended up using the Mathematica software.

I soon found the computer-aided approach addictive. Not only does the software help with big, boring, error-prone calculations. The need to formulate solutions in a machine-tractable way also makes me think more deeply and conceptually about the maths. Plus, the software leads me to discover useful maths I don’t yet know, like any programming language leads to discovering new useful libraries. Finally, the software makes it easy to play around with the parameters of an exercise and visualize the solutions.

This post shows an example of an exercise aced with computer help. It is about a mass that can move around on some surface, in the presence of gravity, with no friction. Like a piece of soap in a bath tub. Here is a concrete case:

A mass tied to a surface, moving under gravity, without friction
A mass tied to a surface, in the presence of gravity, with no friction

Classical mechanics has a neat way of describing a whole system of moving parts by a mathematical term called Lagrangian. It’s beyond the scope of this post to explain the theory behind Lagrangians, but they are really cool. The Lagrangian for this system is:
[mathjax]
$$ \frac{m}{2}(\dot{x}^2 +\dot{y}^2 +\dot{z}^2) – m g z + \lambda(z – h(x,y)) $$

The symbol \(m\) stands for the particle’s mass, \(g\) is the gravity constant, \(x\), \(y\) and \(z\) are the particle’s coordinates, and \(\dot{x}\), \(\dot{y}\) and \(\dot{z}\) the corresponding speeds. The function \(h\) describes the shape of the surface. It can be any sufficiently well-behaved function. In our example, I used a certain polynomial to obtain an interesting hilly terrain. The most interesting part of our Lagrangian is probably the constraint, \(\lambda\), which corresponds, up to constants, to the force that keeps the mass on the surface.

The Lagrangian is a succinct description of the system, but it does not lend itself well to calculate the actual motion. We need to calculate the laws of motion from a Lagrangian. The laws of motion are also called Euler-Lagrange Equations, or just Euler Equations or Lagrange Equations. They form a system of ordinary differential equations (ODEs). There is an easy method, which I won’t introduce here, to obtain the laws of motion from the Lagrangian. Mathematica even has an optional package, called “VariationalMethods”, which contains a command “EulerEquations”, which does exactly this: get the laws of motions from a Lagrangian. The result, in our case, turns out to be this system of ODEs:

\begin{align}
m \ddot{x} &= -\lambda \frac{\partial h}{\partial x} \\
m \ddot{y} &= -\lambda \frac{\partial h}{\partial y} \\
m \ddot{z} &= -\lambda – m g \\
0 &= z – h
\end{align}

Things are beginning to look quite Newtonian here: the first three equations have on the left side terms describing “mass times acceleration”. On the right side, they have terms that at close inspection turn out to be forces. The last equation results from the constraint and just states that the vertical \(z\) coordinate results from applying the surface description \(h\) to the horizontal coordinates \(x\) and \(y\).

We are now a step closer to calculating the actual motion, but we must still obtain the actual function that describes the movement. That function, which maps time to coordinates, is a solution of of the above system of ODEs. I wrote “a” solution and not “the” solution, because there is one solution for each initial condition, by which we mean the particle’s coordinates and speeds at the start of its journey. Of course, we must also fill in the mass \(m\), the gravity constant \(g\), and the surface shape \(h\) to determine the system fully.

In lucky circumstances, the “motion function” corresponding to a system of ODEs can be given as a symbolic formula. But often, the solution can only be approximated numerically. In our case, we can find symbolic solutions for certain very simple surfaces \(h\), e.g. non-curved surfaces, but not for interesting ones like the one in the animation above. In our case, the surface is actually
\begin{align}
h(x,y) &= (x-3)(x-2)(x-1) \\
& \quad (x+1)(x+2)(x+3) \\
& \quad (y-3)(y-2)(y-1) \\
& \quad (y+1)(y+2)(y+3)
\end{align}
Neither I nor Mathematica can find a symbolic solution for this \(h\). (It’s most likely impossible, but I don’t know how to prove that.) Even when we ask only for a numerical solution, Mathematica cannot give one straight away, because the system of ODEs contains certain snags. For Mathematica to succeed, I had to eliminate \(z\) and \(\lambda\) first, and then solve for \(\ddot{x}\) and \(\ddot{y}\). I’ll spare you the details, what counts is that finally, Mathematica is able to give a numerical solution.

Before I created the animation above, I played around with the initial conditions and let Mathematica visualize the trajectory of the particle:

The orbit of the sliding mass
The orbit of the sliding mass

After I found a nice trajectory to show off, I created the animation. The Mathematica programming language has convenient primitives for creating animations. The animation turned out to be very slow, because of the time the software needs to calculate the numerical solution of the ODE system. But that didn’t matter for this post, because I had to export the animation as a animated GIF anyway. Mathematica has a nice trick for doing this: there a command, called Table, which allows to create a sequence of images instead of an animation, like a thumb cinema. That image sequence can than be exported as a GIF.

In summary, we have seen: Classical Mechanics provides a great way to model systems by so-called Lagrangians. These lead automatically to the laws of motion. These form a system of ODEs that can be solved either by hand or with software. The software can also help explore and visualise the system.

Tracking vs. Tracing in the Windows Workflow Foundation (WF4)

The software my company offers includes, among many other things, workflows based on Microsoft’s Windows Workflow Foundation (WF4). These workflows are activated and resumed by WCF calls. That is, the workflows act as services and are hosted in the IIS. Every few months, I need to diagnose some tricky problem in such a workflow, and I cannot debug on customers’ systems. There are two .NET-mechanisms that can help here, “tracking” and “tracing”. Each time I face such a customer problem, I have to think anew which of those two mechanisms I should use, so I decided to write this up once and for all. As a good citizen, I put this on my blog, in case it might help someone else.

I will be pragmatic and just give examples. For theory and background, you can check the links at the end of this post.

Tracking

Tracking is specific to workflows. It can be enabled without changing application code. To enable it, we add an “etwTracking” element to the configuration file, as in the example below. Optionally, we add a “tracking” element that allows us to specify what we want to track and how. From the many possibilities, I have chosen “activityStateQueries”, which allows us to track a workflow’s inner activities.

<system.serviceModel>
  ...
  <behaviors>
    <serviceBehaviors>
      ...
      <behavior>
        <etwTracking profileName="MyTrackingProfile" />
      </behavior>
    </serviceBehaviors>
    ...
  </behaviors>
  <tracking>
    <profiles>
      <trackingProfile name="MyTrackingProfile">
        <workflow activityDefinitionId="*">
          <activityStateQueries>
            <activityStateQuery activityName="*">
              <states>
                <state name="*"/>
              </states>
              <variables>
                <variable name="*"/>
              </variables>
            </activityStateQuery>
          </activityStateQueries>
          ...
        </workflow>
      </trackingProfile>
    </profiles>
  </tracking> 
<system.serviceModel>

A more complete tracking profile, with interesting extra options, is in the “Links” section below.

The tracking data can be viewed with Microsoft’s “eventvwr.exe”, which exists on customers’ machines. Running the tool on the tracking data will result in something like this:

Tracking

To make this work, we first need to right-click on “Application Server-Applications”, and chose “View > Show Analytical Protocols”. Otherwise, we won’t see the “Debug” protocol which contains the tracking data. Finally, we can browse through the events. In the screenshot, we have picked a variable-binding event, as can be seen in the bottom pane. If the variable’s were of basic type, like “int”, we would see the variable’s value. Unfortunately, for complex types like our class “Credentials”, the properties of the object are not displayed. Maybe they can be displayed with a “Custom Tracking Participant” as introduced in the “Tracking Participants” link at the end of this post. More generally, Custom Tracking Participant provide a way to go beyound the out-of-the tracking capabilities. The downside of Custom Tracking Participants is that they must be implemented by the user.

Tracing

Unlike tracking, tracing is not specific to workflows. It too can be enabled without changing application code, and also produces events viewable with “eventvwr.exe”. But it has a great extra option that helps understanding the interplay between workflows and their environment. To use this option, we must first direct the tracing output into log files. This can be done by inserting something like the following code into the application’s configuration file, as a child of the <configuration>-element. In our case, that file is the “web.config” of the workflow application hosted in the IIS. One can trace various sources, employ various listeners, and hook up each source with some of those listeners. Consider this configuration code:

  <system.diagnostics>
    <sources>
      <source name="System.ServiceModel" switchValue="Information, ActivityTracing" propagateActivity="true">
        <listeners>
          <add name="myTraceListener" />
        </listeners>
      </source>
      <source name="System.Activities" switchValue="Information">
        <listeners>
          <add name="myTraceListener" />
          <add name="myTextListener" type="System.Diagnostics.TextWriterTraceListener" initializeData="c:\Windows\Temp\MyTrace.txt" />
        </listeners>
      </source>
    </sources>
    <sharedListeners>
      <add name="myTraceListener"
           type="System.Diagnostics.XmlWriterTraceListener"
           initializeData="c:\Windows\Temp\MyTrace.svclog" />
    </sharedListeners>
  </system.diagnostics>

This xml-example specifies two sources: the first one, named “System.ServiceModel”, ensures that we record the WCF traffic that drives the workflows. That traffic includes WCF calls that activate the workflow for the first time, resume it after it went idle, and replies to such calls. The inner workings of the workflow are not recorded. The other source, “System.Activities”, ensures that we record the inner workings – in particular the events when activities inside the workflow are scheduled, started, and completed.

Both sources use the same listener, “myTraceListener”, which is declared in the <sharedListeners>-element. Writing into a common listener helps analyzing the data, as we shall see. The listener is an “XmlWriterTraceListener”, and it writes the output of both sources into the file “MyTrace.svclog” specified in the xml example. Before we analyze the data, note that the second source also writes its data to another listener, “myTextListener”, which is of type “TextWriterTraceListener” and writes unstructured text into the file “MyTrace.txt”. Note that “myTextLister” needs no entry in the <sharedListeners>-element, because it is used only “locally” by the first source.

Caution: the path to the log files must have sufficient access rights so that the logs can be written! If the logs do not appear, the access rights are the first thing to check.

Now let’s analyze the data in “MyTrace.svclog”. It can be viewed with Microsofts “SvcTraceViewer.exe”. That tool is unlikely to exist on customer’s machines. We will probably copy the log file to a developer machine and analyze it there. When we run the tool on the log and switch into the “Graph” tab, we get something like this:

SvcTraceViewer

Consider the six vertical columns in the chart on the left. Each square corresponds to a line in the upper-right pane. The details of the highlighted line can be seen in the lower-right pane. Each line comes from one of the two sources. As it happens, the rightmost column in the chart – that is,  the column with the many green squares, contains the inner workings of the workflow – that is, the events for scheduling, starting, and completing of the workflow’s internal activities. The five columns on the left correspond to various layers outside of the workflow. The arrows stand for communications – requests and answers. I will spare you the details, but the important thing is: By mixing two sources, we created a chronological chart that contains all events of both sources, and the communications between all layers.

Summary

Tracing gives a great overview of the large-scale interplay between workflows and the environment, plus many details of the workflow execution. Tracking too shows many details of workflow execution, but seems less useful for the big picture. However, tracking can be extended by “Custom Participants” as described in the “Tracking Participants” link below, making tracking potentially more powerful than tracing.

Links

  1. Overview forTracking and Tracing: http://msdn.microsoft.com/en-us/library/vstudio/ee513992(v=vs.100).aspx
  2. Tracing: http://msdn.microsoft.com/en-us/library/vstudio/ee518966(v=vs.100).aspx
  3. Tracking: http://msdn.microsoft.com/en-us/library/vstudio/ee517415(v=vs.100).aspx
  4. Tracking Participants: http://msdn.microsoft.com/en-us/library/ee513993(v=vs.110).aspx
  5. A more complete tracking profile: http://stackoverflow.com/questions/20998149/tracking-profile-implementation-visibility-attribute-has-no-impact

Book review: “The Infinite Resource” by Ramez Naam

Suppose you want a clear picture of climate change, or more generally, the effects of humanity’s increasing usage of Earth’s resources. And suppose you want the information from someone who is very bright, has done a lot of research, is neither alarmist nor denialist, does not engage in party politics, but simply digs up facts. Finally, suppose you are not the type to resign and complain, but enjoy a constructive discussion aiming at a course of action. Then Ramez Naam’s book is for you.

Infinite Resource Final Cover - 96dpi

In the first parts of the book, Naam gives a lot of information about the current state of Earth’s atmosphere and the dangerous changes that will continue if we don’t act (and, to a lesser extent, even if we do act). Besides climate, he also discusses other kinds of resource depletion, for example, the over-fishing of the oceans. Throughout, he succeeds in remaining factual and gives lots of convincing data.

After this – sobering – account of the status quo, Raam describes how humanity, through the “infinite resource” of innovation, has again and again achieved incredible improvements in the usage of natural resources. Examples include the staggering drop of agricultural area needed to feed one person, the successful fight against acid rain (caused by SO2) and ozone depletion (caused by CFCs).

In the later parts of the book, Naam argues that we have a good chance of succeeding again, but that the suffering we will cause along the way will be a lot less if we act proactively. And he proposes a remarkable concrete (and convincing) course of action, including: fixing the market to include the costs for environmental damage, investing in long-term R&D, overcome our reflexes and embrace technologies that seem alien, and drive education, in particular in the developing world.

A short review of “Tigana” by Guy Gavriel Kay

Given how many great fantasy authors I’ve read (Tolkien, Martin, Abercrombie, Rothfuss, Sanderson among them), it is surprising how late I stumbled upon this gem from 1990 by Guy Gavriel Kay.

Tigana

Of all fantasy books I discovered so far, this is probably the most intellectual, in a good way. The plot is brilliant and contains many surprises, and the prose is beautiful. There are no simple notions of good and evil, but a number of complex people driven into tragic conflict by past events or inclination. I cared about some of the characters so much that I could hardly bring myself to read on for fear of their fate.
If I were pressed to state any shortcomings of the book, the only one I’d mention is this: like Tolkien’s books, and unlike some other modern ones by Martin and Abercrombie, Tigana does not play with incompetence, ugliness, and dirt: there is no fun to be had with incompetent, foolish military leaders; there is no ugly character, and all women are beautiful; there are some physical injuries, but there is never infection.
In truth, these “shortcomings” don’t harm the book at all, it is fantastic. I just wanted to point out what the book does and what it does not.
In summary, I think that Tigana represents a pinnacle in fantasy writing. It probably comes close to the limit of what can be achieved in the genre, except in the aforementioned “ugliness, incompetence, and dirt” dimension.

A quick review of Joe Abercrombie’s “Red Country”

I just posted this book review of Joe Abercrombie’s Red Country on Amazon:

Red Country

I “read” the audiobook from Audible. It blew me away. I like all of Abercrombie’s books, yet I’m tempted to say this is the best one yet (maybe tied with The Heroes). There is no single wasted word. The characters are vivid, the story riveting from beginning to end. The character’s fates are masterfully intertwined in remarkable ways. The story is set in the same world as Abercrombie’s previous books, and some old characters return. There is tragedy, comedy, and farce. While knowing Abercrombie’s earlier books is not strictly necessary for enjoying this one, it seems recommendable to read them first.

The speaker Steven Pacey does an incredible job lending a unique and memorable voice to every main character, of which there are many.

I’m fairly sure this is one of the few books I will read a second time.

My online experience with Stanford’s “Introduction to Databases”

I just finished an online course offered by the University of Stanford, Introduction to Databases. It was taught, not for the first time, by the delightful and heroic Prof. Jennifer Widom and lasted from January 15 to March 23. This experience means a lot to me for reasons that will emerge below. This post is aimed at people who are interested in online learning in general, or in this particular course (which will probably be repeated). I am also writing this summary for myself, so feel free to skip passages which seem too biographical.

MOOCforBlog

(Remark: If you are a creator of an online computer-science course, please have a look at this post’s section about automated exercises, gamification, and test-driven design.)

Number of students and their backgrounds

Early activities in the course forum showed that the students came from all continents. (In particular, I was happy to see people from all over Africa.) Students’ ages and backgrounds seemed to differ wildly. According to a statistics page at the end of the course, there were 64127 registered students; 20836 turned in some work; 4854 received a “Statement of Accomplishment” (which can be seen as passing the course), and 1927 received the harder-to-obtain “Statement of Accomplishment With Distinction”. Some observers thought this meant a very high dropout rate, but I disagree: considering that this course is free, and signing up is trivial, I find it impressive that almost a quarter of the people who turned in some work passed.

Prof. Widom also stated that there was a remarkable proportion of middle-aged IT professionals (like me) seeking to polish their skills.

My own motivation

My interest had several reasons:

  • In my job as software engineer, I often deal with databases. While learning-by-doing goes a long way,  academic knowledge is still very beneficial.
  • I have a university degree and a PhD in computer science, but I accidentally skirted around databases. That felt wrong.
  • I am fascinated with computer aided learning, ever since I took a computerized French course in the mid-nineties and realized I could learn the language faster than I had learned other languages in school.
  • In the early 2000s, I was a computer science lecturer myself, preparing lots of downloadable material (which is be still available, on this blog). If I still were a lecturer, I might be attempting to give an online course today.
  • Finally, I deem it possible that online courses like the Stanford one are spearheading a revolution in academic teaching, and I want to watch it while it happens.

How the course worked

On the course page, you can see the schedule straight away. There is a simple sign-up procedure where you create an account before tackling the course.

The lectures

The lectures are: Introduction, Relational Databases, XML Data, JSON Data, Relational Algebra, SQL, Relational Design Theory, Querying XML, UML, Indexes, Transactions, Constraints and Triggers, Views, Authorization, Recursion, Online Analytical Processing, NoSQL.

They are to be followed over a period of ca. nine weeks.

Prof. Widom in action

The quizzes

Almost every lecture comes with a quiz that contributes to the student’s final score. The quizzes are multiple-choice, automatically graded, and very well designed in most cases. Each quiz has to be taken by a certain date, otherwise the score gets halved. Thus, the quizzes set the pace of the course.

The exercises

Many lectures have automatically graded “exercises”. Here the students are asked to write queries in SQL, Relational Algebra, Xquery, or XSLT. A query is typically run against a test database, and passes the automatic check if the result set is correct. (In some cases, cheating by hard-wiring the result is possible, but so cumbersome that one might as well supply a good solution.)

There are simpler “core” exercises, and harder “challenge” exercises.

I loved those exercises and found them almost addictive.

The exams

There was mid-term exam and a final exam. Both were multiple choice, open for three days, and once started, had to be finished within (generous) two hours.

The scoring scheme for the course (quizzes, exercises, and exams) is described here.

The forum

The course also sports a forum, which was rather fun. In the beginning, students from all over the world introduced themselves. Then the interaction turned gradually towards frantic questioning and answering. Most answers were provided by students, and some by Prof. Widom’s assistant Garrett. Near the end of the course, there where many students thanking Prof. Widom and Garrett.

Certification?

At the end of the course, the student receives a “Statement of Accomplishment” showing how they performed. Unsurprisingly, this statement has no official character: because there was no face-to-face authentication, and no invigilation during tests, the student could have cheated to their heart’s content.

The lack of an official certificate is lamentable, but obviously not the fault of this particular course. It is a problem that online learning in general still needs to address.

Time consumption and difficulty

Calculating the effort is tricky. One passes the course with a 50% score according to the scoring scheme linked above. With a good deal more effort, one can obtain a “distinction”. Because the quizzes and exams are well designed, a better score really means better understanding, so aiming for a good score is a worthy goal.

I was probably an atypical student in this course: on the one hand, I had the privilege of an extremely strong academic education in computer science, at several universities, and that helped me a lot. On the other hand, my ambitions went way beyond the distinction boundary, and that cost me a lot of time. All in all, I spent ca. 130 hours, including everything: videos, quizzes, exercises, and exams plus preparation. That amounts to ca. 14 hours a week. A complete computer-science beginner may have to work hard to pass the course. By contrast, a professional software engineer would probably pass with moderate effort, and require maybe 10 hours a week for a distinction. If you want to get every detail right, it gets a lot harder.

Was it worth it?

After this course, I feel more confident when dealing with databases, despite the fact that I had a lot of previous experience. I also gained a much better understanding of the area of databases in the widest sense. Plus, I satisfied my curiosity about how it feels to partake in a top online university course.

So yes, it was definitely worth it.

Do I want to take more such courses?

My enthusiasm may suggest that I generally recommend skilling up with online university courses. But things are not so simple. I, for example, am a quick learner, but also a quick forgetter, unless I apply lessons quickly. Luckily, I can quickly apply many lessons of this database course, and those will be cemented into my long-term memory. It could be very different with other courses, no matter how interesting. I will therefore remain focused on learning-by-doing, but keep my eyes open for interesting online courses I can quickly apply.

Of course, dear reader, if your memory is better than mine, you may come to very different conclusions.

A key point: automated exercises, gamification, and test-driven design

The most interesting insight I gained was that there is a spectacular potential in automatically-checked exercises. The student writes an answer, and the system instantly verifies it.

This verification is trivial for multiple-choice questions, but even there the student benefits from the immediacy of the feedback.

By contrast, the verification performs heavy lifting when the system checks a whole computer program the student has written! Here the immediate feedback is extremely motivating. It introduces an element of gamification: the learning process can feel as addictive as a good (computer) game. (At least to those that like games.)

Besides the benefits for the student, one should mention how automated exercises can reduce the per-student workload of teaching personnel.

And there is another fascinating aspect of automated exercises: test-driven design is becoming increasingly prevalent in software engineering. It means that every piece of production code is preceded by unit tests. (A unit test is another piece of code, which pretends to be a user of the production code and checks if the latter behaves as expected.) Similarly to unit tests, the exercise-checker in Widom’s course checks the students’ code (queries written in SQL, XSLT, and the like), by inspecting the result set. So it is similar to a unit test, except that in typical unit test scenarios, the code is a non-declarative programming language like Java, and not a declarative one like SQL. So: One could create a great programming course by introducing automatic exercises where the student has to beat unit tests! Knowing the extreme importance of test-driven design from first-hand experience, I am sure that this alley should be explored.

Final words

Prof. Widom mentioned once that turning her existing database course into an online one was an incredible amount of work. Having been a lecturer myself, I can easily believe that. Her achievement makes me feel gratitude and admiration. She surely is not the first or only person to set up such a course; all such people are heroes to me.

On testable architectures and how Java-like type systems can harm them

Generally, I’m all for static typing. After all, it make it possible to ensure aspects of program behaviour in a universal way, as opposed to unit tests, which operate on an anecdotal basis. Imagine my surprise when I realized that certain widely-used static type systems, like the ones of Java or C#, can lure programmers into an architectural trap, unlike dynamic type systems like the one of Python. Let me explain.

Consider the following two classes (I am using C# syntax, but I might as well use Java):


public abstract class Car
{
public void Drive()
{
// some code involving the methods
// Accelerate, Brake and Turn below
}

public bool Check()
{
return CheckEngine() && CheckBreaks();
}

public void Repair()
{
RepairEngine();
RepairBrakes();
}

protected abstract void Accelerate();
protected abstract void Brake();
protected abstract void Turn();

protected abstract bool CheckEngine();
protected abstract bool CheckBrakes();

protected abstract void RepairEngine();
protected abstract void RepairBrakes();
}

public class Workshop
{
public void Fix(Car car)
{
if (!car.Check())
car.Fix();
}

public void RunAdvertising()
{
// some code
}
}

We have a Car class and a Workshop class. Car is a typical “framework” class in the sense that, to produce an instance, we need a subclass which overrides some virtual methods (Accelerate, Brake, Turn, CheckBrakes, CheckEngine, and RepairBrakes, and RepairEngine). By contrast, code that consumes instances of Car, as does the Fix method of Workshop, can only call non-virtual methods of Car (Drive, Check, and Repair). (In C#, methods are non-virtual by default, while in Java one would use the modifier “final”. At any rate, Drive, Check, and Repair are cleary intended to be non-virtual from a framework point of view.)

Cars and workshops are very different things, and therefore should be considered separate units for testing. For example, if the team responsible for Car breaks the implementation of Repair, the unit tests for Workshop should still succeed, because the code there has not changed and all that matters is that it calls the Check and Repair methods in a particular way. So a good unit test for Workshop would introduce a mocked Car that records the actions of its callers, then apply the Fix method to it, and finally check if the records are correct. Here is a first attempt:

private class MockedBrokenCar : Car
{
private ArrayList _trace = new ArrayList();

public override bool Check()
{
_trace.Add("Check");
return false;
}

public override void Repair()
{
_trace.Add("Repair");
}

public ArrayList GetTrace() { return _trace; }
}

[TestMethod]
public void TestRepairOfBrokenCar()
{
var workshop = new Workshop();
var car = new MockedBrokenCar();

workshop.Repair(car);

var trace = car.GetTrace();
Assert.AreEqual(2, trace.Count);
Assert.AreEqual("Check", trace[0]);
Assert.AreEqual("Repair", trace[1]);
}

Unfortunately, this unit test does not compile: the methods Check and Repair cannot be overridden, because they are not virtual! (Incidentally, I am avoiding mocking frameworks on purpose here, because I do not want to distract from the language issues.)

A good solution to our problem would be to introduce interface(s) for the non-virtual, public methods of Car, e.g. like this:

public interface IRepairable
{
bool Check();
void Repair();
}

public interface IDrivable
{
void Drive();
}

public abstract class Car : IRepairable, IDrivable
{
void IDrivable.Drive()
{
// some code involving the methods Accelerate, Brake and Turn
}

bool IRepairable.Check()
{
return CheckEngine() && CheckBrakes();
}

void IRepairable.Repair()
{
RepairEngine();
RepairBrakes();
}

protected abstract void Accelerate();
protected abstract void Brake();
protected abstract void Turn();

protected abstract bool CheckEngine();
protected abstract bool CheckBrakes();

protected abstract void RepairEngine();
protected abstract void RepairBrakes();
}

public class Workshop
{
public void Repair(IRepairable car)
{
if (!car.Check())
car.Repair();
}

public void RunAdvertising()
{
// some code
}
}

This improved version allows us to write a compilable version of the above unit tests:

private class MockedBrokenCar : IRepairable
{
private ArrayList _trace = new ArrayList();

bool IRepairable.Check()
{
_trace.Add("Check");
return false;
}

void IRepairable.Repair()
{
_trace.Add("Repair");
}

public ArrayList GetTrace() { return _trace; }
}

[TestMethod]
public void TestRepairOfBrokenCar()
{
var workshop = new Workshop();
var car = new MockedBrokenCar();

workshop.Repair(car);

var trace = car.GetTrace();
Assert.AreEqual(2, trace.Count);
Assert.AreEqual("Check", trace[0]);
Assert.AreEqual("Repair", trace[1]);
}

So far, I have said nothing a good programmer does not already know. But is important to note that (1) the first Car/Workshop example, which thwarts the unit test, still occurs a lot in modern software, and the unit test simply remains unwritten, and (2) the refactoring needed to obtain the testable, interface-based example can be very costly in realistic scenarios. (I am speaking from experience). In fact, code as in the first example abounds so much that articles and books are written about how to get rid of it. (The transition to the second version is not the same as “Inversion of Control” or “Dependency Injection”, but closely related to those.)

Now the funny thing is this:

The mistake in the first example is not even possible in a dynamically-typed language. In such a language one can always mock, because there are no static types that prevent it.

A Python programmer, for example, could never fall into the above trap, and would likely produce better and more complete unit tests. So we have a real-life example where a particular kind of static typing is harmful in that it lures programmers into an architectural trap.

Where does that leave us? I think these are the conclusions we should draw:

  1. We might consider the following approach to writing object-oriented software: whenever we use implementation-carrying types (like Car) in public signatures, we should think very hard if they might harm testability and, if necessary, replace them by interfaces.
  2. We could go even further. If, like me, you find it hard to see any justification for implementation-carrying types in public signatures, you may want to avoid them entirely.
  3. If we decided to prohibit implementation-carrying types in public signatures, we probably could and should enforce that by automatic compile-time checks (probably with existing tools, like FxCop).
  4. If we decided in favor of the prohibition, we might end up seeing the type systems of Java, C# and the like as the true culprits, because they fail to prevent the above architectural trap.

EDIT (13 Feb 2013): I have just learned that Microsoft already spotted the problem I described, and gave an (expensive) solution fairly recently: “shims”, see Microsoft Fakes. Shims are a technique to mock the unmockable – the unmockable being implementation classes without an interface. I don’t know if similar approach exists for Java. Regardless, my point remains that the problem only exists because of the languages’ type systems.