TDD: Driving from the assertion up

I’m doing quite a lot of agile and TDD mentoring at the moment, so such things are always floating near the top of my mind.

A recent article from Mark Needham presents an interesting view on how to construct code within tests, and the impact that might have on how tests drive design of code.

REST and versioning, a more concrete example.

There’s an interesting discussion going on at The Wisdom of Ganesh in which Ganesh Prasad and “Integral ):( Reporting” (presumably the “JJ Dubray” mentioned in the article) are trying to work out some issues around versioning, REST and SOAP. This post is also referenced and commented on at infoQ.

In the 14th comment to the original article, JJ calls for a real-world example – this is a good idea which should help ground the discussion and diffuse the temptation to communicate in abstract principles. In the spirit of this request, I will describe an example based on problems I faced in a previous job.

The first version of the system we were working on consisted of a server component, coded in Java, which provided remote services to several client systems. Each of the client systems was a Java web application, responsible for providing customer-specific web pages and navigation using the services and content provided by the central server. For some customers there would be just one instance of the web client, for others with greater load there would be several.

The server system was responsible for managing products for sale, including descriptions in multiple languages, format and compatibility meta-data, thumbnail images in several sizes, prices in multiple currencies. As well as access to individual items and collections, a search facility provided a way to discover or look up products. The server also managed customer details and purchase histories, and handled both delivery of content and general messaging (by email and SMS) during the purchase process. The client systems were responsible for display and navigation of a product catalogue, customer branding, “shopping cart”, login/logout, and everything else a user experiences.

The API between client and server included ways to list products by category, fetch details of specific products, search using a variety of criteria, make and cancel purchases, fetch and update user data and so on.

I suggest this should be a reasonable system on which to base a discussion – it embodies similar concepts to many other systems, and is neither trivial nor impossible to build. Interestingly, both SOAP and REST versions of the interface between the clients and the server were implemented at different points in the life of the product.

So, on to versioning. It seems to me that there are several kinds of changes which might require versioning. I will list a few here, but I welcome suggestions for others I might have missed.

  • The first deployment of the system worked with only a single currency. The move to multiple currencies was a potentially major change in the interaction between client and server, even though each client works only in a single currency.
  • The customer for one client implementation required the provision of extra services, specific to their market, which were not required by (and should not be available to) other clients.
  • The initial version of the search facility returned data for all matches, with paging through the results implemented entirely on the client. When there was a lot of data in the catalogue this became an unacceptable performance bottleneck, especially as results beyond the first few pages were hardly ever viewed. An alternative approach was suggested where a client would request a specified page (of a specified page size) from the search results. This required changes in both the search request and search results.
  • A new source of products introduced the idea of collections. Items in a collection could be purchased individually or as a bundle. Viewing a collection while browsing, searching, or in a user’s purchase history, should allow a user to “drill in” to the collection to view the items within it. Items located while searching should indicate how to purchase the collection, as well as how to purchase the individual item.

Is this a useful amount of detail for a scenario? I have my own experiences of working with this system and the choices we made, but I’d love to read any suggestions for how you might handle any of the transitions above in a live system with multiple client systems deployed, many of which can not be changed easily or often, and a server full of historical purchase data. Procedural remoting approaches (SOAP, XML-RPC and Java RMI etc.) and resource-based approaches (REST) are all welcome.

Two good videos

Monday was a bank holiday, so I found a little time to catch up with some of the web videos in my queue.

First I watched an inspiring session from TechCrunch Nordic which likens achieving an “exit” for a startup company to dating. Fun, and with a strand of truth.

TechCrunch Nordic – Tommy Ahlers from Mike Butcher on Vimeo.

Anyone running a startup, or thinking about it, should watch this one.

Second I watched a presentation ostensibly about Kanban and “single piece flow”, but really about much wider issues in planning and managing software development. I found the approach presented particularly interesting as it correlates very well with where my thoughts are at right now.

This video is best watched at infoq, to see both the presenters and the slides

Anyone working in software development, or managing a software project really needs to watch this one.

James Carr Feels GREAT to Pair Again

I guess its is a common problem for software developers with a day job as well as out-of-hours projects, but it can be hard to get around to spending time on the out-of-hours stuff.

I read with interest that James Carr sought out someone to pair with and found it a useful and enjoyable experience. ( James Carr » Blog Archive » Feels GREAT to Pair Again. ) It occurred to me that perhaps this is what I need, and by implication, perhaps this is what you might benefit from, too.

So I have an open offer. If you like the idea of spending some evening or weekend time pairing with me, please get in touch. Obviously I’d like to make some progress on some of my own projects, but I’m also very happy to spend time on your projects, too.

There’s a fighting chance that the commitment of an appointment with someone else might get both of us motivated and productive, and that we both might learn some good stuff along the way.

What can we work out together?

The Opposite of Waterfall is Pond – A Metaphor for Agile

You have to love a good analogy. Here’s one which takes the notion of a “waterfall” development process literally, and contrasts it with a pleasant day out on a serene pond.

The Opposite of Waterfall is Pond – A Metaphor for Agile | Agile Blog: Scaling Software Agility

My favourite snippet:

Eventually, we find a place that everyone agrees looks nice and we pull the boat up on shore. Our project is complete in a way that we couldn’t have predicted exactly because we’ve never been on this particular pond before. We’re ready to set out again just as soon as we’re done with the picnic. In Pond, you always have a picnic at the end of the project.

All of which makes me smile. Back when I was working on an agile project where releases were named after ducks and other wildfowl, I proposed at one point a component named “pond” (standing for “provider of necessary data”) shared by all the deployed ducks.

Ah nostalgia.

ecoder – an in-browser programmers’ editor

This is a neat idea, and certainly more friendly than “keyhole surgery” with ssh and vi if you need to edit files on a remote server over the web. Does not seem to have had a lot of development recently, but seems pretty usable as it is.

ecoder | home

Ruby, Sinatra, Dreamhost, Haml, git – a smooth web app workflow … eventually

I have spent many years developing web applications in Java for corporate clients. During that time I have used a wide range of frameworks, APIs and other useful stuff. I have written my own versions (sometimes several) of many of these components, learned the tools well, and become very productive and effective.

However, it has been almost impossible to take that expertise, hard work, and custom code and easily/cheaply turn it into usable web applications for general public use. Low-cost hosting providers have generally shunned Java support. The most reasonable one I have found is LunarPages who actually support both ad-hoc JSP and deployment of custom web applications as war files, even though you have to search pretty deep in their web site to find out, and pay an extra dollar or two a month for the privilege.

So for my own projects I have been looking for an alternative for a long time. A way of developing and testing web apps on my various development boxes (currently running Ubuntu, MacOS X and Windows XP) and easily deploying to a low-cost hosting provider.

By far the most popular web development language is PHP. It’s available pretty much everywhere. It’s so focussed on web app development that the primary unit of coding is the web page. Believe me, I have tried to like PHP, but it’s just so clumsy. After a few paces the application begins to get tangled, development speed drops, and bugs creep in. Its web focus makes it tricky to unit test, and end-to-end testing seems to require a full-fat HTTP server. Not for me.

Beyond the traditional stomping ground of PHP, perl, and other CGI fodder is the new range of “trendy” languages. Ruby, Python, Erlang and even the venerable smalltalk are trying to position themselves as the thinking-person’s web development tool.

Erlang syntax is a bit too odd for me right now, although I may come back to it later. Smalltalk is interesting, but carries with it so much history and is hardly a popular choice for low-cost hosting providers. That leaves a short-list of Python and Ruby.

As languages I like both Python and Ruby. They have broadly similar design goals, both have keen developer communities with plenty of open source resources, and both are commonly found on linux-based web hosts. In order to decide between them I took a look around their frameworks and APIs.

Python has Google on its side. It’s the “native language” of the hugely-scalable Google AppEngine. However, a scan around the web looking for ways of writing web applications led largely to two: Zope and Django. (for balance, there are plenty of others, but these are the standout examples). Zope is old and sprawling. It has some great ideas but is hardly an obvious choice for small, tactical web apps. Django is a bit lighter, but still seems to assume a lot and require a lot of relatively fiddly config.

In the Ruby world the blindingly obvious choice for a web application framework is Rails. Sometimes it seems as if “Ruby” is just another way of saying “Rails”. However Rails, like Django, assumes a lot about the eventual application. Rails also makes a lot of use of code generation, which I simply do not like. I would always prefer that a framework eliminate boilerplate rather than just generate it for me. Looking a little further beyond Rails I came across some really interesting alternatives, and the one which really sparked my interest is Sinatra. For me this one framework made the difference. It’s so streamlined that a basic web app is as simple as:

require ‘sinatra’
get ‘/’ do
‘Hello world!’
end

Best of all, simply running the above file using ruby hello.rb starts up a web server and begins serving pages on port 4567. No extra config or faffing.

Looking around for low cost hosting I found that the provider I already use (Dreamhost) supports Ruby web hosting using Passenger. An ssh to the Dreamhost server for “gem install sinatra” followed by a little bit of FTP and my first Ruby/Sinatra application was live!

A key part of any web application is the pages, and a key part of generating pages is a good template language. As a general-purpose templating language, I still prefer my own Stringtree Templater, part of the Mojasef Java framework. So far I have not found a similar templating solution for any other language. However, for the limited and specific requirement of generating web pages, I am becoming quite fond of Haml. It’s not at all a general templating solution, but it does massively simplify the generation of web pages.

Finally, after years of CVS and Subversion, I have made the jump to distributed version control. Not only is it more trendy, but the ability to work on multiple code branches, on multiple machines, with or without an internet connection, and easily share, identify and merge when necessary has been a key benefit. Occasionally I wonder if one of the other distributed VCS (Mercurial, Bazaar, darcs, etc.) would have been a better choice, but I needed to settle on one and get to grips with it. So I chose git.

There have been a few speed-bumps. Attempting to learn git from manual entries and simplistic tutorials gives very little help on deciding what is worth doing. After about a week of following the techniques in A Git Workflow for Agile Teams, though, I began to get comfortable. Add to that some lovely web deployment tricks from A web-focused Git workflow and a selection of GUI tools ( Git Cola, GitX, and Git GUI ) to get round all that tedious “git add” stuff and simplify infrequent operations, and git becomes a very useful and productive tool.

The upshot is that I currently feel very productive.

My toolbox has a few other things in it, but they are still candidates for change if I find anything better. I am managing my projects and git repositories using Unfuddle but it has a few shortcomings including a ticket system which is a pale and clumsy cousin of bugzilla. For editing I use generic syntax-highlighting text editors (gedit on Linux, TextEdit on Windows and Smultron on Mac) but none of them have the nice autocompletion and refactoring tools I grew addicted to in Eclipse. Suggestions welcome!

Finally, a few spare links relating to the tools mentioned above.

Sinatra: 29 Links and Resources For A Quicker, Easier Way to Build Webapps

HAML reference

Rack

Mini reviews of 19 Ruby template engines

The Forgotten Ruby Web Frameworks

Snakes on the Web: what’s really wrong with web development

I don’t really consider myself a Python developer, although I have dabbled. As with many of the less mainstream languages there are keen developers and thinkers trying to clear away the confusion and push the limits of what is possible.

Snakes on the Web

The article is an enthusiastic call to action for “Pythonistas”, but also a really useful summary of big problems and issues applicable to any language, framework or development approach. Read it, even if just for the excellent (and scary) summary of all the things a modern web application developer needs to be aware of.

Does Agile coaching set up problems for later?

I have seen several attempts to implement an agile approach to software development within large organizations, and in many  (if not all) of those cases the end result has not been very compelling. This is in direct contrast to agile adoption in smaller, typically single-team, companies.

It’s natural enough to assume that problems with implementing agile processes in large organizations stem from some characteristic of the organizations themselves. Amr Elssamadisy, however, has a different suggestion. Perhaps some of the problems stem from the use of external agile “coaches”, and the way that they affect the way both the agile team and the organization operates simply by being there.

Read more at: InfoQ: Opinion: Agile Coaches Frequently a Source of Adoption Problems.

Code should start out messy

An excellent point from Andy Palmer. Code which starts out too neat and ordered can make refactoring too difficult. Throw it all in and let the organization emerge from the functionality.

Andy Palmer » Code should start out messy.

Steve Freeman compares Test-Driven Development to rock climbing

I love this kind of analogy. Thinking and learning about one area by considering another is a very powerful technique for boosting overall understanding and wisdom. In this case, Steve Freeman has scraped off the climbing terminology from a snippet of an article and replaced it with jargon from software development.

Thought-provoking.

Tips on Test-Driven Development | Steve Freeman

Fun with very strict TDD

I use Test-Driven Development (TDD) every day, and find it very helpful. It can be hard to get to grips with, though. I was pleased to read that acceptance-testing pundit Gojko Adzic had fun with some very strict TDD rules.

Gojko Adzic » Thought-provoking TDD exercise at the Software Craftsmanship conference.

My approach to TDD is really quite similar to these strict rules. I’ll admit that I do (sometmes) cut a few corners. The biggest aid to getting the most from TDD is definately good refactoring tools. Without that the whole thing becomes so much more clumsy.

TDD is very comfortable with Java and Eclipse. Recently I have moved out of that comfort zone into some fairly deep JavaScript work, and really miss the ability to automatically extract or move methods etc.

Linux VirtualBox vs Windows

Now this is an interesting result. It appears that even when running in a virtual machine, Linux can be a faster development system than the Windows the VM is running on!

Linux VirtualBox vs Windows for Rails Dev – James Crisp.

Pounding A Nail: Old Shoe or Glass Bottle?

I just found this article from 2005, but it’s a classic!

Pounding A Nail: Old Shoe or Glass Bottle? – Alex Papadimoulis’ .NET Blog.

(via Stack Overflow Blog)

How to Embed Almost Anything in your Website

Another summary of useful tips. This time about how to use existing software and familiar techniques to give a richer web experience.

How to Embed Almost Anything in your Website

Context and problems with “Best Practice”

I sometimes have to suppress a shudder when people use the term “best practice”. Despite a positive sounding name, the idea of “best practice” is almost always used in a way that is restrictive rather than enabling. Declaring one approach or solution as “best practice” by implication shuts out other answers.

I will admit that for some (very narrow) fields there can be a common understanding of the one best way to do something, but this is often so well understood that it does not even get a name. Walking on your feet is generally better than walking on your hands or knees, for example, but I have never met anyone who referred to foot-walking as “best practice”.

In my world of software development, where the landscape changes at a moment’s notice, naming something as “best practice” is tantamount to declaring it obsolete. Yet large numbers of software developers still numbly follow the its lead.

James Bach tackles a similar issue in testing James Bach’s Blog » Blog Archive » The Great Implication of Context-Driven Methodology.

ChromeWatir release 1.0.0

Every now and then we discuss ways of better automating the manual tests which accompany our web applications. This is especially poignant right now as both the development and test teams have been recently reduced in size. We have had some success with Watir in the past, but it was always dependent on Internet Explorer and Windows. So it’s cool to read that there is now an equivalent for Chrome.

ThoughtWorkers on Open Source: Announcing ChromeWatir release 1.0.0

Options for developing mobile apps: PhoneGap, Palm Pre, etc.

Mobile application development is certainly a hot topic at the moment. People seem to be climbing over one another to produce iPhone apps, and Google’s Android is never far from the tech news. But there are also other players, and several want to enable a more familiar web development experience on mobile devices.

SitePen Blog » PhoneGap, Palm Pre, and the State of Mobile Apps

Test-Driven Development of HTTP and REST interfaces with Mojasef

Test-Driven Development (TDD) of HTTP and REST interfaces can be tricky. This post contains some examples of how to do it using the open source Mojasef toolkit. I was prompted to write this post after recently finding and fixing an irritating bug using just this technique.

First, let’s set the scene. In TDD the rules are very simple: No production code is written without a failing test; just enough code is written to satisfy the current set of tests; duplication is mercilessly refactored. TDD is a very powerful and effective technique which can improve both the quality and delivery time of software. HTTP and REST interfaces provide access to a system or component using the HTTP protocol. This access may be by fetching HTML or WML pages, for example, or it may be by sending, receiving and updating resources in some other format such as XML or JSON.

For a first scenario imagine we have an existing HTTP interface for which we want to write a client using TDD. This service is relatively simple to start with. To send a message requires a POST request to a particular URL with two parameters “destination” and “text”. If the destination is valid, the text message is sent to the destination and a “200″ status code is returned. If the destination is not recognized, a “404″ status code is returned. This interface is so simple that it is tempting to just write the client, test it manually and move on. But if we were to do that, then we might not think of all the test case possibilities, and there would be no regression tests to help protect the software from unexpected side-effects later. So we opt to do the right thing, and use TDD.

For the sake of simplicity, I will assume we are using the Stringtree HTTPClient as described in an earlier post. So let’s start with a simple test to make sure the code compiles and the test libraries and stuff are in place:

import org.stringtree.http.*;
 
public class MessageSendingTest extends junit.framework.TestCase {
  public void testExceptionFromUnknownURL() {
    Form form = new Form();
    form.put("destination", "name@example.com");
    form.put("text", "hello from HTTP");
    HTTPClient client = new HTTPClient();
    try {
      client.post("http://localhost:9999/send", form);
      fail("should throw an exception");
    } catch (Exception e) {}
  }
}

This test serves two purposes. First, compiling it helps drive the structure of the test case, what classes need to be imported and so on. Second it documents the expected behaviour of our client if the server is not running or not where it is expected to be. I always like to start with this sort of “null” test case wherever possible. Once we get this test working we are ready to move on to the next step, testing against an actual server.

It might be possible to test against a real server, perhaps by manually examining log files, or checking the actual receipt of a message. Feel free to do that, but understand that that is really integration testing rather than unit testing, and neither helps us design and debug the client, nor document and enforce the proper behaviour of our code once we move on to other work. To gain these benefits we need a server which may be started, examined and stopped quickly and under the control of a simple unit test. This is where Mojasef comes in.

Mojasef is a server and web application framework designed for efficient test-driven development of web applications. Although usually used for building applications, it is just as suitable for building test harnesses. In this case we will build a simple application which implements the HTTP interface described above. And yes, we will do it using TDD, so we leave the MessageSendingTest for the moment and start a new one to drive our test harness without requiring HTTP. As usual, I start with a “null” test to get started:

public class MessageHarnessTest extends junit.framework.TestCase {
  MessageHarness harness;
 
  public void setUp() {
    harness = new MessageHarness();
  }
 
  public void testNoAction() {
    assertFalse(harness.wasCalled());
  }
}

This won’t compile without a MessageHarness class, so let’s make the minimum necessary.

public class MessageHarness {
  public boolean wasCalled() {
    return false;
  }
}

Good, our test now runs, so let’s add some behaviour. First another test:

  public void testCalledWithoutArguments() {
    harness.send();
    assertTrue(harness.wasCalled());
  }

To make this compile we need to add another method to MessageHarness

  public void send() {
  }

Our new test fails, so we need to make it work.

public class MessageHarness {
  private boolean called = false;
 
  public boolean wasCalled() {
    return called;
  }
 
  public void send() {
    called = true;
  }
}

That seems enough to start with. Now back to the main test case. Add a new test to call the application we have just built over HTTP and check that all the communication stuff works. With a bit of refactoring to keep the tests clean and duplication low.

import org.stringtree.http.*;
import org.stringtree.mojasef.standalone.InlineServer;
 
public class MessageSendingTest extends junit.framework.TestCase {
  HTTPClient client;
  Form form;
  InlineServer server;
  MessageHarness app;
 
  public void setUp() throws Exception {
    client = new HTTPClient();
    form = new Form();
    app = new MessageHarness();
    server = new InlineServer(app, "9998");
    server.start();
  }
 
  public void tearDown() {
	server.halt();
  }
 
  public void testExceptionFromUnknownURL() {
    form.put("destination", "name@example.com");
    form.put("text", "hello from HTTP");
    try {
      client.post("http://localhost:9999/send", form);
      fail("should throw an exception");
    } catch (Exception e) {}
  }
 
  public void testHarnessWiring() throws Exception {
    form.put("destination", "unknown@example.com");
    form.put("text", "hello from HTTP");
    assertFalse(app.wasCalled());
    client.post("http://localhost:9998/send", form);
    assertTrue(app.wasCalled());
  }
}

This probably needs a bit of explanation. The MessageHarness class we produced above is a Mojasef web application. Really, without any other configuration, base classes or nonsense. It’s just a “plain old Java object” (POJO). The job of the Mojasef code is to take an object of that class and make its methods available as HTTP URLs.

To serve it over HTTP we could use a MojasefServlet and run it in any Servlet Container, but for this test we want an ultra-light server which can be started and stopped in a test. So we use the InlineServer provided in the Mojasef jar. It’s a real HTTP server which you can use from a regular web browser, but it’s mainly designed for streamlined use in tests.

This server is configured to serve the MessageHarness application on port 9998. Having configured the server we start it in startUp and stop it in tearDown to ensure that nothing is left behind between tests.

The new test makes a HTTP request to the freshly started server, then checks (by calling the MessageHarness method we created earlier) that the test harness application was successfully called. This verifies that the server has been correctly started and called.

It’s still not really testing the message API. To do that we need more tests.

Now, we know from the introduction above that our resource should return a HTTP 404 (“not found”) error if we try to send to an unrecognised address.

  public void test404FromUnknownDestination() throws Exception {
    form.put("destination", "unknown@example.com");
    form.put("text", "hello from HTTP");
    Document result = client.post("http://localhost:9998/send", form);
    assertEquals("404", result.getHeader(HTTPClient.HTTP_RESPONSE_CODE));
  }

Making this test work is pretty simple, especially as we have no other tests which say anything about the HTTP Response code. The only “cleverness” is that we now need to use some slightly smarter features of the Mojasef code.

import org.stringtree.finder.StringKeeper;
import org.stringtree.mojasef.HTTPConstants;
 
public class MessageHarness {
  private boolean called = false;
 
  public boolean wasCalled() {
    return called;
  }
 
  public void send(StringKeeper context) {
    called = true;
    context.put(HTTPConstants.RESPONSE_CODE, "404");
  }
}

Mojasef will try a variety of ways to call a public method. We have seen the basic one – a method with no parameters mapped directly to a URL. This is another one – a method taking a “context” as an argument. This context will be pre-loaded with any POST or URL parameters, as well as any request headers and plenty of other stuff which is not of interest right now. This context also provides a way of setting information to be sent back to the client.

Now, our application code is passing all its tests, but it does so by returning a “404″ error code for all requests. This is not really desirable behaviour, so we need another test:

  public void test200FromKnownDestination() throws Exception {
    form.put("destination", "known@example.com");
    form.put("text", "hello from HTTP");
    Document result = client.post("http://localhost:9998/send", form);
    assertEquals("200", result.getHeader(HTTPClient.HTTP_RESPONSE_CODE));
  }

This test fails, so we need to modify the application to add some understanding of the supplied form data.

import org.stringtree.finder.StringKeeper;
import org.stringtree.mojasef.HTTPConstants;
 
public class MessageHarness {
  private boolean called = false;
 
  public boolean wasCalled() {
    return called;
  }
 
  public void send(StringKeeper context) {
    called = true;
    String destination = context.get("destination");
    if ("known@example.com".equals(destination)) {
        context.put(HTTPConstants.RESPONSE_CODE, "200");
    } else {
        context.put(HTTPConstants.RESPONSE_CODE, "404");
    }
  }
}

Now we reach an interesting point in the development process. It is perfectly feasible to continue in this vein, step-by-step bringing the application into existence. However, even the streamlined InlineServer still needs to set itself up, bind and unbind ports, deal with network traffic and so on. This is considerably slower than a regular method call, and as more tests are added the test case will continue to slow down.

The advantages of the Mojasef approach to web applications really begin to pay off at this point. The tests we already have prove the basics of HTTP Communication are working, so further tests do not really need to bother with HTTP, provided the tests are testing exactly the same code. Luckily (as pointed out earlier) a Mojasef application is just a regular Java class, which needs no modification to be tested using regular JUnit tests. Here are the same tests as above, but implemented as simple method calls:

import org.stringtree.finder.StringKeeper;
import org.stringtree.mojasef.HTTPConstants;
import org.stringtree.mojasef.HTTPConstants;
 
public class MessageProcessingTest extends junit.framework.TestCase {
  StringKeeper context;
  MessageHarness app;
 
  public void setUp() {
    context = new MapStringKeeper();
    app = new MessageHarness();
  }
 
  public void test404FromUnknownDestination() throws Exception {
    context.put("destination", "unknown@example.com");
    context.put("text", "hello from HTTP");
    app.send(context);
    assertEquals("404", context.get(HTTPConstants.RESPONSE_CODE));
  }
 
  public void test200FromKnownDestination() throws Exception {
    context.put("destination", "known@example.com");
    context.put("text", "hello from HTTP");
    app.send(context);
    assertEquals("200", context.get(HTTPConstants.RESPONSE_CODE));
  }

I shall stop there, leaving the development of the rest of the application to interested readers.

From the above steps, I hope you can see that the normal process of Test-Driven Development is quite possible for both web applications, and web-application clients. When using a framework which gets all the fiddly stuff out of the way it can even be as simple, quick and productive as in-process development.

How Agile Benefits the Individual

This is an interesting idea. It’s common for agile techniques to be defined by their benefits to the business, but there is often a benefit to the development of the individual people involved in the agile process, too.

InfoQ: How Agile Benefits the Individual