WalkerCodeRanger.com

Month: March 2014

March 28, 2014

Why CoffeeScript Isn't the Answer

CoffeeScript is an open source project that provides a new syntax for JavaScript. I have to say that I have a lot of respect for CoffeeScript and it got a lot of things right. The “golden rule” of CoffeeScript is “It’s just JavaScript”. That means there is a straightforward equivalent to every line of CoffeeScript. Consequently, there aren’t as many issues with JavaScript interop as there are with Dart (see Why I’m Ditching CoffeeScript by Chris Toshok for a discussion of how this isn’t true for accessor properties and a peek into the politics of open source). It also makes it easy to deal with any shortcomings in tooling, because the developer should be more comfortable switching between CoffeeScript and the compiled JavaScript, for example, when debugging in the browser without the aid of a source map. Though CoffeeScript has matured enough that a lot of those shortcomings have been resolved. Nevertheless, the assurance that you can read the compiled output is comforting. CoffeeScript programs can be very compact and require less typing. The language also protects you from many of the JavaScript land mines. For example, in CoffeeScript == compiles to the strict equality operator ===, making it impossible to use the dangerous loose equality operator.

The strengths of CoffeeScript were the reason that I argued for its use on the last project I was part of. Indeed, we adopted CoffeeScript and used the Mindscape Web Workbench extension for Visual Studio which compiled on save. For me, the compile on save was helpful in learning CoffeeScript because I could immediately see what the resulting JavaScript was without firing up a browser, as required by many of the other options that compile on the fly as part of an asset pipeline. If you’re seeking a similar approach you might also want to check out the popular Web Essentials plug-in. Though I found merging the compiled JavaScript files to by annoying enough that I am now moving away from that approach. I spent 6+ months on that project learning and working in CoffeeScript. Out of TypeScript, Dart and CoffeeScript I really can speak to the strengths and weaknesses of the last from experience. That experience has led me away from using CoffeeScript on my current project.

Ambiguous Code

I quickly found that there were situations where I couldn’t predict what a given chunk of CoffeeScript would compile to or couldn’t figure out how to write the CoffeeScript for the JavaScript I wanted. The problem arises because in CoffeeScript parenthesis, curly braces and commas are often optional and white-space and indention replace them. Frequently code I thought should compile didn’t. Consider this valid code.

func 5, {
   event: -> 45,
   val: 10}

Now, if the event function needs to be expanded, one would logically think it could be changed like this.

func 5, {
   event: (e) -> 
     if e.something
       36
     else
       45,
   val: 10}

However, that doesn’t compile. You have to drop the comma or move it onto the next line, before val.

How about something like func1 1, func2 2, 3? Does 3 get passed to the first or second function? I still frequently forget one place where parenthesis are not optional, leading to unexpected behaviour. The statement x = f -> f looks like it should assign x to the identity function, but it doesn’t. Instead, x is assigned the result of calling f with a function of no arguments returning f. Or how about this, a + b adds a and b while a +b calls a with the argument +b. There are lots of other examples of ambiguous and confusing syntax in CoffeeScript. For more examples, check out My Take on CoffeeScript by Ruoyu Sun and this Gist from Tom Dale.

Readable, Think Again

Ambiguous code is only one part of what makes CoffeeScript difficult to read. Everything is an expression (returns a value) and it has lots of control flow and operator aliases. All of which encourages very English sentence like code. However, that often makes the code less readable, not more. The human mind is good at understanding logic in symbols; English is not good at expression logic. As an example, consider the line eat food for food in foods when food isnt 'chocolate' from the CoffeeScript tutorial. The declaration of what food is occurs in the middle of the line and doesn’t even look like a variable declaration. Furthermore, until you finish reading the line it isn’t clear which foods will be eaten. That code could easily be worse if unless eat is undefined was added to the end, making the whole line conditional. One wouldn’t realize it was conditional until reading the end. Imagine if the expression before the for had been a complex multi-line method call with logic in it. Ryan Florence digs deeper into these issues in his post A Case Against Using CoffeeScript. Suffice it to say, many of the features added to CoffeeScript with the intent of making it “readable” actually have the opposite effect.

Variable Capture

In addition to the these confusions, CoffeeScript actually creates new mines that aren’t present in JavaScript at all. As explained by Jesse Donat in CoffeeScript’s Scoping is Madness, in CoffeeScript’s zeal for terseness and “simplicity” it has actually created a major pitfall around variable declarations. In CoffeeScript there is no variable declaration syntax equivalent to var in JavaScript. Instead, all variables are declared in the scope they are first assigned in. This means it is easy to accidentally change the scope of a variable and not even realize it.

To see how this would happen, imagine you are in a hurry to implement the next feature. Unbeknownst to you, the following code is near the bottom of the file you are about to modify.

innocent = (nums) ->
	lastValue = 1
	for num in nums
		doSomething lastValue, num
		lastValue = num
	lastValue

Now, near the top of a code file you add these lines. So that the file is now.

value = 42
lastValue = null
changeValue = (newValue) ->
	lastValue = value
	value = newValue


# many pages of code here


innocent = (nums) ->
	lastValue = 1
	for num in nums
		doSomething lastValue, num
		lastValue = num
	lastValue

Did you catch the error? Originally, lastValue was local to the innocent function, but now it is global to the file and the innocent function actually modifies it. We now have a bug waiting to happen when someone calls innocent then checks the value of lastValue. Keep in mind there could be multiple screens of code between these two code segments.

Not Far Enough

Certainly, a language that is “just JavaScript” won’t be able to fix everything. Yet, despite radically altering the syntax of JavaScript and claiming to only expose the good parts of JavaScript, in some ways CoffeeScript doesn’t go far enough in fixing the issues of JavaScript. For example, the + operator is still both numeric addition and string concatenation. That is frequently listed as one of the bad parts of JavaScript. Why no provide separate operators for the two? Likewise, the typeof operator “is probably the biggest design flaw of JavaScript, as it is almost completely broken” according to the JavaScript Garden, but CoffeeScript brings its behaviour over unchanged. Instead CoffeeScript could have altered the meaning of typeof to something that was more useful, for example the typeOf() function recommend by Douglas Crockford.

Classes Are an Illusion

Many developers wish that JavaScript had classes. This has led to numerous alternative ways to emulate class like functionality in JavaScript and libraries that embody those various approaches. Many of the different approaches don’t interact well with each other. There is even debate on whether to use constructors requiring the new keyword or to make everything a factory function. CoffeeScript has a class keyword that makes it easy to create classes. However, since “it’s just JavaScript” they are just one particular emulation of classes on top of JavaScript. Consequently, they may not play well with your library of choice. More troublesome is that they make other language features more confusing. In particular the this keyword. When creating a class you can’t help but feel that this should refer to the class everywhere within the body of the class. That is what it would mean for something to be a class. But the actual semantics of this are unchanged. For example, if you declare a class with methods using this.

class Car
  constructor: (@model) -> 

  drive: () ->
    alert "You are driving a " + this.model;

  delayed: () ->
    -> this.model

Because Car is a class, one expects this to always refer to the current car object, but instead it behaves like regular JavaScript.

myRide = new Car("BMW")
letsDrive = myRide.drive

letsDrive() # alerts "You are driving a undefined"

getModel = myRide.delayed()
alert("Delayed model: " + getModel()) # alerts "Delayed model: undefined"

Ultimately, JavaScript isn’t a class based language and classes never quite work right in it. I believe it is a mistake to push the language in that direction. For a more in-depth discussion of why this is the case, see JavaScript Doesn’t Need Class by Ian Elliot.

I have been writing JavaScript for 8 years now, and I have never once found need to use an uber function. The super idea is fairly important in the classical pattern, but it appears to be unnecessary in the prototypal and functional patterns. I now see my early attempts to support the classical model in JavaScript as a mistake.

And So…

CoffeeScript started from a strong position and good philosophical approach to the problem of the JavaScript Minefield. Unlike TypeScript, it was willing to break with JavaScript and fix its issues. Unlike Dart, it was intended to remain true to JavaScript and be fully interoperable. Realistically, the issues I have raised with CoffeeScript don’t come up every day. Ultimately though, they are enough to say we need something better. I hope to share some thoughts soon on what such a solution might look like. However, based on feedback in the comments, we’ll need to discuss JavaScript linters first.

This article is Part 4 in a 6-Part Series.

March 16, 2014

Ember.js on Cassette: Embedding Templates

I’m starting a new web application project, and I’ve decided to use Ember.js. That will enable me to provide users a slick single-page app experience. Since I am a .NET web developer by training, I plan to use C# and ASP.NET Web API as my server technologies. I could use tools like Lineman.js or Grunt to manage and package my client-side code. Instead, I’d like to use the Visual Studio toolchain, because it provides a lot of great tools for web application development. Since I already know Visual Studio, there will be almost no learning curve for me. I’m not trying to argue this is the right choice. I’m just trying to share a little about what it takes to make it work with Ember.js. Early on, I realized that I would want to bundle and minify all my scripts and templates. I’ve chosen the Cassette library for this which provides “asset bundling for .NET web apps”. Here is how I made it work with Ember.js, but first, why did I choose Cassette?

Why not ASP.NET Web Optimization

Ever since Microsoft released the ASP.NET Web Optimization framework, now available as a NuGet package, it has been the default choice on the .NET platform for bundling and minification of scripts and css. Indeed, I initially started with it. However, I quickly ran into a number of issues with it, all of which were made more challenging by the lack of documentation.

It provides support only for minification of *.js and *.css files by default and no support for languages like Less, Sass, TypeScript or CoffeeScript. I’ll be using Less, and possibly CoffeeScript. It seems the encouraged workflow for such languages in Visual Studio is to use the Web Essentials extension to compile them. However, with that, the compiled js or css files are included in the project and need to be committed to source control. I have found that to be problematic when doing merges in a DVCS. Also, it just seems like the wrong thing to do. Like committing the compiled assemblies of my .NET code. Even using third party or custom built extensions, it generally isn’t possible to mix languages in a single bundle. For example, I might want to combine some JavaScript libraries into a bundle containing CoffeeScripts I have written.

More serious than that, ASP.NET Web Optimization provides no support for compiling or embedding templates. In the official EmberJS template from Microsoft they use a beta version third party extension to provide template compilation for Ember.js and provide a 117 line class for embedding templates outside the the web optimization framework. The third party library appears to be abandoned, with 8 months since the last commit and still in beta as of March, 2014. Even with all that, the EmberJS template’s solution doesn’t switch between embedding and compiling based on whether the web optimization library is in debug mode, leading to possible problems.

Introducing Cassette

The Cassette library preceded Microsoft’s ASP.NET Web Optimization library and is arguably the primary alternative to it. If your familiar with how Web Optimization approaches bundling it may take a while to become accustomed to the Cassette approach. They use the term “bundle” somewhat differently, which is confusing when you are first learning. I recommend you read the “Getting Started” and “Assets and Bundles” sections of the Cassette v1 docs before switching and reading the the v2 docs. Those sections of the v1 docs explain basic concepts not explained in the v2 docs. Until I read them, Cassette wasn’t making any sense to me.

The main difference between the approaches is around what a bundle is. In the Web Optimization library, a bundle is a group of files that will be minified and combined into a single file. Referencing that bundle is including a reference to the combined file. Whereas, in Cassette a bundle is more like a group of files that work as a single dependency. Meaning that you would never want one file out of the bundle separate from another. Referencing bundles is then stating what the page’s dependencies are. The bundles are then minified and combined into three separate files for css, scripts and templates. For templates, Cassette supports the idea of embedding the templates rather than loading them from a separate file.

At the top of your cshtml page you reference any individual assets or bundles the page depends on:

@{
    Bundles.Reference("Scripts/jquery.js");
    Bundles.Reference("scripts/app"); // the main application bundle
    Bundles.Reference("Scripts/page.js");
    Bundles.Reference("Styles/page.css");
}

Then in the page body, you indicate where the html to include scripts, templates and style sheets should be rendered. This will then group the dependencies by type and, depending on whether Cassette is in debug or production mode, output either debug friendly assets or minified, compressed, cached, versioned assets.

<!DOCTYPE html>
<html>
<head>
    <title>Web App</title>
    @Bundles.RenderStylesheets()
</head>
<body>
    ...
    @Bundles.RenderScripts()
    @Bundles.RenderTemplates()
</body>
</html>

Cassette is a powerful library with many more features and options. Be sure to check out the documentation for the details. Additionally, the author of Cassette has created NuGet packages for drop in support for Less, Sass, CoffeeScript, TypeScript and more. One of those NuGet packages is for pre-compiling Mustache Templates using Hogan.js. Unfortunately, this doesn’t work for Ember.js, because it needs its own template compiler due to the get and set methods on Ember models. Never the less, we’ll see that all is not lost.

Configuring and Referencing an HtmlTemplateBundle

Setting up a bundle in Cassette for all your templates is very easy. Don’t install the Cassette.Hogan NuGet package since it doesn’t work with Ember.js. I choose to put all my templates in the app/templates folder following the example in the EmberJS template from Microsoft. The template uses the extension hbs for Handlebars templates, however I choose to use the also common extension handlebars, because it was more explicit. Since all the templates are in one directory, creating a bundle was an easy addition to my Cassette bundle configuration.

public class CassetteBundleConfiguration : IConfiguration<BundleCollection>
{
    public void Configure(BundleCollection bundles)
    {
        // Other configuration ...

        bundles.Add<HtmlTemplateBundle>("app/templates", new FileSearch()
        {
            Pattern = "*.handlebars",
            SearchOption = SearchOption.AllDirectories,
        });
    }
}

To reference the templates from my application page only required adding Bundles.Reference("app/templates"); to my bundle references. The templates were then automatically embedded in the page inside script blocks in place of the @Bundles.RenderTemplates() call right before the close body tag.

Giving Templates a “data-template-name”

There were some problems with the embedded templates at this point. The script blocks were being generated with an id attribute based on the path of the template file and the type attribute was set to “text/html” instead of “text/x-handlebars”. While there is some confusion over this, I believe that the data-template-name attribute is the preferred way of identifying your ember templates, rather than the id attribute. The reason is that nested route templates have names separated with ‘/’, but it is not valid to have the ‘/’ character in an html id. Fortunatly, Cassette is based around a very flexible pipeline model, making it easy to customize. After reading some of the documentation, poking around the source and reading some some code from the Cassette.Hogan package, I came up with a simple solution.

Cassette allows the bundle pipeline for any bundle type to be easily modified by implementing the IBundlePipelineModifier<T> where T : Bundle interface. All bundle pipeline modifiers are picked up automatically. Fixing the issues was almost as simple as setting the content type of the html template pipeline and swapping out the implementation of how templates were wrapped in a script block.

public class SetupHandlebarsPipeline : IBundlePipelineModifier<HtmlTemplateBundle>
{
    public IBundlePipeline<HtmlTemplateBundle> Modify(
            IBundlePipeline<HtmlTemplateBundle> pipeline)
    {
        // Set the content type
        var index = pipeline.IndexOf<ParseHtmlTemplateReferences>();
        pipeline.Insert(index, new AssignContentType("text/x-handlebars"));

        // Replace how the scripts are wrapped
        index = pipeline.IndexOf<WrapHtmlTemplatesInScriptElements>();
        pipeline.RemoveAt(index);
        pipeline.Insert(index,
            new WrapTemplatesInEmberScriptElements(new HtmlTemplateIdBuilder()));

        return pipeline;
    }
}

The new WrapTemplatesInEmberScriptElements class is basically the same as the old WrapHtmlTemplatesInScriptElements with the id= replaced by data-template-name=.

public class WrapTemplatesInEmberScriptElements : IBundleProcessor<HtmlTemplateBundle>
{
    private readonly IHtmlTemplateIdStrategy idStrategy;

    public WrapTemplatesInEmberScriptElements(IHtmlTemplateIdStrategy idStrategy)
    {
        this.idStrategy = idStrategy;
    }

    public void Process(HtmlTemplateBundle bundle)
    {
        foreach(var asset in bundle.Assets)
        {
            asset.AddAssetTransformer(new WrapTemplateInEmberScriptElement(bundle, idStrategy));
        }
    }
}

public class WrapTemplateInEmberScriptElement : IAssetTransformer
{
    private readonly HtmlTemplateBundle bundle;
    private readonly IHtmlTemplateIdStrategy idStrategy;

    public WrapTemplateInEmberScriptElement(
            HtmlTemplateBundle bundle,
            IHtmlTemplateIdStrategy idStrategy)
    {
        this.bundle = bundle;
        this.idStrategy = idStrategy;
    }

    public Func<Stream> Transform(Func<Stream> openSourceStream, IAsset asset)
    {
        return () =>
        {
            var template = openSourceStream().ReadToEnd();
            var scriptElement = String.Format(
                "<script type=\"{0}\" data-template-name=\"{1}\">\n{2}\n</script>",
                bundle.ContentType,
                idStrategy.HtmlTemplateId(bundle, asset),
                template
            );
            return scriptElement.AsStream();
        };
    }
}

An Exception

If you try the above code with version 2.4.1 or prior of Cassette, you’ll get an exception when it’s not in debug mode. I didn’t notice this issue until a week after writing the code above when I deployed to the test environment. The switch between production and debug mode can be confusing in Cassette, because it isn’t your first thought when something works on the developers machine but not the deployment environment. It took me at least an hour to track down the problem. In production mode the exception you get is KeyNotFoundException from deep inside Cassette around bundle cache code. Turns out that setting the content type to "text/x-handlebars" causes Cassette to not know what extension to give the cache file. That seems to be poor design choice to me, but essentially the fix is that "text/x-handlebars" needs to be added to a list of known content types. I have submitted a pull request to do this, that will hopefully be accepted soon, so this won’t be a problem in future versions. Until then, you can work around this by adding the following hack to the beginning of your CassetteBundleConfiguration.Configure() method.

// Hack so we can use type="text/x-handlebars" in release mode
var bundleType = typeof(Bundle);
var field = bundleType.GetField("FileExtensionsByContentType",
                                 BindingFlags.Static | BindingFlags.NonPublic);
var fileExtensionsByContentType = (IDictionary<string, string>)field.GetValue(null);
// Sometimes the config is run again and it is already there
if(!fileExtensionsByContentType.ContainsKey("text/x-handlebars"))
	fileExtensionsByContentType.Add("text/x-handlebars", "htm");

With that, my Ember.js templates where embedded correctly into the page and developers could begin work with a clean separation of the templates into individual files. Obviously, before production release I would like to be able to enable compiled templates when Cassette is not in debug mode, but that challenge can wait for another day.

March 8, 2014

Why Dart Isn't the Answer

Dart is Google’s latest answer to how to do large scale web application development. Dart isn’t just a new programming language it is a “platform”. That includes having its own standard libraries and tools. Additionally, even though Dart compiles to JavaScript, there is also a Dart VM that runs in a preview version of Chrome called Dartium. The language itself will feel very familiar to developers who have worked in JavaScript, Java and C#. Like TypeScript it’s “optionally typed”. That means type declarations are optional, but when you provide them the compiler will provide type checking warnings. Unlike JavaScript, it is class based rather than prototype based. It fixes the problems with both the syntax and semantics of JavaScript

Dart is a much more ambitious project than Microsoft’s TypeScript. It moves further away from both the syntax and semantics of JavaScript. So the JavaScript produced by the Dart compiler, while quite readable, may not correspond one-to-one with the original Dart source. The Dart compiler applies more transforms and optimizations to your code. Beyond that, even core libraries are replaced. Dart has it’s own DOM manipulation library that differs from the standard one provided by browsers. This allows them to fix not only problems with JavaScript, but problems with the browser APIs which are widely regarded as being one of the worst parts of client side web development. This ambitiousness makes Dart an exciting project that appears to be a real improvement over the current state of affairs.

Before we look at some problems with Dart, a word about the Dart VM. Since Google wants Dart to eventually be the platform of the web, they are hoping that they can convince browser makers to include a native Dart VM. Since they control one of the big three browsers, they are already 13 of the way there. However, many people feel that it is unlikely the other browsers will follow suit. It wouldn’t seem to be to their benefit to spend the time and money doing so. When Microsoft tried basically the same thing with VBScript in IE, it didn’t go well. Admittedly, the browser market isn’t as contentious and political as it was then, but competitors will always be competitors. To address this, Google has the, quite effective, compile to JavaScript escape hatch. The situation will be different if all major include a native Dart VM some day, but for now, the idea of a Dart VM is irrelevant to whether Dart is the answer to the JavaScript Minefield.

I guarantee you that Apple and Microsoft (and Opera and Mozilla, but the first two are enough) will never embed the Dart VM.

Brendan Eich, creator of the JavaScript language & active partcipant in JavaScript standardization

JavaScript Interop

Dart is such a radical departure from JavaScript that it is not possible to interact directly with JavaScript libraries from Dart. Instead, you must use a special interop library that exposes wrapped versions of any JavaScript objects you access. This enables Dart to safely sandbox JavaScript away and prevent its problems from leaking into a Dart application. This is very reminiscent of what Microsoft had to do with COM interop, for .NET all be it for somewhat different reasons. Like COM interop, JavaScript interop is not a pleasant experience. It’s a necessary feature for times when the only implementation for a library you need isn’t in the platform you are working in, but whenever possible you avoid it. The problem with that is, it tends to silo you in the platform you have chosen. Currently, many new and exciting JavaScript libraries are being released and the Dart platform is immature and hasn’t had time to fill out with all the options a developer might want. Being siloed into the Dart platform will be a very high price to pay to avoid the JavaScript minefield.

Another GWT?

The Google Web Toolkit (GWT) is a project first released by Google back in 2006. It provides a platform allowing developers to create client side web application in Java that are then cross-compiled to JavaScript. The GWT project has a lot of similarities to the Dart project. Both create a siloed platform with restricted interop options that addresses the pitfalls of working directly in JavaScript and the browser. The largest difference is that GWT builds on an existing language (Java) and platform which are potentially not as well suited to the needs of web development and semantically more distant from JavaScript. Never the less, the history of the GWT project is instructive. While it was released with fanfare and promise, it has remained a niche solution and is not where all the exciting advances in web development are being made today. I don’t see why the future of Dart should be any different.

Still not statically typed

It’s surprising to me that Google would deviate so far from the semantics of JavaScript and include optional typing but stop short of actually having static type checking. Dart’s type annotations have no effect on the execution of the code and the compiler only reports warnings, not errors, for type violations. Essentially, it is as if someone took a dynamic language like Ruby and added type annotations to it without actually changing the way the language works. Because of this, it is possible to put incorrect and misleading type declarations in a program, for example declaring an integer variable as an array of strings, and still have the program execute correctly. C# has shown with its dynamic type that a mix of dynamic and static typing can be interesting and useful. A language showing another way of mixing the two with dynamic as the default would be very interesting. Unfortunately, that isn’t what Dart is. Dart is a dynamic language, plain and simple. Type checking is just a jsHint style suggestion that something might be wrong. What’s the use of a type declaration if it doesn’t mean the value will actually be of that type?

To dig deeper, check out Why Dart is not the language of the future by Rafaël Garcia-Suarez.

Not the Answer

Previously we saw Why TypeScript Isn’t the Answer, today we have seen that neither is Dart the answer. It is much more ambitious and addresses many more of the JavaScript mines, but ultimately, it will be doomed to go the same way as GWT and not be a major player in web development. That is mostly a consequence of it’s separate platform approach, but also because of a few poor choices in the design of that platform.

This article is Part 3 in a 6-Part Series.