Friday, September 20, 2013

A taste of Spanner

Spanner is the name of my soon-to-be-released open source statically typed domain specific language for building Knockout web applications in C#. Here is a very brief sample, which I will let stand by itself: Build and run this program and you get the following web page:
+ = which is .

Now, this is a fairly trivial example, but it illustrates some of the key points about Spanner.
  • A Spanner program is completely, strongly, statically typed -- it's just C#. As soon as you make a type error in your program, Visual Studio will list the problem areas in the error window. The generated JavaScript code cannot contain type errors (well, up to the point where you start including third-party JavaScript libraries). This alone makes Spanner valuable.
  • Strong typing means you get strong refactoring support from Visual Studio.
  • You don't need special syntax for expressions: you can freely use +, -, /, *, etc.
  • Because you are writing in C#, you have all the usual mechanisms for abstraction (i.e., functions!). You are not limited to the ad hoc hodge podge of compromises necessary in ordinary HTML + JavaScript development.
  • You don't need special syntax for Knockout observables -- Spanner knows which variables are observables and which are plain old JavaScript variables and generates the appropriate code for reading and writing them. Indeed, observables are much more transparent in Spanner than they are in JavaScript.
  • All the documented, well-typed parts of Knockout are supported.
  • Every HTML element and every well-typed JavaScript construct is represented by a correspondingly named Spanner function.
  • The correspondence between HTML attributes and view model variables is transparent -- you never need to embed code or identifiers in HTML strings. This is another key benefit of Spanner.
  • Spanner handles all the usual types (int, double, string, arrays, enums, POCOs). There are no special cases.
  • Spanner supports modularisation via view/view-models pairs, "global" models (i.e., libraries), strongly typed templates, and use of arbitrary third-party libraries.
  • Spanner will sort all your code dependencies for you and emit modules and variable definitions in the right order.
  • Spanner provides mechanism rather than policy. As long as you are happy using Knockout for your observables, it is entirely up to you how to structure your web application.
  • Spanner makes it easy to mix hand-written JavaScript with Spanner-generated JavaScript. The two worlds work quite comfortably together, provided the non-Spanner JavaScript has a well-typed API (hah!).
  • Building happens in the blink of an eye. If you are used to waiting ages for MVC to do its thing, Spanner's instant turn-around will be a relief.
  • Normal web development is excruciating for anyone used to more sophisticated languages. You spend so much of your working day chasing down trivial bugs and the primitive languages involved practically force you to turn your code into a mess of expedient short cuts. I wrote Spanner as a reaction, to see how far I could Do It Right while using a mainstream programming language (trust me, if we all migrated to F# or Haskell, Spanner would look a lot less cunning).
  • Using Spanner will clearly make you more attractive to members of your favourite sex.
Watch this space. I have the code completed, tested, and documented. I am just putting together a web site with a tutorial and some demonstrations (as my old PhD supervisor said to me, never show an idiot something half finished :-)). Being a family man with a full time job, this may take a week or three...

9 comments:

Ilya said...

Interesting, I imagine you're neck deep in Expr parsing. I wonder if the Roslyn project would have eased these pains... (haven't had a look at it, but I get the sense it could assist in this). Anyway, I like it, has potential. Looking forward to seeing more examples (the sort of example covered by TodoMVC.com)


Rafe said...

The beauty of my scheme is that I only create expression trees, I never need to parse them. Each kind of expression knows how to print itself as JavaScript and there are only a few different "flavours" of expression. I'll try to put the code up this week for you. It's only about 1200 lines of working code, most of which is boilerplate implementing HTML tags and Js functions. I'll take a look at ToDo MVC for ideas for examples.

Ilya said...

Just came across this, something similar to what you're doing, black voodoo magic to define most of the KO info in C# and Razor: http://knockoutmvc.com/HelloWorld

Rafe said...

I looked at KnockoutMVC a year back and, at least then, it seemed to operate almost entirely in post-back mode. That is, no processing of any meaningful sort is done on the client, so it isn't really for building SPAs. Have a look at their "click counter" example: every button function calls executeOnServer(...).

Ilya said...

Oh ok, didn't spot that. Thought they were somehow emitting JS that matched the handler, on the client. If it needs to go back to the server, it is cheating.

I'm curious about all this Spanner stuff you're doing because recently we've been building rich client side web pages, using Telerik's MVVM framework and UI controls (Kendo UI). It's a bit of a knockoff of knockout (ha!). We ended up with a lot of server side helpers to try to move to a DSL like construction of pages, but we didn't go anywhere near as far as what Spanner does, just merely fluent builders for a range of elements...

Hope to see more of it soon!

Rafe said...

I nearly convinced my employer to let us use this approach, but after much deliberation they decided to go with more conventional tools. At least we weren't forced to go fully MVC!

All the things I was hoping to avoid have happened: most bugs are simple, but they take from tens of minutes to hours to locate and fix. If we'd been coding the same functions in C#, most such bugs would never make it past Visual Studio. Hence my interest in this approach.

Rafe said...

This morning I got up early and did a bit of hacking on Spanner to implement ToDoMVC. It was a worthwhile exercise, in that it revealed a wart I need to elide from the design. While I was doing it, I thought "in places, this is a tad more wordy than it would be in plain old HTML." Now, having spent a day at work immersed in HTML, TypeScript, and CSS. Holy crap, what a painful way to work. If I had any hair, I would be pulling it out in frustration. I realise now that a small amount of extra typing to save hours of fruitless bug tracing is surely worth the cost.

Ilya said...

The public demands another Spanner post!

Rafe said...

Hi Ilya, last night I finished ToDoMVC in Spanner. It was a worthwhile exercise which revealed a couple of design warts (one removed, one in need of a better solution), a couple of holes (filled), and a bug (also now fixed). To my delight, it all worked first time, which is what I was hoping for. The immediate feedback in the Visual Studio error window was invaluable.

I'm going to put it all up on Codeplex in the next few days, as soon as I find a few hours.

The end result is, I think, fairly pleasing. If you imagine JavaScript/HTML as English, it's as if someone were speaking correctly and very precisely, but with a pronounced foreign accent. I'm convinced it's far better than standard "stringly typed" web development.