NexWerk Blog

Thoughts from the craft

Easter Monday

Thanks to Ed Yourdon for allowing me to use this photo.

  Photo by Ed Yourdon

This Easter Monday Ade came over to the workshop to pair with me for a couple of hours on a project that he wanted to start on googles AppEngine.

When he came we talked a bit over what the project will be all about. Xandria, as we later in the day decided the baby should be called (I will actually explain how we came to that name too), is a feed aggregator.

Knowing that we need to work with feeds and offer some functionality to a user we defined a two stories to begin with:

As a user I want to add a feed to the list of feeds.

As a user I want to see a list of all the feeds in the system.

Before we started though, we wrote our first test to see how gaeunit will work in AppEngine and what we can learn from it.

import unittest
 
class TruthTest(unittest.TestCase):
  """Testing the truth of all matters in gae"""
  def test_should_be_true(self):
    self.assertEquals(True, True)

We decided to call it truth as the test is totally unrelated to a feed aggregation program or anything like it, but it forced us to configure our application so that AppEngine would respond to requests (and it helped me to get busy with python):

application: aggregator
version: 1
runtime: python
api_version: 1
 
handlers:
- url: /test.*
  script: gaeunit.py

Firing up the development environment of AppEngine

dev_appserver.py xandria/

we could actually see the test running and passing which told us that the environment was ready for us to start coding.

It was the time to concentrate on the first story:

As a user I want to see a list of all the feeds in the system.

For this we would need a Feed object which has a url attribute in it:

def testShouldExist(self):
    try:
      Feed()
    except NameError, e:
      self.fail(str(e) + 'The Feeds class does not exist! What are you waiting for?')

As our failing test comment told us when we ran it: what were we waiting for?

So we implemented the very basic Feed class to make the test pass and we continued with the next test. A feed is supposed to have a url, so let’s test that!

def testFeedShouldHaveUrl(self):
    self.assertEquals(self.url, self.feed.url)

Moving on and fast forwarding this story we kept on implementing the two stories of Xandria pomodoro after pomodoro, refactoring the code as we went by, till we got it all working (there is no UI or anything yet).

One thing that got me worried was that we could not find at the moment any way of testing the actual story, i.e. a functional test of the whole shebang. We actually made excuses not to spend time searching for it… To be honest, when we finished our session I was a bit worried about that and could not really rest well.

In the morning (today) I looked around and actually saw that gaeunit could be useful after all for testing the functionality. So armed with lots of courage (I am an absolute noob in Python) I implemented the missing tests and pushed the changes, once they where passing, to github with a cosy warm feeling…

Why Xandria?
The name Xandria came up from the following though process. Xandria is a feed aggregator, which is a compilation of feeds. A feed is a document, aka a book if you will. Alexandria was the largest library in the ancient world, that is the librarians in Alexandria compiled all the information they could get about books and stored them in their library. Now, there are tons of projects called Alexandria in the world…

Ale ≠ Ade… So AdeXandria would not really rock… so forgetting the whole Ale/Ade we are left with Xandria, which sounds pretty good to me :)

Lessons Learned so far
One of the biggest lessons I took form this session was the syntax of the Python language, which was something I wanted to look at a while back (2003 or so) but never did.

It was nice to see how AppEngine works and how easy it is to setup an application with it in nearly no time. It somehow reminds me when I first built a Rails application a couple of years back (although without the wow effect I experienced back then).

But the really important thing I took from the session is that you should never ever code without testing your functionality! Yes, it is embarrassing to admit that we chose not to test the UI (although there is not much of a UI yet). The reasons was not really a good one either, there was simply none. At least I spent some time this morning learning how to do it, implemented the tests, and have them now…

What Next?

Well, the application is far away from being anything that we would like to use, so there is still a couple of sessions left to develop it. We will meet soon again (maybe this Saturday) and continue where we left yesterday. If someone is interested to come and code with us just shout (given you are in London ;) ).

If you want to look at the source code don’t hesitate to check it in the Xandria git repository on github.

About the picture

The picture displayed in this post comes from Ed Yourdon‘s flickr photo stream. He very kindly allowed me to use it in this post, which I am very grateful of.

I chose this picture as it shows road leading to a beautiful mountain range, as it reminded me to the long road we are in as Aspiring Craftsmen trying to make learning and the craft an integral part of our life.

Share and Enjoy:
  • Print
  • Digg
  • del.icio.us
  • LinkedIn
  • MySpace
  • Tumblr
  • Twitter

One ResponseLeave one →

  1. I don’t want to act rudely, but I disagree with the way you use the term “story” here, and I nearly gasped when you added a property ‘url’ to your Feed because, “feeds should have URLs”!

    As a user, I never want to add a feed to a list, and I never want to see the list of feeds. I interpret those as design activities, and return to the classic question “What’s the good business reason for doing this?” to help me find the story. Not knowing your domain intimately, I can’t answer the question, but I can certainly ask it. What’s the good business reason for adding a feed to a list?

    Your tests leave me speechless:

    def testShouldExist(self):
    try:
    Feed()
    except NameError, e:
    self.fail(str(e) + ‘The Feeds class does not exist! What are you waiting for?’)

    Why do you need this class? What feature requires you to design it? I consider this step far too small for TDD.

    Now I must stress something: I imagine you built good software with a strong design, but your “stories” are tasks and your tests indicate that you wrote your code doing test-first programming, rather than test-driven development. I have no problem with all that, except that when we use the same words to describe different things, we cause wars.

    Take care.

Leave a Reply

Get Adobe Flash playerPlugin by wpburn.com wordpress themes