That Vision Thing

This is a bit of a ramble, but it does hit its points, so here goes…

I was just watching Mark Williams' Industrial Revelations, which aired on the Discovery Channel last night.

I love the show and its subject matter: I am always entranced by the oily, noisy, lumps of steel, brass and leather, the ingenuity of the designers and builders and the sheer daring of the project sponsors.

The section on the construction of the Cromford Canal activated my muse. The canal was built by Sir Richard Arkwright (who was one of the richest people in the world at his death) to bring raw cotton from Liverpool to his mills. As business boomed, the capacity of the canal was filled and so the Cromford and High Peak Railway was constructed to allow expansion to continue. The machinery (beautiful steam engines, etc.) continues working to this day; although it has been rendered obsolete by changes of fortune, it has not failed.

Interestingly, the canal was built by one generation and the railway built by a second generation of the same family: William Jessop and his son, Josias.

This got me thinking: about how many times I have been given a brief along the lines of "we know that the system is stuffed and needs to be completely upgraded, but we don't want (dare/can afford) to change it, so please just twiddle around the edges and keep it plodding along." I have worked on code that has also been touched by older/younger siblings (roughly equivalent to different generations in "IT years"…); my brief was to fix but not change, the unspoken attitude was "it ain't broke, really, so don't change it" or "she'll be right, mate" or perhaps even "it's close enough for Government work."

Let's go back: Josias didn't try to simply fix up his father's canal (widen it, make the horses move a bit faster, put lighting along it to ensure that 24-hour operation was possible, maybe play around with a few other tweaks); he was brave enough to say "we need a new approach, we need this new technology, so bring on the railway."

How different these attitudes are!

Sadly, I feel that the spirit, the vision, the will to do this has vanished from our society. We seem to be too fat and comfortable, too intransigent, too resistant to even the smallest change to actually do much of anything worthwhile, it seems.

Here in Sunny Brisbane, I have seen people tearfully protesting because a nearby roadside noise barrier was painted red by the council. The affected residents seemingly couldn't say what colour was actually appropriate, but they knew that their world was going to implode as a result of having a red barrier.

As in life, so in the IT world.

I have seen (and been a part of) research institutions set up and then left to gradually wither on the vine; I have seen (and been a part of) software engineering 'Incubators' set up and then almost instantly destroyed by the threat of a punitive tax ruling. There's no driving force, no grand plan to force these things along so instead they just churn away in the background and the best that one seems to be able to achieve is a zero-sum game.

Take a look at the way the Australian IT job market has developed over the past few years: there seem to be a multitude of positions for project managers, analysts, documenters, support personnel, etc. There are very few for developers and those that are out there are for junior-grade people. My conclusion from this is that nobody is doing anything new, the PMs, analysts, etc. are all working in holding patterns but not pushing anything forward. We seem to be restricted to cutting the grass on the banks of the canal, hoping that will improve things. We need the railway engineer.

I can't help but think back to the amazing achievements of the Industrial Revolution, many of which still stand even today. Consider how London is still benefiting from its city-spanning underground system (opened in 1863)…

Would the underground get built today? We have vastly superior technology so it would be simpler to achieve, but would the initial proposal even get past the "first post"?

I think not.

Here in Brisbane, we are abandoning capital works like rail corridors, roads (even simple road upgrades) and tunnels left, right and centre.

The Powers That Be claim that this is "due to the 'credit crunch' and the other impacts of the financial crisis."

I say that this is truly due to a lack of drive, of will, of vision. Perhaps it is about abandoning the future, as well?

I wonder if Richard Arkwright would have said "OK, I don't have the money in my pocket today, so I'll wait." I suspect he actually would have said "I stand to make a sh*tload of motza by this…bring it on."

Back to the IT world again: where is the Ozzie Google, Facebook, Amazon? These organisations don't depend on the presence of natural resource, they aren't restricted by national boundaries so why hasn't Australia-which is well-known as an early adopter of (other people's) technology-got its act together? We do have wotif, I am happy to say; we should have many more wotifs.

Having seen China's massive change and ongoing development over the last 20 years, I can't help but come to the conclusion that we are seeing the rise of a new industrial power and of a new people who "can do."

China (and India, and to lesser degrees Thailand, Vietnam, Malaysia, Singapore, …) is also beginning to think big and build for the future. They aren't abandoning their future, they are preparing for it, shaping it.

Truly, we complacent Ozzies (and brits and yanks, etc.) are going to be left well and truly behind.

Tags: Rant

The Curious Cat

This is an interesting (if slightly stale) site: The Curious Cat.

While interesting in its own right, it also provides a nice jumping-off point for other points of interest such as Deming Connections, John Grout's Mistake-Proofing Center and Your Code Sucks and I Hate You: The Social Dynamics of Code Reviews.

Tags: Agile, Tools

Perhaps I'll Open a Bag Shop…

…'cos here's another one from the pile:

I remember that months of deliberation went into the phrase "People, Places, Things"; the phrase was supposed to act as a rallying call to give the research a tangible direction. I was never sure how a random collection of nouns was supposed to achieve this but it was probably as good (and as effective) as any other slogan.

Tags: Retrospectives

The Cleanup Continues…

…and I found another DSTC-related T-Shirt; this one comes from the wrap-up party that was thrown to celebrate DSTC's demise. Take a look:

Although my personal opinion is that DSTC was not a successful endeavor, I will restate an earlier opinion/question: where is Australian (IT) Research? The Australian media is always claiming that Australia punches above its weight at sports, at warfare (sorry: peacekeeping activities), at media-related activities, etc. so why aren't we punching above our weight here? Well…no…dont get me started. Really!

Oh wow! Look what else the cleaning uncovered: a genuine JavAus98 bag!

I had a hand in organising and presenting at both JavAus98 and JavAus99. Although these events have both faded from memory (they cant even be found at the wayback machine), they were fun. Java was 'new' and 'buzzing' and was about to change the IT world as we knew it ( ;-) )…

Tags: Retrospectives

Ah! Memories!

I have been doing the annual "New Year's Clean-Up" (what my Hongkie wife calls "dai so choi []") and I found an old T-Shirt. Take a look:

This was a nice bit of political grandstanding by the fairly-new Borbidge Liberal Government of Queensland, attacking DSTC, the research organisation that I was then working for.

Happily, that little political experiment didn't last too long!
(edit: I meant the Borbidge government, but I guess I could say the same about DSTC itself…)

Sadly, we still don't have strong government support for IT or any other 21st century technology in Queensland…think about the current absurd National Broadband Network debacle and then compare and contrast with Singapore, Shanghai, Mumbai, etc.

It seems that all flavours of Australian pollie are simply content to keep doing nothing more demanding than digging and shipping our dirt overseas…

Tags: Retrospectives

Head(ing) in(to) the Clouds

That's me, all right, always dreaming!

Waaaaay back in the far-gone days of the late 1990s and early 2000s I was involved in a project to build a distributed object-based system for a small (to remain nameless) Queensland business. We built it, schlepped it around, set up a demo/trial testbed and got a fair bit of interest. We even made the first steps to getting a patent (I have no idea what happened to that). Somehow however, it didn't quite take off and anyway the bubble and social phenomenon that was The Internet burst and so interest quickly evaporated.

All that work :-(

Such is life!

Getting a testbed up and running was (ahem) 'interesting': we had to buy a dedicated server and round up an old box to act as a firewall, arrange for a tame organisation to host them for us (one of our backers helped us out there…), configure the pair appropriately, get the darned kit on the 'net (easy to say but this was the time of the 33.6Kbps modem, remember; those things were not known for their reliability), and so on. Not the easiest thing to do and definitely not core to what we wanted to be doing.

Things are so much easier these days. Why, back in my day, we….

I have just had a play with http://www.stax.net. This gives a glimpse of Platform As A Service.

According to TechCrunch, Stax is:

…built on top of Amazon EC2 and allows developers to create, text and deploy Java applications without having to build out their own physical infrastructure.

For now Stax isn't charging users at all. Eventually they'll move to a model that charges for resources uses, similar to EC2 and other infrastructure platforms.

At the moment, Stax is in beta test and one has to sign up to get an "invitation code" so that the stax guys can control demand appropriately. I got my code within a few days of making my application.

There are other similar facilities such as Morph AppSpace for Java; the buzz is that this is more mature so I may give this a burl later on.

Stax is based on Amazon Elastic Compute Cloud (Amazon EC2):

Amazon EC2 presents a true virtual computing environment, allowing you to use web service interfaces to launch instances with a variety of operating systems, load them with your custom application environment, manage your network's access permissions, and run your image using as many or few systems as you desire.

In what is pretty much the simplest possible test, I downloaded the Stax SDK, took my earlier Pokie/Drools example and uploaded it to Stax.

Since grails is not officially supported quite yet, I followed the instructions here.

It worked! Right out of the box! Take a look at the URL…

There is a rudimentary console that lets you control your application, invite new development team members, etc.. Nothing special but it gets the job done:

Uploading the application was a bit slow (probably due to my internet connection, rather than anything Stax-related) and the application is pretty simple (no database at all, for instance) but I instantly found myself reminiscing about that earlier project. How much simpler setting up a testbed would have been, how many kilometers of modem-nastiness-related driving I would have saved, how easily I could have demoed new iterations to the client, etc., etc.

Kids these days have got it too easy :-)

Tags: Grails, Programming

A Piccy From the Past

I came across this piccy a while back and thought that I would preserve it for posterity:

It shows me teaching Java to a group of QUT students taking a summer course. At the time of the photo (likely summer 1999), I was working at the now-defunct Distributed Systems Technology Centre's QUT offices. The photo shows the DSTC training room at QUT; through the door behind me was a load of SGI boxes donated on the premise (apparently) that DSTC would help SGI 'rule' the Internet.

Ah…memories!

Tags: Retrospectives

One Source to (D)Rool Them All…

[edit: 12 May, 2009]
Whoopee! At least one person has read this posting:

Thanks Bob for great article on drools/grails. It is very useful.

regards
zys

I've wanted to get onto this for a while now, so here goes.

The "State of the Art" application is generally a real dog's breakfast. Sure, we all create our nice MVC-based applications using the Spring framework, or JBoss SEAM or even good-old Struts and we feel pretty good about it but let's face it: the typical MVC application is actually a pretty nasty thing that is not MVC at all.

Here's one aetiology…I'm sure you will recognise it.

Andy the Architect comes in and specs out a nicely structured work of art. On paper, it is clean and tidy with clearly separated layers and distint responsibilities. Then a few cross-cutting concerns muddy the waters a bit but no problem, things are still lookin' good. Then Joe the Developer comes along and starts building. Except in the interests of performance it becomes vital that some processing is moved into stored procedures. Well, OK, there is still a logical mapping in the architecture. Joe shuffles off the project and Freda arrives. Freda wasn't privy to those early days when the architecture was decided upon and when the rationalisation (sense 2) surrounding the decision to use stored procedures was fresh in everyone's mind and so decides to implement a nice, clean separate module for her work. Time progresses, the business changes and expands and suddently Bill is brought in to help out Freda. Of course both Freda and Bill can't work on the same module so it is split. Bill is an old war-hardened JSP developer but is not really au-fait with the system's backend and so another, JSP-oriented and (subtly?) different approach is brought to bear.

And so it goes.

This effect is seen most keenly with respect to the mechanisms of data access/searching/filtering: Joe is happy to spend a day working how to use n-level nested selects with carefully decided-upon projections, etc. to ensure that what he pulls from the database is precisely and only what he needs whereas Bill-more cognizant of approaching deadlines, perhaps-just grabs everything and iterates across the result set, rejecting 90% but getting what he needs. The code is quick and easy to write, however ;-)

The effect is also a major issue when one considers the business rules that underly most, if not all, applications. It is depressingly common to see the aetiology considered earlier resulting in rules split across an application's database, webservice, controller and view (it is also depressingly common to see these layers implemented variously in different technologies, but that is a rant for another time).

Recognising the drawbacks of traditional MVC some have adopted the idea of MVP (Model View Presenter) as a way of saying "make sure that your view layer is only about the UI." The idea of anaemic domain as anti-pattern still rules the roost and is frequently used to justify the messiness that I am trying to highlight here.

In the J2EE world, it used to be said that "stored procedures should migrate to Session Beans" and there was a lot of truth in this. After all, to quote Michael Juntao Yuan, author of Seam Framework: Experience the Evolution of Java EE, Second Edition:

In almost all enterprise applications, the database is the primary bottleneck, and the least scalable tier of the runtime environment. People from a PHP/Ruby environment will try to tell you that so-called "shared nothing" architectures scale well. While that may be literally true, I don't know of many interesting multi-user applications which can be implemented with no sharing of resources between different nodes of the cluster. What these silly people are really thinking of is a "share nothing except for the database" architecture. Of course, sharing the database is the primary problem with scaling a multi-user application-so the claim that this architecture is highly scalable is absurd, and tells you a lot about the kind of applications that these folks spend most of their time working on.

Almost anything we can possibly do to share the database less often is worth doing.

Sadly however, trying to persuade someone fixated on the 'fact' that "stored procedures are faster" is usually a lost cause; one can talk about clean design and easier maintenance, fewer technology and cultural impedance mismatches, the benefits of integrated security and monitoring, the ease of clustering and so on but one's arguments always seem to fall short, as measured by the yardstick of a mental stopwatch. Such is life…

What if one could centralise all the messy rules that are typically spread throughout a system into one clearly-separated subsystem. This is what JBoss' Drools (now JBoss Rules) aims to enable and-ranting aside-is the actual focus of this post.

Welcome to Bob's Pokie machine!

Before we start, please note that I do not like these damn things at all. They are a scourge on the social groups least able to resist them, IMHO. For once I agree with Russell Crowe!

A pokie is essentially simple but has a number of rules regarding when payment is to be made to the punter and when the house should take the money and run.

Bob's Pokie is written using Grails. It is very,very simple!

The design goes something like: "A Pokie has a spindle with 3 reels. After each spin, the value of each reel is obtained and the overall results evaluated to determine whether the spin has produced a win or a losing result." From this, we get a single simple GSP and a number of simple objects: Spindle, Reel, EvaluatorResult, EvaluatorService and PokieController.

It is probably worth taking a quick tour around the source, starting with the GSP:

<%@ page contentType="text/html;charset=UTF-8" %>
<html>
  <head><title>Bob' Pokie</title></head>
  <body>
    <h1>Bob's Pokie</h1>
    <p>Guaranteed to eat all your money, "but don't you worry about that"</p>
    <g:form controller = "pokie" action = "play">
      <g:select name = "leftReel" from = "${1..5}" value = "${session.spindle?.spindle.leftReel.value}" multiple="multiple" size="5" />
      <g:select name = "middleReel" from = "${1..5}" value = "${session.spindle?.spindle.middleReel.value}" multiple="multiple" size="5" />
      <g:select name = "rightReel" from = "${1..5}" value = "${session.spindle?.spindle.rightReel.value}" multiple="multiple" size="5" />
      <br />
      <g:submitButton name="spin" value="Spin" />
    </g:form>
    <g:if test="${session.evaluatorResult == pokie.EvaluatorResult.INACTIVE}">Give it a spin...</g:if>
    <g:elseif test="${session.evaluatorResult == pokie.EvaluatorResult.LOSE}">You Lose :-(</g:elseif>
    <g:elseif test="${session.evaluatorResult == pokie.EvaluatorResult.SMALLWIN}">You Win. Just.</g:elseif>
    <g:elseif test="${session.evaluatorResult == pokie.EvaluatorResult.BIGWIN}">You Win...BIGTIME!</g:elseif>
    <g:else>Oh Dear! Something (${session.evaluatorResult}) went wrong here<br /><g:link action="index">Start Over</g:link>
    <script type="text/javascript">
      document.getElementById('spin').disabled = true
    </script></g:else>
  </body>
</html>

The associated controller is, in true Grails style, very simple:

class PokieController {
  def evaluatorService

  def index = {session.spindle = new pokie.Spindle(); session.spindle.reset(); redirect(action: show) }

  def show = { session.evaluatorResult = evaluatorService.evaluate(session.spindle) }

  def play = {session.spindle.activate(); redirect(action: show) }
}

A Spindle is pretty much simply a collection of Reels:

package pokie;

public class Spindle {
  private final spindle = [leftReel: new Reel(), middleReel: new Reel(), rightReel: new Reel()]

  private initialised = false;

  def reset = { initialised = false; spindle.each { k, v ->  v.reset() } }

  def activate = { initialised = true; spindle.each { k, v -> v.activate() } }

  def getSpindle = { Collections.unmodifiableList(spindle) }
}

A Reel is:

package pokie;

public class Reel {
  final rand = new Random()

  int value

  private rint = { rand.nextInt(5) + 1  }

  def reset = { value = 3 }

  def activate = { value = rint() }
}
        

For completeness, here is EvaluatorResult, a standard enum:

package pokie

public enum EvaluatorResult {
  INACTIVE, LOSE, BIGWIN, SMALLWIN, OTHER
}

The first attempt at making EvaluatorService will ignore Drools and do everything "by hand." Here goes:

import pokie.EvaluatorResult

public class EvaluatorService {
  static transactional = false

  // a SMALLWIN is: all 3 reels show the same value
  // A BIGWIN is: all 3 reels have the value 3
  // everything else is a LOSE
  static evaluate = {spindle ->
    if (!spindle.initialised)
      return EvaluatorResult.INACTIVE;

    def firstVal = spindle.leftReel.value
    if (spindle.find {k, v -> v.value != firstVal} != null)
      return EvaluatorResult.LOSE

    return firstVal == 3 ? EvaluatorResult.BIGWIN : EvaluatorResult.SMALLWIN
  }
}

Nothing special here; the code is small, straightforward and easy to understand, right?

Yes and no.

Looking through the code, I see a couple of 'if' statements and a bit of searching through a collection. In fact there is absolutely nothing to tell me that here is the key set of business rules. Unfortunately enough, it is the comment that gives the only real clue. Truly this is not good and we need to try harder.

Consider too, that it may be neccessary to get a Product Owner or domain specialist to review the rules (something that may actually be required for a Pokie in Queensland). My guess is that not too many domain specialists are going to understand even simple code like that in EvaluatorService.

Drools helps by providing a general-purpose rules engine, based on some pretty clever ideas, which allows for rules to be specified in ways other than pure code. Drools allows for rules to be written in XML, the "near english" DRL or even Spreadsheet-based Decision Tables. There is also an extensive toolset supporting Drools with editors, debuggers, etc..

Take a look a the DRL corresponding to the evaluation that we have just used:

package pokie;

rule "Other"
     salience -1000
     dialect "mvel"
     lock-on-active
     activation-group "pokie"
  when
      e : Evaluation(initialised == true)
  then
     modify ( e ) { result = EvaluatorResult.OTHER };
end

rule "Pokie is Initialising"
     salience -1
     dialect "mvel"
     lock-on-active true
     activation-group "pokie"
  when
      e : Evaluation(initialised == false)
  then
     modify ( e ) { result = EvaluatorResult.INACTIVE };
end

rule "Big Win"
     salience 2
     dialect "mvel"
     lock-on-active
     activation-group "pokie"
  when
      e : Evaluation(initialised == true,
                          (leftReelValue == middleReelValue) && (leftReelValue == rightReelValue) && (leftReelValue == 3))
  then
     #System.out.println( "Big Win" );
     modify ( e ) { result = EvaluatorResult.BIGWIN };
end

rule "Small Win"
     salience 1
     dialect "mvel"
     lock-on-active
     activation-group "pokie"
  when
      e : Evaluation(initialised == true,
                          (leftReelValue == middleReelValue) && (leftReelValue == rightReelValue))
  then
     modify ( e ) { result = EvaluatorResult.SMALLWIN };
end

rule "Losing"
     salience 0
     dialect "mvel"
     lock-on-active
     activation-group "pokie"
  when
      e : Evaluation(initialised == true)
  then
     modify ( e ) { result = EvaluatorResult.LOSE };
end

Much more verbose, of course but also probably clearer, especially once one becomes familiar with the ideas of salience (basically a rule's weight or priority), activation-group (only one rule in an activation-group is allowed to become active at any time) and lock-on-active (don't reevaluate the ruleset after a modify has executed).

With the exception of the way that data is packaged up into an Evaluation instance for the ruleset to use, the code that handles rule evaluation is pretty much boilerplate:

import org.drools.KnowledgeBase
import org.drools.KnowledgeBaseFactory
import org.drools.builder.KnowledgeBuilder
import org.drools.builder.KnowledgeBuilderFactory
import org.drools.builder.ResourceType
import org.drools.definition.KnowledgePackage
import org.drools.io.ResourceFactory
import org.drools.runtime.StatefulKnowledgeSession
import pokie.Evaluation

public class EvaluatorService {
  static final RULES = 'pokie.drl'
  static transactional = false

  def evaluate = {spindle ->

    def kbuilder = KnowledgeBuilderFactory.newKnowledgeBuilder();

// this will parse and compile in one step
    kbuilder.add(ResourceFactory.newClassPathResource(RULES,
            EvaluatorService.class), ResourceType.DRL);

// Check the builder for errors
    if (kbuilder.hasErrors()) {
      def errs = kbuilder.getErrors().toString()
      def msg = "Unable to compile '${RULES}': ${errs}"
      log.error (msg);
      throw new RuntimeException(msg);
    }

// get the compiled packages (which are serializable)
    def pkgs = kbuilder.getKnowledgePackages();

// add the packages to a knowledgebase (deploy the knowledge packages).
    def kbase = KnowledgeBaseFactory.newKnowledgeBase();
    kbase.addKnowledgePackages(pkgs);

    def ksession = kbase.newStatefulKnowledgeSession();

    def e = new Evaluation(leftReelValue: spindle.spindle.leftReel.value,
            middleReelValue: spindle.spindle.middleReel.value, rightReelValue: spindle.spindle.rightReel.value, initialised: spindle.initialised)
    ksession.insert(e);

    ksession.fireAllRules();

    ksession.dispose();

    e.getResult()
  }

}

That's it! Plop a few jars on the classpath and we're up and running. Very clean.

So what does this buy us? Those obsessed with SLOC or 'efficiency' would be quick to say "nothing." IMHO, this may well be short-sighted and probably quite wrong.

For one thing, none of the rest of the application outside of the EvaluatorService is 'infected' by the need for rule handling at all. This is A Good Thing.

Another benefit is that this gets us to a situation where adding rules is easy. So far the rules defining the winning combinations are few and simple: all 3 reels must have the same value, with a 'bonus' if that value is 3:

In a fit of unexpected generosity, let's make it easier to win by adding a few new winning patterns:

With Drools, very little extra work is needed. Only a slight mostly cosmetic modification of the GSP and the addition of a couple of new values in the EvaluatorResult enum are required to support the addition of a few more rules to the ruleset, viz:

...
rule "MEDIUM Win 0 > 1 > 2; ASC"
     salience 1
     dialect "mvel"
     lock-on-active
     activation-group "pokie"
  when
      e : Evaluation(initialised == true,
        (leftReelValue == (middleReelValue + 1)) && (middleReelValue == (rightReelValue + 1)))
  then
     modify ( e ) { result = EvaluatorResult.MEDIUMWIN_ASC };
end

rule "MEDIUM Win 0 < 1 < 2; DSC"
     salience 1
     dialect "mvel"
     lock-on-active
     activation-group "pokie"
  when
      e : Evaluation(initialised == true,
        (leftReelValue == (middleReelValue - 1)) && (middleReelValue == (rightReelValue - 1)))
  then
     modify ( e ) { result = EvaluatorResult.MEDIUMWIN_DSC };
end
...

These changes have added almost nothing to the complexity of the application but have added some significant new features.

If you take the time to consider what the 'old' hand-coded evaluator will be starting to look like (a few more 'if's to get one's head around, with a lot nastier cyclomatic complexity), you will start to get an appreciation of the value of the Drools approach. If you push this example a little further and consider that a real pokie would have rules for dealing with everything from dealing with maintenance needs and hardware faults through determining an response to a network outage to dealing with customer loyalty cards and you will see that even a simple system can get complex very quickly; the original simple evaluate() method has ballooned out into a module…

Now, I am the first to admit that this is a very simple example and not at all a good use-case for a rules engine like Drools: it is far too simple and the problem doesn't really have a multitude of cross-cutting rules and business illogic that would make Drools a better fit. It has made a nice playpen for understanding and experimenting with Drools however, and I hope that the fundamentals have come through: how Drools has kept the application clean and tidy and centralised all the messiness of rule processing into one place. A major benefit of this has been to make the rules themselves explicit, easily changeable and amenable to review by an appropriate tame domain expert.

Of course, if you really feel the need, you can be really clever ;-)

One of the more interesting uses for Drools is that it is used to provide the underlying security infrastructure for Seam 2.0.

The Grails/IntelliJ project for this posting is available (requires Grails 1.1).

Tags: Grails, Programming

Some Other Very Wise Sayings…

Both of these speak to my favourite neuroses

From http://www.c2.com/cg … ocumentationPatterns:

Documentation is more likely to be wrong than code, because it has no test cases

From http://www.agiledeve … 10-ba0e-b6a08b659a44:

"Error rate in manual testing is comparable to the bug rate in the code being tested."-Boriz Beizer.

Think about these. Please!

Tags: Agile

A Better Way?

Yet another Lunchtime Conversation; this time about easyb and responses to my earlier posting Green is Good, but easyb may be Even Better….

Basically, the question was "What's wrong with JUnit, anyway!"

Well…

Here is the more 'traditional' JUnit-based (but also Groovy-friendly) EasySpec:

package org.easyspec.example

import org.easyspec.*

@EasySpec(interest='A character')
class Character_when_freshly_created_Test extends GroovyTestCase {
    def character

    @Context("that has just been created")
    public void setUp() {
        character = new Character('Thorr')
    }

    @Behavior
    public void test_should_have_a_health_level_of_100() {
        assertEquals 100, character.health
    }

    @Behavior
    public void test_should_have_a_name() {
        assertEquals 'Thorr', character.name
    }
}

(this is the basic EasySpec example, by the way…)

There is also BDoc, which enables 'goodness' such as this:

@Test //Scenario
public void givenIHave200$InMyAccountWhenIAskToWithdraw20$ThenIShouldBeGiven20$AndMyBalanceShouldBe180$() {
  Account account = new Account(200);
  int cashGiven = account.withdraw(20);
  assertEquals(20, cashGiven);
  assertEquals(180, account.balance());
}

Now, I do NOT want in any sense to dismiss or belittle these projects, but maybe something more "out of left field" might just be better…compare the EasySpec example above to an equivalent easyb version:

scenario "Freshly Created Characters Test" {
  given "A character that has just been created" {
    character = new Character('Thorr')
  }
  then "The character should have a health level of 100" {
    character.healthLevel.shouldBe 100
  }
  then "The character should have the name 'Thorr'" {
    character.firstName.shouldBeEqualTo 'Thorr'
  }
}

I know which *I* think wins in oh so many ways: clarity, ease of preparation, lack of strange conventions (all those annotations and strange names…IMHO not so good). Recall from my earlier posting the idea that perhaps a Product Owner or Domain Expert could write an easyb story which is then passed on to a developer for further elaboration. Could that be done with either the EasySpec or BDoc versions? I have strong doubts!

For those absolutely wedded to JUnit, it is probably worth mentioning TestDox, which can help to make documentary sense of things. The closest 'competitor' to easyb is the written-in-ruby rspec.

Again: please don't think that I am trying to "put down" EasySpec, TestDox, BDoc, etc., but it just seems to me that there can be a better way…

Tags: Tools