JavaScript All the Way Down

A Slew of DDs!

Modern agile development processes usually emphasize very short cycles, based on writing tests for code yet unwritten, and then actually writing the desired code, the tests being both a check that the code works as desired and as a sort of specification in itself. This process is called TDD (Test-Driven Development), and it usually leads to modularized and flexible code, which also is easier to understand, because the tests help with understanding. BDD (Behavior-Driven Development) is a process based on TDD, which even specifies requirements in a form quite similar to the matchers mentioned in this article. Yet another "DD" is ATDD (Acceptance Test-Driven Development), which highlights the idea of writing the (automated) acceptance tests even before programmers start coding.

Building and Deploying

Whenever your code is ready for deployment, you almost certainly will have to do several repetitive tasks, and you'd better automate them. Of course, you could go with classic tools like make or Apache's ant, but keeping to the "JavaScript all the way down" idea, let's look at a pair of tools, Grunt and Gulp, which work well.

Grunt can be installed with npm. Do sudo npm install -g grunt-cli, but this isn't enough; you'll have to prepare a gruntfile to let it know what it should do. Basically, you require a package.json file that describes the packages your system requires and a Gruntfile.js file that describes the tasks you need. Tasks may have subtasks of their own, and you may choose to run the whole task or a specific subtask. For each task, you will define (in JavaScript, of course) what needs to be done (Listing 7). Running grunt with no parameters will run a default (if given) task or the whole gamut of tasks.

Listing 7. A Sample Grunt File


module.exports = function(grunt) {
  grunt.initConfig({
    concat: {
      dist: {
	  dest: 'dist/build.js',
	  src: ['src/**.js'],
      },
      options: 	{ 
	separator: ';',
	stripBanners : true,
      },
    },
    
    uglify: {
      dist: {
        files: 	{ 'dist/build.min.js': 
           ↪['<%= concat.dist.dest %>'] },
      }
    },
  });

  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.registerTask('default', ['concat', 'uglify']);
};

Gulp is somewhat simpler to set up (in fact, it was created to simplify Grunt's configuration files), and it depends on what its authors call "code-over-configuration". Gulp works in "stream" or "pipeline" fashion, along the lines of Linux's command line, but with JavaScript plugins. Each plugin takes one input and produces one output, which automatically is fed to the next plugin in the queue. This is simpler to understand and set up, and it even may be faster for tasks involving several steps. On the other hand, being a newer project implies a smaller community of users and fewer available plugins, although both situations are likely to work out in the near future.

You can use them either from within a development environment (think Eclipse or NetBeans, for example), from the command line or as "watchers", setting them up to monitor specific files or directories and run certain tasks whenever changes are detected to streamline your development process further in a completely automatic way. You can set up things so that templates will be processed, code will be minified, SASS or LESS styles will be converted in pure CSS, and the resulting files will be moved to the server, wherever it is appropriate for them. Both tools have their fans, and you should try your hand at both to decide which you prefer.

Getting and Updating Packages

Because modern systems depend on lots of packages (frameworks, libraries, styles, utilities and what not), getting all of them and, even worse, keeping them updated, can become a chore. There are two tools for this: Node's own npm (mainly for server-side packages, although it can work for client-side code too) and Twitter's bower (more geared to the client-side parts). The former deals mainly with Node packages and will let you keep your server updated based on a configuration file. The latter, on the other hand, can install and update all kinds of front-end components (that is, not only JavaScript files) your Web applications might need also based on separate configuration metadata files.

Usage for both utilities is the same; just substitute bower for npm, and you're done. Using npm search for.some.package can help you find a given package. Typing npm install some.package will install it, and adding a --save option will update the appropriate configuration file, so future npm update commands will get everything up to date. In a pinch, npm also can be used as a replacement for bower, although then you'll possibly want to look at browserify to organize your code and prepare your Web application for deployment. Give it a look just in case.

Conclusion

Modern fast JavaScript engines, plus the availability of plenty of specific tools to help you structure, test or deploy your systems make it possible to create Web applications with "JavaScript all the way down", helping your developers be more productive and giving them the possibility of working on both client and server sides with the same tools they already are proficient with. For modern development, you certainly should give this a thought.

Resources

Keep up to date with JavaScript releases, features and more at https://developer.mozilla.org/en-US/docs/Web/JavaScript.

Get the Traceur compiler at https://github.com/google/traceur-compiler. CoffeeScript can be found at http://coffeescript.org, and TypeScript is at http://www.typescriptlang.org. You can read a draft version of the AtScript Primer at https://docs.google.com/document/d/11YUzC-1d0V1-Q3V0fQ7KSit97HnZoKVygDxpWzEYW0U/mobilebasic. Finally, for more details on asm.js, go to http://asmjs.org.

Common client-side frameworks are AngularJS at https://angularjs.org, Backbone at http://backbonejs.org and Ember at http://emberjs.com, among many others. With Backbone, you also might consider Chaplin (http://chaplinjs.org) or Marionette (http://marionettejs.com) for large-scale JavaScript Web applications. MEAN.JS is at http://meanjs.org, MEAN.IO is at , and Sails is at http://sailsjs.org.

You certainly should use libraries like jQuery (http://jquery.com), MooTools (http://mootools.net), Dojo (http://dojotoolkit.org) or Prototype (http://prototypejs.org).

Use "promises" to simplify callback work in Node; you can choose among Q (https://github.com/kriskowal/q), when (https://github.com/cujojs/when), bluebird (https://github.com/petkaantonov/bluebird) or kew (actually, an optimized subset of Q, at https://github.com/Medium/kew), among many more. You can find the standard "Promises/A+" documentation at https://promisesaplus.com. An alternative to promises could be async (https://github.com/caolan/async).

For server-side package management, use npm from https://www.npmjs.org. For client-side packages, either add browserify from http://browserify.org, or get bower from http://bower.io.

Working with CSS is simpler with Sass or {less}; note that the latter can be installed with npm.

Use testing frameworks, such as Intern, Jasmine or Mocha. Chai, Should.js (), Expect.js () and UnitJS are complete assertion libraries with different interfaces to suit your preferences. (UnitJS actually includes Should.js and Expect.js to give you more freedom in choosing your preferred assertion writing style.) PhantomJS and Zombie.js allow you to run your tests without using an actual browser, for higher speeds, while Selenium is preferred for actual acceptance tests.

Deploy your systems with Grunt or Gulp.

______________________