English |  Español |  Français |  Italiano |  Português |  Русский |  Shqip

Developing a Twitter Flight Edge

1. Git and Testing Basics

This chapter will focus on your development ecosystem more than the specifics of Flight. For users familiar with git, skip to the section on testing with Phantom.js and Jasmine. For users familiar with headless testing and the Jasmine testing framework, go on to Chapter 2 to get started with Flight. If you want to clone the demonstration repository, run the following:

git clone https://github.com/scottrabin/flight-rss-reader.git

Source Control - Git

By far, the most important aspect of development (and not just for the web) is source control. Being able to track incremental changes to individual files and rolling back your whole codebase to a previous point is invaluable in maintaining a stable product. Git is one of many varieties of source control. You may be familiar with tools like Subversion, Bazaar, Mercurial, or any number of other source control management systems. The core philosophy behind git focuses on branching and merging, where multiple developers can deviate from the main code line (almost universally the master branch) and merge their entire set of changes back into the main branch with the least amount of difficulty.

Branching

"Branching" in git terminology refers to forking off a known commit in one branch into a separate line of code with each set of incremental changes recorded against the forked commit. This allows multiple developers on a team to each have their own state of the codebase without interference from any of the other developers. Branches are officially made via git branch <branch-name>, but creating a new branch and then checking it out is so common that you can instead run git checkout -b <branch-name> to create and immediately check out a new branch. Git allows you to check out any branch and will modify your entire copy of the code base to conform to the state of the code base in that branch, which permits you to inspect other developers' branches.

Merging

The recommended basic git workflow starts with branching from the main code line and incrementally changing the code via a set of commits, which are individual patches to the code starting from the branched commit. Once you have completed your task, those changes will need to be merged into the main code line again; git trivializes this process by using an incredibly complex merge algorithm to apply your set of changes against the target branch to correctly make the same set of changes to the code in the target branch, even if that code has changed. This is the main advantage of using git over other source control systems; merging two branches of divergent code, which has historically been very difficult and error-prone, is trivial with git. Occasionally git will be unable to correctly merge branches and will notify you of a merge conflict, which you must manually resolve, but this is rare and occurs only when the same code has been modified in the two branches.

Workflow

Though the specifics may differ from team to team, most developers use the following workflow: create a new branch for each feature or bug fix, apply changes and commit to that branch to implement the feature or fix the bug, and create a pull request to the stable branch when your feature or bug fix is complete. A pull request is a request to apply a patch containing all of your changes to another target branch; it allows a repository maintainer or fellow team members to inspect your changes or try them out for themselves without affecting the state of the target branch. We won't be using pull requests for our own code, since there will be no review process, but we will be creating feature branches and merging them back into the master branch as we develop our application.

Testing: Phantom.js + Jasmine  

Flight uses this combination of driver and testing harness, so we will use it as well to become more familiar with the libraries and be able to quickly read and understand Flight unit tests. Consulting a library's unit tests is often an excellent way to determine if your usage of the library is incorrect or if the library has a bug. If you do discover a bug and patch it, submitting a unit test that fails without your changes is often an effective way to convince a library's maintainer to accept your patch.

Phantom.js

Phantom.js is a headless webkit driver, which means that our tests will run in the console without the need for an open browser window. By comparison, a testing framework like Selenium uses full browser windows and programmatically controls them. The benefit to Phantom.js over a full browser window is speed; by avoiding the overhead of drawing to a window, Phantom.js tests can run significantly faster than in Selenium. Unfortunately, only the webkit rendering engine can be tested, which makes Phantom.js more suited to testing code accuracy than for cross-browser regression testing. Still, for quickly testing our code, Phantom.js is an excellent choice of first-line testing.

Jasmine

Jasmine runs inside Phantom.js's headless environment as a test harness, providing functions to mock objects, describe behaviors, and assert results. It falls in the category of behavior driven development (BDD), where tests are written ahead of the implementation and describe expected behaviors of your program. This provides a clear goal for a single feature: write a failing test, verify it fails, and then keep writing and rewriting the implementation until it passes. Jasmine focuses more on object manipulation and behavior in expressing test cases, making it more suited to unit testing than end-to-end testing. For a single page application like ours where navigation won't cross page boundaries and no JavaScript server testing is necessary, Jasmine will work fine.

Module Loading - Require.js

Managing JavaScript dependencies between files without a module loader can be done manually, but a purpose-built library should be used for any reasonably-sized project. Flight makes use of the Asynchonous Module Definition (AMD) format for individual files, allowing runtime loading of dependencies and easing the task of building single file payloads for use in a production environment. Require.js is a common choice for AMD-compliant loaders, and has a separate optimizer to compile your files into one when deploying your application. Writing AMD -compliant modules is easy; just wrap your code in a call to define, list the dependencies, and the loader will take care of the rest.

0001:    define(
0002: ['lib/dependency1', 'lib/dependency2'],
0003: function(dep1, dep2) {
0004: // module initialization code here
0005: }
0006: );

Require.js also offers an alternate syntax, the Simplified CommonJS Wrapper, that we will be using in this book. Instead of declaring your dependencies as an array and maintaining the ordering between the array and function parameters, modules can use a synchronous version of require inside the function and Require.js will automatically compute the dependencies before invoking the function. Our modules will look like this:

0001:    define(function(require) {
0002: var dep1 = require('lib/dependency1');
0003: var dep2 = require('lib/dependency2');
0004: // module initialization code here
0005: });

Require.js has many more features useful to application development and dependency management; we will cover those features as they become relevant to developing our application with Flight. We will also not be covering the Require.js optimizer and minifying our application. The directory structure will be set up correctly for optimization, however, so if you want to explore the Require.js development path and create production-ready applications, you can do so with the application we develop in this book.

Setting Up Your Local Environment

Before we start developing our application, we will need to make sure our environment is ready. This means installing dependencies and configuring our project with the essentials: git, nodejs/npm, and bower.

Installing Git

Installing git will vary from system to system, and though installing from source is sometimes recommended, we will install via precompiled binaries.

Linux

Most Linux distributions come with a package manager for installing precompiled binaries. Users of Debian-based distros like Ubuntu or Mint can run the following:

apt-get install git

And Fedora/Red Hat users can run:

yum install git-core

Other package managers will have similar methods for installing the binaries, or you can install from source if you prefer.

Mac OSX

Mac users will have three easy options for installing git: Homebrew, MacPorts, or a graphical installer.

Via Homebrew:

brew install git

Via MacPorts:

port install git-core +doc +bash_completion +gitweb

Windows

Download and install msysGit, which will install git and a helpful shell utility you can use for the git commands in this book.

Installing Node.js & npm

These tools will be used for third party package management, and their installation varies from system to system. For Windows and Mac users, visit http://nodejs.org/download/ and download the installer for your system; for Linux users, download the source tarball and run the following commands  (replacing the file version with the version you download from nodejs.org):

0001:tar -zxf node-v0.10.3.tar.gz #Download this from nodejs.org
0002:cd node-v0.10.3
0003:./configure
0004:make && sudo make install

As fair warning, building Node.js from source can take quite some time, but it is the easiest and most robust method for installing Node.js on Linux systems. 

Installing bower

At this point, our ecosystem is nearly set up. Flight uses bower, a separate "component" manager, instead of npm. Fortunately, bower can be installed with npm! Just run:

npm install -g bower

And wait for npm to install bower for you.

Installing Phantom.js, Jasmine, and Flight

Now that our system has all of the executables we need, installing the libraries we use will be trivial. First, create a directory for our project, cd into it and run the following:

0001:git init
0002:npm init

This sets up our local git repository and creates a default npm package.json configuration file. Running npm init will ask a number of questions before generating the configuration file; the defaults should be appropriate in most cases. Next, run the following:

0001:npm install --save-dev phantomjs phantom-jasmine
0002:bower install --save flight

These commands will download and install Phantom.js and a helpful adapter for running tests. They will also save them to our package.json configuration file, and do the same for Flight in our new component.json file. Though bower does not distinguish between --save and --save-dev, there is a subtle difference for npm: --save will insert the module into the dependencies has, whereas --save-dev will put it in the development dependencies. Normal dependencies are always downloaded when running npm install to ensure the module can function correctly; development dependencies are only downloaded when running npm install -d and are restricted to modules needed only for development purposes.

Setting Up Our Application

Single page applications like ours are very easy to set up in terms of the HTML structure. Including additional modules into our application becomes trivial once the boilerplate is taken care of, so we'll get that out of the way now. Flight requires es5-shim.js, which attaches functions to native prototypes in place of potentially missing ECMAScript 5 functions (a practice called polyfilling) to make them available in older browsers. Additionally, jQuery needs to be included before Flight loads. We will also be using Twitter Bootstrap to simplify the styling of our application. Our application entry point, app/index.html:

0001:    <!DOCTYPE html>
0002: <html>
0003: <head>
0004: <title>Twitter Flight RSS Reader</title>
0005: <script type="text/javascript" src="components/es5-shim/es5-shim.js"&gt
0006:</script>
0007: <link rel="stylesheet" media="screen" href="css/bootstrap.min.css">
0008: <link rel="stylesheet" media="screen" href="css/bootstrap-responsive
0009:.min.css">
0010: </head>
0011: <body>
0012: <script type="text/javascript" src="components/jquery/jquery.js"></script>
0013: <script type="text/javascript" src="components/requirejs/require.js" data-main="js/main"></script>
0014: <script type="text/javascript">
0015: require.config({
0016: // We'll fill out the Require.js configuration
0017: // as we develop our application
0018: });
0019: </script>
0020: </body>
0021: </html>

With this very basic markup, we'll be able to start developing our application by adding the necessary markup. The general structure is also useful for our Jasmine application page; our dependency list is a bit larger for testing, so please look at the TestRunner.html file in the tests directory for implementation specifics.

Conclusion

In this chapter, we've covered the steps necessary for setting up a development environment for our application. Our source control management system, git, has been installed and is now ready to use, and the Node.js and Phantom.js runtimes have been installed for package management and testing. We have also set up our application repository with git init, installed Flight via bower, and installed our testing libraries. In the next chapter, we will briefly review the DOM Event Model and focus on the parts relevant to Flight. If you're already intimately familiar with DOM events, you can skip the next chapter and move directly to Chapter 3, starting our application.

There has been error in communication with Booktype server. Not sure right now where is the problem.

You should refresh this page.