Tuesday, July 9, 2013

Automated Testing of HTML5 Canvas Applications with Selenium WebDriver

This is the first in a series of articles about using automated testing tools on a Canvas-based Web application. Each article covers a different testing tool or technique.  (See the second on Geb.)

The specific application I'm testing is sized for a tablet, and uses a combination of a Canvas taking up roughly 2/3 of the space and a set of JQuery Mobile widgets taking up most of the remaining 1/3 of the space (there's also a small space on top showing a read-only "status bar" with key statistics). The basic concept is an editable diagram in the Canvas, with specific edit controls in the JQuery Mobile area. You can hover, drag, and click parts of the diagram in the Canvas, which can change what's displayed in the edit area, and changes you make in the edit area can add, remove, or change elements of the diagram in the canvas as well as updating the values shown in the status bar.

My goals for the automated testing are:
  • Make it easy to write tests
  • Run the tests in a real browser, to ensure I'm testing what a user would actually see
  • Make it easy to run a suite of tests and drill into specific test failures
  • Make the tests run fast enough that it's not terribly onerous to run before every commit
  • Be able to verify the visible state of the HTML showing on the screen (e.g. in the edit area, in the status area)
  • Be able to verify the underlying diagram model that dictates what is drawn to the Canvas. (I haven't attempted to go as far as testing the actual Canvas state -- as in the pixel color at some specific coordinate. The bugs I get aren't that the Canvas is drawing something that does not accurately represent its model state.)

Summary of Selenium WebDriver

Good: It has a model that I like -- you write tests, and when you run them, it launches a browser and runs through the tests, clicking on various things on the screen, waiting for screens to appear, etc. It supports multiple browsers (though with varying quality). You can evaluate JavaScript within the context of the page (e.g. "return mymodel.somevalue;") to get at the underlying state in addition to testing the visible component state.

Neutral: You write the tests in a programming language such as Java, C#, Ruby, or Python. (I used Java.)

Bad: All the examples show a test that runs from as a standalone application. You have some decisions if you want to run from within a unit testing framework -- do you restart the browser between tests (~10 seconds), reload the page (but it's not like a user does that for every action), or try to recover from an unknown page state if a test fails? The detailed event support is poor -- you can cause a mouse move to a specific location, for instance, but not a mouse down, mouse up, or click at specific coordinates. It's fine if all you do is click buttons, but terrible for a Canvas (there is a workaround). As far as I know there's no way to record WebDriver tests from the Selenium IDE or a tool like that.

Bottom Line: If you're willing to write a lot of setup code, you can record and execute tests easily. They run in a browser, 99% like a user would experience. I just hope to find some still higher-level tools that wrap WebDriver to record tests, run multiple tests and show results, etc. I also hope future releases resolve some of the differences in the browser-specific hookups that make tests work differently in different browsers.

Detailed Review

The basic model is that you write a test in code, compile (if needed), and execute the test. The test launches a real browser (Firefox, Safari, etc.) and interacts with it, simulating mouse movements, clicks, etc. This causes the page to function just as if a user was interacting with it. A test can also execute JavaScript within the context of the page, to retrieve information on the JavaScript state, to execute JavaScript functions defined for the page, or whatever.

Installing WebDriver:

Since I'm just writing Java code, all I had to do was put the dependency in my Maven POM:
<dependency>
    <groupid>org.seleniumhq.selenium</groupid>
    <artifactid>selenium-java</artifactid>
    <version>2.33.0</version>
</dependency>
For Chrome support, I also had to download the Chrome driver.

Learning Curve:

My first problem was with the event support. A perfectly suitable API is there for the tests to use:
new Actions(driver).moveToElement(canvas, xWithinCanvas, yWithinCanvas)
                   .click().perform();
However, this API is not reliable. In Firefox, every mouse down, mouse up, or mouse click happens at the center of the element. So the code above produces a mouse move event to the provided x,y, then a mouse move event to the center of the Canvas, then a mouse down, mouse up, and click all at the center of the Canvas. That may be fine for a button, but is unworkable for a Canvas, where you want to be able to hover, click, etc. at a specific location. The situation is even worse in Safari, where it just produces an exception indicating that mouse move events aren't supported. Chrome, meanwhile, works fine.

The workarounds are ugly -- manually dispatching synthesized mouse events using JavaScript:
driver.executeScript("var evt = $.Event('click', "+
                             "{pageX: "+x+", pageY: "+(y+55)+"} );"+
                     "$('#diagramCanvas').trigger(evt);");
Here I'm manually creating a mouse event with pageX and pageY using offsets I happen to know from the provided mouse coordinates. Yuck!

For Firefox for my purposes, things were a little smoother. My Canvas event processing is to record the subcomponent of the diagram that the mouse is over on a mouse move, and do something with the selected subcomponent on a click, so I don't actually use the mouse coordinates on a click event. Since the move event works OK in Firefox, something like this works for me:
new Actions(driver).moveToElement(canvas, xWithinCanvas, yWithinCanvas)
                   .perform();
driver.executeScript("$('#diagramCanvas').click();");
I also ran into some other differences between browsers. In Firefox I could click a widget that closed a JQuery Mobile dialog and immediate click on the diagram. In Chrome, the same occasionally failed unless I introduced a slight delay to allow the dialog to get out of the way.

Writing Tests:

Once I got past that, I started writing tests. Writing one little test was fine, and it was exciting to see it run in the browser. But I quickly determined that it was going to be incredibly obnoxious to write any substantial quantity of tests by hand. Too much code, and languages like Java and Ruby don't describe a user's interaction with HTML very well.

When I ended up doing was:
  1. Write a helper class with methods like waitForFooPage(), clickToolbarButtonFoo(), replaceTextIn(id, text), clickElement(id), clickCheckbox(id), confirmModelState(x, y, z), and so on. All the WebDriver API calls are hidden in the helper class.
  2. Write an additional JavaScript "QA" file that added a bunch of event listeners to emit (via console.log) calls to the helper class -- for instance a click on an a emits a clickElement(id) and a change on an input generates a clickCheckbox(id) or replaceTextIn(id, text) and a JQuery Mobile pageShow generates a waitForFooPage() and so on. Then it adds a listener to the very bottom left-hand corner of the canvas (otherwise unused) to toggle the recording state.
So when that file is included in the page, I can basically record a script, though I still have to copy and paste it into a test file to use. Still much better than writing tests by hand. My recorder has some basic page state validation in there (for instance for screens where the links have different content depending on the current state when you load it -- like a category browse type page). But I still have to write any detailed validation by hand.

The QA JavaScript has a little custom logic but basically ends up looking like this, emitting test code to the console as you interact with the app:
$('#diagramCanvas').click(function(e) {
    if(e.pageX >= 0 && e.pageX <= 10 &&
                e.pageY >= 55+590 && e.pageY <= 55+600) {
        QA.recording = !QA.recording;
        console.log("Recording: "+(QA.recording ? "on" : "off"));
    } else if(QA.recording) {
        console.log('helper.clickOnDiagram('+
                        e.pageX+','+(e.pageY-55)+');');
        QA.lastClickToolbar = false;
    }
});
$('a').on('click', function() {
    if(QA.recording && $(this).attr('id')) {
        var id = $(this).attr('id');
        console.log('helper.clickOnElement(\"'+id+"\");");
        QA.lastClickToolbar = false;
    }
});
$('body').on('change', 'input', function() {
    if(QA.recording) {
        var type = $(this).attr('type');
        if(type === 'checkbox' || type === 'radio')
            console.log('helper.clickOnCheckbox(\"'+
                        $(this).attr('id')+"\");");
        else if(type === 'text' || type === 'number')
            console.log('helper.replaceTextIn(\"'+
                        $(this).attr('id')+"\",\""+
                        $(this).val()+"\");");
    }
});
$('#page1').on('pageshow', function() {
    if(QA.recording && !QA.lastClickToolbar)
        console.log('helper.waitForPageOne();');
});
$('#page2').on('pageshow', function() {
    if(QA.recording && !QA.lastClickToolbar)
        console.log('cw.waitForPageTwo();');
});
And the helper class that it emits commands for looks something like this:
private JavascriptExecutor js;
private WebElement canvas;
private WebElement page1;
private WebElement page2;
private Actions ui;

public TestHelper(WebDriver driver) {
    js = (JavascriptExecutor)driver;
    canvas = driver.findElement(By.id("diagramCanvas"));
    page1 = driver.findElement(By.id("page1"));
    page2 = driver.findElement(By.id("page2"));
    ui = new Actions(driver);
}

public void clickOnDiagram(int x, int y) {
    ui.moveToElement(canvas, x, y).perform();
    clickOnCanvas(x, y);
}
private void clickOnCanvas(int x, int y) {
//    js.executeScript("$('#upperSchematic').click();");
    js.executeScript("var evt = $.Event('click', { pageX: "+
                     x+", pageY: "+(y+55)+" } );\n" +
            "$('#diagramCanvas').trigger(evt);");
}
public void waitForPageOne() {
    waitForPage(page1);
}
public void waitForPageTwo() {
    waitForPage(page2);
}
private void waitForPage(WebElement page) {
    wait.until(ExpectedConditions.visibilityOf(page));
}
public void clickOnCheckbox(String id) {
    // In JQuery Mobile you need to click on the label
    WebElement element = (WebElement)js.executeScript(
                         "return $(\"label[for='"+id+"']\")[0];");
    ui.click(element).perform();
}
public void clickOnElement(String id) {
    WebElement element = page.findElement(By.id(id));
    if(!element.isDisplayed())
        throw new RuntimeException(
            "Cannot click on '#"+id+"' because it is not displayed!");
    if(!element.isEnabled())
        throw new RuntimeException(
            "Cannot click on '#"+id+"' because it is not enabled!");
    ui.click(element).perform();
}
public void replaceTextIn(String id, String text) {
    WebElement element = page.findElement(By.id(id));
    String old = (String) js.executeScript(
                                   "return $('#"+id+"').val();");
    ui.click(element);
    for(int i=0; i<old.length(); i++) {
        ui.sendKeys(Keys.BACK_SPACE);
        ui.sendKeys(Keys.DELETE);
    }
    ui.sendKeys(text);
    ui.sendKeys(Keys.TAB);
    ui.perform();
}
A little copy and paste and I end up with a test method that looks like this:
helper.mainMenu();
helper.clickOnElement("MainMenuNew");
helper.wait(100);
helper.clickOnDiagram(393, 412);
helper.waitForPageXYZ();
helper.replaceTextIn("SomeTextFieldID", "MyNewText");
helper.clickOnElement("SomeEditWidgetID");
confirm(helper.getElementText("SomeSpanID").startsWith("MyNewText"));
...

Running Tests:

I wasn't too interested in writing a dozen tests as command-line executables and running them one after the other. I wanted to run one command and have it run all the tests, counting successes and failures, logging stack traces for any failures, and so on. I really wanted a little GUI to show red and green bars and so on, but it wasn't worth the time to recreate that. I ended up writing a little wrapper to run and capture the results of all my individual tests, but it didn't seem like something I should have to be doing.

The bottom line is that I can issue a command, watch a browser flash through interactions with my app, and get a list of failures and stack traces at the end. When I want to write a new test I include my extra JavaScript file, click the obscure corner of the Canvas to turn on recording, and then interact with my app as usual. At the end, I copy and paste the script from the Web Console into a new source file and add any additional validation I want. Then I can comment out the QA JavaScript and run more tests.

It's what I wanted, but less flashy, and I had to write a lot of setup code to get there.

Here's the code from the master class that runs the tests:
public static void main(String[] args) throws InterruptedException {
    FirefoxProfile profile = new FirefoxProfile();
    profile.setEnableNativeEvents(true);
    DesiredCapabilities capabilities = new DesiredCapabilities();
    capabilities.setCapability("nativeEvents", true);
//    WebDriver driver = new SafariDriver(capabilities);
//    WebDriver driver = new ChromeDriver(capabilities);
    WebDriver driver = new FirefoxDriver(profile);
    driver.manage().window().setSize(new Dimension(1040, 850));
    driver.get("http://localhost:9393/");
    TestHelper helper = new TestHelper(driver);
    helper.waitForDefaultPage();
    List<Throwable> exceptions = new ArrayList<Throwable>();
    // NOT SHOWN: Introspect the test class and run the test methods
    if(exceptions.size() == 0)
        System.out.println("All tests passed!");
    else
        for (Throwable exception : exceptions) {
            exception.printStackTrace();
        }
    driver.quit();
}

Areas for Further Investigation:

The next thing I'd like to try is Geb as a wrapper for WebDriver (Update: see results here.)

It looks like a standard pattern for wrapping all the interesting application actions and state is PageObjects. My gut reaction is that it would have been way too much work to do that for all the "pages" in my application, but it's a much more organized approach and better than just scattering various IDs and coordinates through a bunch of individual tests. I feel like the approach has merit, I just can't put my finger on the line where the provided value overcomes the necessary work. Probably if you're writing all the tests by hand, but I'm not willing to go there anyway.

Monday, June 17, 2013

Announcing: Android Training at Chariot Solutions

We are pleased to announce Android developer training at Chariot Solutions, starting July 22, 2013.

The course curriculum covers the gamut from user interface design, to access of sensors and features of your devices, and to network access and local storage.  We use courseware designed for phones and tablets, including modern fragment-based layout design.

Several dates are available on the Android Training course page.

Here is a condensed course outline:

Chapter 1. The Android Operating System 

Mobile Form Factors * Versions of Android * Applications and APK Files * Process Architecture * The Role of Java * Hello, Dalvik * What's In, What's Out * Services * User Interface * Memory and Storage * Operating-System Services * Inter-Process Communication

Chapter 2. Android Development 

The Android SDK * The SDK and AVD Managers * Configuring the Emulator * Eclipse * Resources * APK Files * Build Process * The R Class * Assets * The Dalvik Debug Monitor Server * The Android Debugger (adb) * Command Shells * The Android Log and LogCat * Ant

Chapter 3. Applications 

Activities and Fragments * Activity Lifecycle * The onCreate Method * Layouts and Views * The findViewById Method * Tasks and the "Back Stack" * Intents and Results * startActivity and Related Methods * Custom Application Classes * Shared Application State

Chapter 4. User Interface Design

XML Layouts * Layout Parameters * The Box Model * Gravity * The LayoutInflater Service * The <LinearLayout> * The <RelativeLayout> * Views and Adapters * Form Widgets

Chapter 5. Fragments and Multi-Form Design 

The Fragments API * Fragment Lifecycle * Relationship Between Activity and Fragment * Possible Cardinalities * Communication between Activity and Fragment * Fragment Arguments * Callback Interfaces * Designing for Multiple Form Factors * Fragments on the Back Stack

Chapter 6. Working with Lists

AdapterView and Subclasses * Adapter and Subinterfaces * ListView and ListAdapter * ListFragment * Spinner and SpinnerAdapter * Handling Item Selection * Custom Adapters * ExpandableListView and ExpandableListAdapter

Chapter 7. Menus and the Action Bar

Options and Context Menus * The Action Bar * Menu Resources * The MenuInflater Service * The <Menu> * The Menu and MenuItem Classes * Handling Menu Selections * The Escape from switch/case! * Using a Dispatch Map * Building Menus Dynamically

Chapter 8. Local Storage

The Android File System * Internal Storage * File Formats * Parsing JSON * Storage and the Application Lifecycle * External Storage * Private Storage vs. Public Media * Permissions * Checking for Availability

Chapter 9. Networking and Web Services

java.net * android.net * Apache HttpClient * Consuming RESTful Web Services * Building URLs * Parsing JSON * Parsing XML * Connected Applications * Offline Operation and Server Synchronization

Chapter 10. Asynchronous Tasks

The UI Thread * Background Tasks * Loopers and Handlers * Using AsyncTask * Using ProgressDialog * Error Handling

Chapter 11. Multimedia 

Playing Sounds * Haptic Feedback (Vibrating) * Managing Images * Storage and Retrieval * Invoking the Camera * Invoking the Media Recorder * Gallery and other Image Views

Chapter 12. Location Services and Maps 

Location Services * Location Notifications * The Google Maps API * License Terms and Maps API Keys * Map View and Map Activity Classes * Configuring a Map * Controlling a Map * Events * Projections * Map Overlays * Item Overlays * Custom Overlays

Tuesday, May 7, 2013

AngularJS Directives - building a DSL with your HTML

I will admit in advance - this content trades off of a great little screencast by Brian Ford from CODEShow on AngularJS directives. Go watch that if you have a little knowledge of AngularJS and 45 minutes to kill... But if not...

What is AngularJS?

Google built AngularJS, a Javascript MVC (well, MV VM, more later) to write single-page web applications. It provides an application framework, which lets you define view templates for your HTML content, register MVC controllers (for handling activities, listening for events and initializing views), build services (stateful or stateless Javascript code for handling integration to outside data sources and sinks), and several other components, including directives.
As I mentioned before, we'll get to directives in a bit. But first, the 5 minute AngularJS sample.

AngularJS in a nutshell

AngularJS provides a bridge between your HTML and Javascript via a nice two-way data-binding mechanism. Angular uses a view model object, which can be set within your controllers, to send data to a page. A one-way example:
To play with this, just click on the various headings (Javascript, HTML, Result). I'm using JSFiddle, an incredibly useful playground where you can quickly cook up snippets of whatever you wish and share them online, even associate them with your GitHub account.

Breakdown - the Module

you can see that we've defined an module named 'demo' (ignore those square brackets for now):
var demo = angular.module('demo', []);
This module defines an application for us. We can eventually register a number of elements in this application, but for now, we'll just set up the application itself so it can be bound to a portion of our page.

The Controller and 'ViewModel'

We then defined a controller called 'MyCtrl':
function MyCtrl($scope) {
...
}
which will automatically inject the magically named 'scope' variable - $scope. Just like Spring or other dependency injection systems, provided you know the service you're injecting, you specify it by name. Built-in and add-on services from Angular generally use the '$' prefix. Yours will not. That's a way of distinguishing user code from system-built code.
The '$scope' variable is a ViewModel - meaning a model specific to display of a template or view. To demystify the whole 'MVVM' term you may have heard, consider the ViewModel is simply the model that is given to the view, so that you can decouple it from your application's internal model, some of which you may not want to share with the page at a given time. Those darn terms...

The View

Now we come to the view. In our case, we've decided to make this view static - meaning that it's embedded into the page. We can certainly set up external views in another post, but for now, let's just focus on the content. You'll notice in the HTML we've defined two special tag attributes that you won't recognize, 'ng-app' and 'ng-controller'.

Greeting

Hi, it's Ken. The current time is {{time}}.
The ng-controller attribute is easy - it tells the page to watch for any data exported from our controller, named MyCtrl, and inject data stored in the $scope variable by its name. You'll notice above we left out our controller implementation. Let's look at it now:
function MyCtrl ($scope) {
    $scope.time = new Date().toTimeString();
}
Now, you can see the linkage - the $scope.time variable becomes {{time}} in the page. But what about the ng-app attribute?

The ng-app attribute defines what the scope of a given application might be on a given page. Like the controller, this limits the exposure of the application to a given area of the page. An application may be composed of elements such as controllers, services, views, directives, etc., and you may have need of Angular on several completely unrelated places on a given page. That's OK, you can create two applications, or an outer application and two related inner applications, all by defining modules. Further, once you start building components you'll likely want to set up more than one controller on a given view page, rather than one monolithic controller and view.

A sample directive

Ok, so let's bring it home. Maybe we want to think of the time as a 'feature' - something we'd use on the page in a few places. What if we wanted it to be referred to by a 'display-current-time' HTML tag? Something like this:
Hi, it's Ken. The current time is
to define a tag like that, you use a directive - a Javascript component that provides an HTML tag, attribute or CSS class with YOUR defined name, that then behaves like a DSL language element in the page.

Defining a directive

Let's begin with what we want our HTML to look like. This is a completely trivial and silly example, but it gives you an idea of what you can do.

Greeting

Hi, it's {{name}}. The current time is .
I didn't want to remove the controller, so I used it to bind the name to 'Ken'. Here's the controller now:
function MyCtrl ($scope) {
    $scope.name = 'Ken';       
}
Ok, our manager is going to freak out. Maybe later we'll externalize this into a form field, and show you that nifty two-way binding.

The directive

Now for the directive. We'll add it to the javascript sample file, and since we've defined our application (demo) above, we simply add the directive to it.
demo.directive('displayCurrentTime', function() {
    return {
        restrict: 'E',
        template: '12:00:03'
    };
});
The directive is given a camel-cased name - displayCurrentTime and in the inimitable Javascript way, we provide the implementation as an inlined anonymous function. The directive must return at least a template to render, and optionally a narrowed-down 'restrict' variable which tells Angular to activate the directive for HTML tags/elements (E), HTML tag attributes (A), or CSS classes 'C'. In the example above, we're going to only activate it for tags.
Angular expects that camel-cased name to turn into a lower-cased, dash-separated name in the HTML. Hence why our tags above are called 'display-current-time'.

Getting dynamic

Now let's get a bit more code-driven and dynamically generate the time.
demo.directive('displayTime', function($parse) {
    return {
        restrict: 'E',
        replace: true,
        transclude: false,
        template: '',
        link: function (scope, element, attrs, controller) {
            var currentDate = new Date();
            element.text(currentDate.toTimeString());
        }
    }});
One key function of a directive is to link the content in the model to DOM elements on the page. We supply a link function definition, and AngularJS injects the element as the second parameter. We then create a Javascript date with an empty constructor (current time) and use the element's text method to send it to the content of the span itself. In more advanced cases, we can supply a compile method, which is more powerful, but for simple cases like this the link method will suffice. Play with this snippet: By the way, if you begin trying to troubleshoot issues with your AngularJS or other framework app, some developers insist you reproduce the core problem in a tool like JSFiddle. It's a good way to play with a sandbox with zero setup.

Marco... Polo!

Let's take this one step further, and implement another directive to provide a business-level component. Perhaps you need to provide a list of user roles in a drop-down element, and you want to notify the rest of the application when you've changed the current one. In AngularJS, a typical way to do this is via a controller and view:

Play around with the values, and open Firebug or your Chrome developer tools (sorry IE users, I'm sure there's a way but I've been a mac user for too long). You'll see the console writing the change as we make it. Note the name of the attributes all begin with ng-. That's short for Angular. These are built-in attributes of the various supported widgets. Read up on the various ngXXX API attributes/elements to learn how to control text boxes, buttons, text areas, and other objects.

The DSL for groups

Let's say you want to set up a widget for group selection, with its own styling and form elements. You might start by coding it directly using a controller/view combination. First, we're using a simple form, with some AngularJS decoration here. From the HTML:
    <form class="userGroup">
        <label for="userGroupSelect">Select a Group</label>
        <select 
            ng-model="currentGroup"
            ng-options="o.value as o.label for o in myGroups"></select>        
        <input type="button" ng-click="applyNewGroup(currentGroup)" value="Switch Group"/>
    </form> 
Now, we'll bring in the AngularJS controller. We'll break this down step-by-step. First, we provide the application and a controller:
var demo = angular.module('demo', []);

function MyCtrl ($scope, $rootScope) {
    $scope.myGroups = [
        {label:'Admin', value:1},
        {label:'Users', value:2},
        {label:'Public', value:3}
    ];
    ...
}
The group list is arbitrary here - we could easily use Angular's $http component or even a RESTful resource to fetch the values. Note that the myGroups scope variable lines up with the curious expression in the ng-options attribute of our select tag. Let's explain that:
o.value as o.label for o in myGroups
What? Ok, this is almost like a select statement. It's one of the things in Angular you have to read through a few times to get it right. This expression assumes we are passing it an array of JS objects (myGroups) and that we're providing both a display and an option for the option tag it generates. Reading the fragments from the right, we first assign an alias 'o' to myGroups (o in myGroups). Then, we provide an optional label in the middle (o.label), and the data value (o.value). Hence, 'o.value as o.label for o in myGroups'. Easy, peasy? Well, nope but it does work. See the select directive and the cries for better documentation in the comments to make sure you're not the only crazy one.

Handling the change event

Rather than immediately changing the group for our application, we want to do it once the user clicks the button. So in that way, our currentGroup model element is transient. To do that, we'll define a function that takes the immediately bound model element currentGroup and broadcasts it to the rest of the application:
$scope.applyNewGroup = function (currentGroup) {
    $rootScope.$broadcast("new group", currentGroup);
};

// this could be anywhere in our application...
$scope.$on("new group", function(obj, value) {
    console.log("Global group switched to " + JSON.stringify(value));
});
You may not have noticed but in our controller, we not only requested $scope, but $rootScope. The root scope is a scope that all controllers in our application can see. If we wanted our controllers to be notified when the user changes groups, we simply call the root scope's $broadcast method, passing it a message and optionally, data to send. We've done that by passing the group id along. To subscribe to a message, in any sub-scope of the application (any controller), we just use the local scope's $on method. The scope is passed the object generating the event and the value passed. Since the value is our group, we accept it.

Put it all together

Now we'll put in the magic sauce. Let's externalize the form into a template string (yes, this can be an URL instead and loaded as a view file) and use the directive function to set it up:
demo.directive('userGroupSwitcher', function() {
    return {
        restrict: 'E',
        replace: true,
        transclude: false,
        template: '<form class="userGroup">
         <label for="userGroupSelect">Select a Group</label>
         <select ng-model="currentGroup" 
           ng-options="o.value as o.label for o in myGroups" />
         <input type="button" 
            ng-click="applyNewGroup(currentGroup)" 
            value="Switch Group"/>
         </form>'
    };
});
Then, to place the tag on the screen, we use:
    <user-group-switcher />
Play around with it here:

Summary

AngularJS is a powerful client-side Javascript application platform. You can use as little or as much of it as you wish. There are tons of samples online about building Angular web applications with simple controllers and forms, but I wanted to show you how to write directives - a way of liberating your domain-specific features from DOM elements, and allowing you to assemble views using business-specific building blocks. You can use directives for anything from menus, to re-use of forms, to wrapping other JS component libraries and widgets, to anything you can think of. Combining directives with Angular's message passing, easy REST/Ajax support, two-way data binding, support for templates and dependency injection, it's hard to pick a better framework (in my opinion) that can get you started quicker or provide you more flexibility without forcing you to build your own skeleton.

Resources

For finding more AngularJS component libraries based on directives, see ngmodules.org. A few of my favorites: Angular Bootstrap, for wrapping / encapsulating Twitter bootstrap features using directive tags and attributes, Angular UI, a set of widgets based on jQuery UI, and one I'm hacking with right now, jQuery Mobile Angular Adapter which tries to settle the score between Angular's dynamic views and jQuery Mobile's jump-link based dialog switching. For hacking around with Angular, please DO use JS Fiddle and search around for some good ones to start from. Feel free to fork any of mine to get going. In my next article, I'll show you more of the inner workings of Angular directives. If you want to learn that beforehand, go to the above-mentioned projects' github pages and start reading. Marco!

Thursday, April 25, 2013

Setting Realistic Expectations For Mobile App Development

This article was originally seen in the May issue of SmartCEO. It was written by Mike Rappaport, CEO of Chariot Solutions.

One common misconception about mobile application development is that it's much easier and less expensive than traditional software creation.  We've all heard stories about an app that was developed overnight, released in the app store, with the app quickly becoming a big success. This is usually not the case.  In reality, developing a mobile solution is sometimes more costly and difficult to implement for most businesses.

Since mobile applications are delivered on smaller screens and tend to have a more focused purpose, the thought is that they should be less expensive to develop than traditional applications. So why isn't that the case?

The main reason is that mobile application development still needs to adhere to the same processes as traditional software development. All software development should include planning, requirements definition, design, development, testing, delivery and support.  Along with an effective development process, delivering a quality solution requires having the right people in the right roles.

Since mobile applications have a more focused purpose than traditional applications, it is even more important that business, creative and development resources work together to clearly define and deliver a successful application.

Moreover, mobile development faces additional challenges that most traditional applications may not experience.  The most significant challenges include: variety of devices, user interface paradigm shifts, network connectivity, testing and distribution.

Mobile devices come in a variety of sizes, shapes, and platforms.  The type of devices to be supported will have a direct impact on the cost of development.  The major platforms are iOS (iPhone and iPad) and Android. But what if the user base includes Windows Phone or BlackBerry? What about tablets versus phones? Even within tablets or phones, device sizes can vary from a design, development and testing perspective.

User interfaces on mobile devices rely on the user touching a small screen with their finger or thumb.  This is a very different experience from traditional applications.  This not only forces designers to rethink how users interact with applications, but it requires a design that is intuitive.  These designs also need to adapt to varying screen sizes and take into account the size of a finger as opposed to the point of a cursor.  A poorly designed (yet typical) web form in a traditional application might include 15 or more fields with descriptions on what acceptable values might be.

How does that fit on a 3.5 inch screen?  Challenges like this require more creative solutions, which subsequently have a direct impact on cost.

Imagine entering 15 fiels of data using thumbs, only to find that the network suddenly became unavailable during the submission.  How does the application handle that? As with traditional applications, data integrity and security are a major concern on mobile devices. However, network availability is much more variable on mobile devices.  Also, data can be more vulnerable on mobile devices, simply due to the fact that devices are mobile. Accessing and handling mobile data introduces additional complexity into the design and implementation of mobile applications.

As features are developed, testing of mobile applications becomes even more important.  How a touch-based application looks, feels and reacts can vary significantly from device to device.  It is critical to get the applications deployed onto devices and in the hands of users early and often.  Depending on the size of the application, this can lead to longer testing cycles.

Finally, once development is complete, it must be distributed.  This process varies from platform to platform.  There may be additional effort required to prepare the application for submission to an App Store. The time for submission and potential rejection need to be accounted for when planning the project.

The bottom line is that developing mobile applications is much like developing software for other platforms, with some additional complexities.  But the recipe for success is the same: It takes the right people and an effective process to be successful.  When all of this is done properly, it has been proven that mobile applications have the ability to dramatically improve, and in some cases transform businesses.  Business leaders need to understand that though the cost of mobile application development may be high, the ROI can be much higher.

Tuesday, April 9, 2013

The Pivotal Initiative - the future of Spring and open source at VMware/EMC



EMC and VMware have poured their open source software development workforce into a new wholly-owned subsidiary, dubbed "The Pivotal Initiative". This organization will focus on data science consulting and tooling from GreenPlum, including SpringSource/vFabric development teams.

It is being girded by a team of forward-looking developers at Pivotal, a recent EMC purchase and well known for their work with Ruby tools and testing software.

Until now, Pivotal has not yet discussed their strategy for the SpringSource teams. Adrian Colyer, one of SpringSource's spiritual leaders, here outlays what the future will hold, including support for Java 8 Lambdas (closures) in Spring 4, Groovy, Grails, and Cloud Foundry. 

Monday, March 18, 2013

Training Courses on Tap for Spring 2013

It's that time again. Flowers are sprouting, pollen is flowing, and, lo and behold, Chariot is running more training...

We have some exciting additions to our courses this quarter, including a guest course by Neosoft, our usual Spring training courses, a Groovy and Grails offering, and more. Here's our lineup:

  • March 26-28 - Comprehensive Maven 3 and Nexus training - We are running a 3 day maven intro, intermediate and advanced course starting on March 26. You'll learn how to build Java application with Maven, including JARs, WARs, and multi-module projects.
  • April 9-12 - Core Spring Developer Training/Certification - Recently updated, this course covers Spring 3.1 and above, all three styles of dependency injection (XML, annotations, JavaConfig), JDBC, Hibernate/JPA, an introduction to Spring Web MVC, Security, JMX and more. A deep discussion of the Spring lifecycle and features such as proxying, interface-driven development, JUnit-based testing and Aspect Oriented Programming provides a strong foundation for new Spring developers.
  • April 17-19 - Neo4j Tutorial by Neo Technology - We are featuring a guest training course by NeoSoft, discussing their NoSQL Graph database, Neo4J. This is a two-day course to get developers up to speed in using Neo4J.
  • April 30-May 3 - Groovy and Grails v2.0 - new for Chariot training, we're featuring a four-day Groovy and Grails training course, written by the developers of Grails at VMware. This course begins with a heavy introduction to the Groovy programming language, and then dives into Grails, the convention-driven Spring-and-Hibernate application framework. Configuration, controllers, services, scaffolding, testing, writing plugins, and GSP tags are covered.
  • May 9-10 - Advanced Scala - This Typesafe course, taught by Michael Pigg, takes our Scala training even further than Fast Track to Scala, and includes a deep dive into functional programming concepts, internal DSLs, custom Scala collections, and details on the Scala type system.
As usual, we offer discounts for Chariot training alumni. Contact us for information on obtaining a discount code - please provide your name, course, and estimated training date. We also provide private training and can offer courses in Hadoop, Java, Tomcat, and other technologies. Check our course catalog for more information.

Friday, March 15, 2013

Recap - Chariot Day 2013 - Our internal conference...

One thing Chariot people love to do is learn new technologies and techniques. Being consultants constantly challenged in the field, keeping our blades sharp is key to doing battle. Every year or so we get together and run our own internal conference to see what each of our current passions are. We call it Chariot Day.

Earlier this month, on a Saturday, we had two rooms going from 9-5PM, each with 45-minute sessions on subjects such as:
  • Becoming a better programmer, Mythbusters Style
  • Async networking for Android w/Robospice
  • A great session on zsh
  • Data Mining - it's not just for kids
  • Universal EventBus with Vert.x
  • Functional programming with Scala
  • Single-page Javascript with AngularJS
  • Billions of Things (you can imagine scalability and performance on a large scale)
  • Having fun with the Raspberry Pi
  • HTML5 Canvas
  • Understanding the Persistent Data Structures of Clojure
  • Get low w/HBase
  • Getting started with Phone Gap
  • 20 tools that turbo charge a 1.51 person development team
We will be reviewing the content from these sessions to see if we can share them with you.