Friday, February 21, 2014

Client-side MVC with JavaScript

Continuing the JavaScript theme from my previous two posts, there was one more JavaScript idea I wanted to investigate. I have to admit, I have been confused by what I've seen in the MVC space recently. It did not match up with what I thought of when I thought of MVC. Now, I'm not a web developer, this is not a topic that concerns me on a regular basis, but I feel like any self-respecting developer should have an understanding of these sorts of things.

Reading the Model-view-controller Wikipedia article actually made a light bulb go on in my head. See, I was stuck in the past and was thinking of all three components living on the server, but as client-side technologies have matured (read AJAX) the components have shifted to the client. This makes a lot of sense as MVC does not prescribe the exact implementation, rather MVC is a design pattern.


Whether it's client-side or server-side, you still have a controller that manipulates the model and a model that updates the view. With client-side MVC all three components would be written in JavaScript. With server-side MVC the model is a JavaBean, the view is a JSP, and the controller is a servlet. The latter is how I originally learned MVC and it is shown in the image below:


So what I decided to do was create a pure JavaScript MVC example whose model talks to the Node.js app from my last blog. There appear to be many existing frameworks for this, but they all looked way overkill for such a simple example.

The HTML


It simply has a few forms to trigger the different CRUD operations.

The JavaScript


I think it seems strange I need to refer to so many HTML elements in my controller. I could initialize the controller with the IDs it needs. That would be better, the controller would be less coupled. I still wonder if I separated my components correctly though. Is there a better way?

It's Alive

I ran everything on my laptop and dropped these files into a "public" directory at the same location as my my Node.js app. They are served as static files and this conveniently eliminates cross domain AJAX issues since both are at localhost.

The result of clicking "List All Wines":



Testing (in theory)

In my first blog I talked about how to get started testing JavaScript, so naturally I wanted to see if those principles could be applied here. It seems like the model and the view (with minor refactoring) would be easily testable. The AJAX requests to my Node.js app could be mocked as I demonstrated. I would say those components turned out really well. The controller would require more effort. I would have to pass the controller a mock view and mock model, but it's definitely possible. I think this conclusion gives merit to the design even though this was a simple example. I like the way it separated the unrelated parts of my code.

Tuesday, February 18, 2014

Node.js CRUD API

I have been wanting to check out Node for quite a while now. I am used to the more common OS thread-based concurrency model that we see in Java application servers. Node is instead based on an event-driven, non-blocking I/O model where all connections are handled in one thread.1 As long as the processing for each request is not CPU-intensive, it can handle thousands of concurrent requests.2

Another more obvious advantage of Node is that your application is written in Javascript. Anyone who has ever written client-side Javascript can immediately begin writing server-side code. You could also, for example, use the same input validation code in your client and server.3

Setup

Never having written a Node app before, I based my first one largely off this great blog Creating a REST API using Node.js, Express, and MongoDB by Christophe Coenraets. I hope to explore MongoDB more in another post. For now I will ignore it and just say that it is simple to install and Chritophe's code to talk to it works as is.

I ran my app on Windows and I did get tripped up on installing the Node MongoDB driver with npm. I had to follow these steps and run "set npm_config_arch=x86" before running "npm mongodb".

The Code

The server is pretty straightforward. Map each of your routes to a function that handles the request and listen on a specific port.


I updated the functions that talk to MongoDB to (I think) be more RESTful.4 The non-GET requests will respond with more meaningful HTTP response codes instead of JSON.


Node is able to handle multiple connections in one thread because of the use of callbacks. Any time you do something in your app that may take a long time you, tell Node what to do and provide a function to call when it is finished. It can handle other requests while the long running operation (like reading a file) is completing.

Testing

Bringing in a testing framework would probably be overkill for this simple app, so cURL will suffice. I got it for Windows here. An example for each of the routes:

curl -i -X GET http://localhost:3000/wines
curl -i -X GET http://localhost:3000/wines/<id>
curl -i -X DELETE http://localhost:3000/wines/<id>
curl -i -X POST -H "Content-Type: application/json" -d @new-wine.json http://localhost:3000/wines
curl -i -X PUT -H "Content-Type: application/json" -d @new-wine.json http://localhost:3000/wines/<id>



Tuesday, February 4, 2014

Unit Testing Client-Side JavaScript

I'm far from a JavaScript expert, but I've done some web development using JavaScript before and one thing I have always wondered about was how to write automated unit tests. Of course you'll probably still want to do manual testing and functional testing with something like Selenium. It seems like unit tests would greatly improve the development experience though. The thing is, I had no idea what a JavaScript unit test would look like, so I chose to investigate it as the subject for my first blog.

The advantages of unit testing JavaScript are the same as unit testing in other programming languages: looking for regressions is easier. It also promotes better code design because you can either refactor with confidence or are doing TDD and writing testable code from the start. And because our execution environment is the browser, unit tests make it incredibly easier to do cross-browser testing.

The basic requirements for being able to write unit tests are that your JavaScript is in separate files from your HTML and that you write granular, parameterized functions. Then you can call these functions from a test HTML file and run the tests by opening the HTML file in a browser. 

I'll quickly mention that I came across PhantomJS for running headless tests and an intriguing project called Karma for hooking your tests into your continuous integration process. I'm sure there are dozens of other great JavaScript frameworks too. Again, for this post I want to keep it simple and just go though some baisc examples of how to get started writing unit tests.

Getting Started With The Code

This is the test HTML file. Originally I wanted to do this with pure JavaScript, but it quickly became apparent that it would be easier to use an existing testing framework and not try to reinvent the wheel. I chose QUnit. Many of their examples use jQuery so I will pull that in too. It also seems like the subject of mocking would come up pretty quickly testing a site with AJAX calls and I would like to see how that work. I will use jQuery Mockjax for a mocking example. The purpose of this post is not to learn about or endorse any specific frameworks though. The examples below should be understandable without having used any of the frameworks before. I chose these three because they are light-weight and seem to be easy to get started with.

I include the js files for jQuery, QUnit, Mockjax (and json2 which it needs), and testable_js (my JavaScript code that I am trying to test). QUnit also needs a CSS file for displaying the results. Your JavaScript should only rely on the #qunit-fixture element. QUnit will reset elements inside the #qunit-fixture element after each test so that all tests can be atomic.

The JavaScript that I am testing is largely based on the QUnit Cookbook and this tutorial. I have some basic functions, a function that makes a HTTP request to Flickr, a function that makes a HTTP request to a not-yet-implemented page, a couple functions that modify the DOM, and a key logger function.

To test these I need to be able to test synchronous and asynchronous callbacks, simulate user actions (like pressing keys), the tests need to be atomic (since the DOM will be modified more than one), and I need to be able to mock an HTTP request (to the not-yet-implemented page).

Adding Actual Tests

Here I define a module with two tests. A module is just a logical grouping. Each test modifies the DOM and I check that only one change was made, so as I mentioned earlier they have to be atomic. This is also why suggested that parameterized functions are necessary.


Here I test my key logger by simulating a user pressing keys. This is obviously a contrived example, but I thought it was pretty cool nonetheless and is what convinced me to use jQuery.


Here I've mocked an AJAX call and have it return an error status code. The test is that my error handling callback is called. The test would fail after half a second if there was no response.


Here I've again mocked an AJAX call and have it return a success status code. The test is that my success handling callback is called. This is pretty cool and seemingly very useful too. You can set the response time, response body, headers, etc. too. Someone can then work on the front-end of a site before the back-end is finished.

Results

Look here to see my complete test HTML file. I included a few other tests and show how to do setup/teardown for a module which is another nice QUnit feature. Once finished when I open tests.html in a web browser this is the report I see:


It's still a big leap to go from these simple examples to testing a real site, but I learned that the barrier to entry for writing JavaScript unit tests is lower than expected and you can get going in a couple hours with existing opensource tools. I think I would try to include something like this in a future JavaScript project.