ThoughtWorks Australia is Hiring!
ThoughtWorks Australia is looking for new talents!
This time we are hiring Senior QA Testing Consultants!
So if you want to work in this fast growing, unhierarchical consultancy, applying your knowledge of testing in a variety of client environments while constantly using the latest methodologies and technologies, you can continue reading this post, otherwise, just don’t bother
Working with us, you’ll get to work alongside truly talented teams and help them enhance their performance by bringing quality assurance to the forefront of clients’ minds. As well as ensuring the bug-free delivery of custom built software, you will also be working with clients to advise them on improving their test processes and teaching them about the very latest from the QA world.
Some Of The Duties
Our test processes are very different to many organisations. Testers are involved from the initial requirements gathering through implementation to deployment. They are always around to ask the awkward questions and try scenarios that analysts or developers are unlikely to dream up. They are involved when analysts are capturing requirements in the form of user stories. These stories are then converted into acceptance tests outlining specific scenarios. Testers play a big part in making sure those tests are well defined and complete so that developers know when they have finished implementing the functionality defined in a story. For more information, visit http://testing.thoughtworks.com.
Desired Experience
- Be a very hands-on tester who is comfortable across a whole range of functional testing including UAT, acceptance and system testing with tools like Fit, Fitnesse, Silk, Winrunner or any other automation tool
- Experience of participating in full life cycle development right from the requirements gathering and analysis phase
- Have worked on large, long term projects (more than 10 people, longer than 6 months)
- Enjoyment of working closely with developers, analysts and clients in a highly collaborative environment
- Exceptional communication skills
- An unrivalled passion for delivery
Also Highly Desirable
- Experience of creating test frameworks and strategy, choosing automated testing tools and creating testing standards
- Experience of, or interest in working with Open Source testing tools like Selenium and Sahi
- A knowledge of testing within an Agile development environment
- A background in OO development
- A track-record of innovation in testing
- Experience of working in an onsite, consultancy environment
So if you are interested, then click here to apply online. And just a quick reminder that ThoughtWorks offers Visa Sponsorship for candidates.
Lean: Go-Kart Exercise
Last week I attended the Lean Thinking And Practices For IT Leaders workshop organised by ThoughtWorks. There we had the presence of Mary and Tom Poppendieck, my colleague Jason Yip and two consultants from KM&T. One of the things that I really liked about it was that it wasn’t only driven by presentations, but also by a lot of practical exercises, so we could get a better feeling of the benefits of applying these thinking and practices. One of the exercises we did was the Go-Kart game.
How it works?
Two teams are created (alpha and beta), and each one has to split up into five groups with the given responsibilities: disassembly, transportation, assembly, observation and time-keeping. They are given the task to completely disassemble, transport and re-assemble a Go-Kart as quick as possible, in a safe manner, while the observer write notes about problem points. The whole process is done twice, so that you can run it once, analyse the process used, based on feedback provided by the observer, and think of ways to improve it, before running the second time.
First Attempt
In our first attempt, all we knew was that we had to split the team into five groups. We had no idea of the necessity of a detailed process, but doing all the phases as fast as possible. Vikky, our team leader, proposed the creation of a manual with the detailed steps needed to assemble the kart, to be used by the assembly team. And that’s what we did!
Our marks
Planing time: 10 minutes
Disassembling time: 5 minutes
Assembling time: 12 minutes
Total time: 14 minutes 20 seconds
Quality of delivered product: OK
Problem Points (Gathered by observers)
- The team took seven minutes to get organised and start doing something.
- No leadership nomination. Vikky, one of the team members, had to auto-niminate herself as the team leader.
- Disassembly group didn’t notice differences on the washers and on the bolts, causing uncertainty and waste of time in the assembly group.
- Bottleneck on the transportation of the parts from one station to another. No one from disassembly group to pick up the parts, making the transporter keep holding them, stopping the process flow.
- The components needed to assemble specific parts of the car were not delivered together, making the assembly group wait for the remaining ones.
- Some members in the assembly group were in a rush to finish fast and ignored the manual, resulting in some mistakes.
Second Attempt
Before starting the second attempt we got together to discuss the problem points, coming up with some ideas of improvements. Here they are:
Improvements
- We nominated people on both disassembly and assembly groups to be in charge of handing and picking up parts from the transporter.
- We decided to hand the parts related to each other in chunks, so that they could be assembled straight away, eliminating the time wasted waiting for remaining parts.
- We nominated specialists for roles such as assembling the wheels, etc.
- We added one more member to the transportation group, to get rid of the bottleneck.
Instead of spending a long time planning, we did it the agile way, highlighting only things we knew at the time, very quickly, and running through, spiking and checking if we were actually carrying out with the improvements, before doing the official attempt. We found some problems, adjusted to them and immediately got organised for the second attempt.
Our marks
Planing time: 10 minutes
Disassembling time: 1 minute 50 seconds
Assembling time: 2 minutes 33 seconds
Total time: 3 minutes 45 seconds
Quality of delivered product: OK

Click here to see some photos of our team during the exercise.
Conclusion
Lean advocates that you should pursue perfection when improving your process - aiming to reduce effort, time, space, cost and mistakes - and I learnt that this applies to any organisation, of any size. Thus, from the process used on this game, collaboration, self-organisation, rapid feedback contributed a lot to our improvement, helping us to eliminate waste.
So, what could you do for your organisation?
Take a step back, take a look at the big picture of how things work in your company and ask yourself questions such as: How do we deliver? Does it takes longer to test and deploy our system than to develop it? Who do we depend on to put the system onto production? What is causing a bottleneck? What could I do to change this scenario? Answer these questions (or others you make up) and think of improvements.
Hamcrest Out Of Test Code!
It’s been a while since I read some interesting posts showing creative uses of Hamcrest library out of test code. Since then I’ve been proscrastinating to implement my own version, trying strongly typed java delegates.
Thankfully this week I came across a nice API called hamcrest-collections. It uses Hamcrest to implement features such as select, reject, map, reduce and zip familiar from languages like Ruby and Python.
Selectors
Selectors can be used to select or reject items that matches a given Matcher, from any iterable object. It reminds me the Specification Pattern from Domain-Driven Design, which is also used for querying objects that satisfies defined specifications.
public static final Person john = new Person("John", 28);
public static final Person nicole = new Person("Nicole", 12);
public static final Person ryan = new Person("Ryan", 23);
public static final Person nathan = new Person("Nathan", 18);
public static final List list() {
return Arrays.asList(john, nicole, ryan, nathan);
}
The code below selects from the list of users defined above, the ones that are under twenty.
@Test
public void should_select_only_people_under_twenty_years_old() {
List users = Person.list();
Iterable underTwentyList = select(users, underAge(20));
assertThat(underTwentyList, hasItems(nicole, nathan));
assertThat(underTwentyList, not(hasItems(john, ryan)));
}
The code below rejects all the users that are under twenty.
@Test
public void should_reject_every_people_under_twenty_years_old() {
List users = Person.list();
Iterable aboveTwentyList = reject(users, underAge(20));
assertThat(aboveTwentyList, hasItems(john, ryan));
assertThat(aboveTwentyList, not(hasItems(nicole, nathan)));
}
Map and Reduce
Map is used to apply a function onto each item in any iterable object, whereas Reduce combines all these elements, applying a Reducer implementation. In our example, we map the timesTwo function, that doubles each element in the list, and then we reduce it by adding up all of them.
@Test
public void should_double_each_number_in_the_list_then_sum_all_of_them() {
List numbers = Arrays.asList(1, 2, 3);
MultiplyBy timesTwo = new MultiplyBy(2);
Iterable result = map(numbers, timesTwo);
assertThat(result, hasItems(2, 4, 6));
Integer sum = reduce(result, new Sum());
assertThat(sum, equalTo(12));
}
public class MultiplyBy implements Function{ private Integer factor; public MultiplyBy(Integer factor) { this.factor = factor; } public Integer apply(Integer number) { return (int)number * factor; } }
public class Sum implements Reducer{ public Integer apply(Integer first, Integer second) { return first + second; } }
Despite the bias created by some developers, that Hamcrest should not be used anywhere else but test code, specially after JUnit has defined it as its new matcher library, just ignore it and add these features to your runtime library, so that you can let your creativity drive you when developing. Get rid of “for” loops from your life! ![]()
2008 Retrospective

After reading posts from some friends I decided to write my 2008 retrospective, so there it go!
Personal Life
- First year married
- Moved to the land down under.
- Tried to go to the gym, but it still seems like I am better as an investor
Professional Life
- Joined ThoughtWorks Australia.
- Tried to post more often on my blog.
- Became a Certified Scrum Master Of The Universe!
- Projects: 4
- Conferences attended: JAOO Sydney
Learning
2009 Resolutions
Still haven’t planned properly what to do for 2009, the only thing for now is continuing learning Clojure, and understand more about applying Lean principles into software development.
Clojure: Integrating With Java
Currently I am learning Clojure. It is a functional programming language, but not a pure one, since you can both write code that share state (mutable) and also ones that doesn’t.
Why Clojure?
The main reason why I chose Clojure is its easy interoperability with Java, still one of the most used languages, bringing to it the power of Lisp. It’s fast, since the code is compiled, and it supplements some of Java’s weakness, such as the Collections framework and concurrent programming. It is pretty straightforward to write concurrent programs, everything is automatic, no manual lock management!
Integrating With Java
Importing classes
A single class:
(import java.util.List)
Multiple classes from the same package:
(import '(java.util List Set))
Creating instances
Using Java’s new keyword:
(new java.util.ArrayList) (new ArrayList) ; after importing
Assigning a new List to a Clojure variable:
(def list (new java.util.List)) -> #'user/list
Syntactic Sugar:
(ArrayList.)
Accessing fields
Static fields:
(. Math PI)
Syntactic Sugar:
Math/PI
Invoking methods
Static Methods
(.currentTimeMillis System)
Syntactic Sugar:
(System/currentTimeMillis)
Non-static Methods
(. list size) (. list get 0) ; returns the object stored at index 0
Syntactic Sugar:
(.size list)
Mixing Them All
Clojure provides a macro called memfn that makes possible execute Java methods as functions. So, for a list of String objects, if I want to make all of them upper-case, all I have to do is:
(map (memfn toUpperCase) ["a" "short" "message"])
The map function applies the function/method toUpperCase to each element in ["a" "short" "message"]
You can also use the bean function to wrap a Java bean in an immutable Clojure map.
(bean (new Person "Alexandre" "Martins"))
-> {:firstName "Alexandre", :lastName "Martins"}
Once converted, you can manipulate the new map using any of Clojure’s map functions, like:
(:firstName (bean (new Person "Alexandre" "Martins"))) -> Alexandre
The code above extracts the firstName key, originally from the Person object.
Retrospectives: Analogy For Developers
One day, while reading Esther Derby’s book, preparing for a retrospective session, I came across a great analogy between retrospective and development life-cycle:
While continuous builds, automated unit tests, and frequent demonstrations of working code are all ways to focus attention on the product and allow the team to make adjustments, retrospectives focus attention on how the team does their work and interacts.
Indeed it helps people improve practices and focus on teamwork. That’s why it is one of my favorite meetings.
Ping Pong Pairing: Even More Fun!
The agile software development practice I like the most, and at the same time, the one I find the most difficult is pair programming. Each individual has his/her own way of working, and characteristics such as motivation, engagement, habits, open-mindedness, and coding/design style varies a lot from individuals. Sometimes, to get a balance between these differences is quite hard. I am still not an expert in pair programming coaching, but I’ve been learning a lot on my current assignment.
And from this experience, it seems that clients are definitely more involved and amused when it comes pairing following the ping pong pattern.
Ping Pong Pattern
It happens when the developer 1 from a pair implements a test for a given feature and see it failing, then passes the keyboard to developer 2 who makes the test pass, do some refactoring on the code and implements another test, passing the keyboard back to developer 1 to do the same thing and continue until the feature is done.
Why Do We Like
- Challenge - Each time a developer writes a test for you to make it pass, it sounds like a challenge, then you do it and write another one, challenging him back.
- Dynamics - The worse thing is a developer that just hogs the keyboard, making you feel a useless. Ping pong pairing makes you swap keyboard more frequently.
- Engagement - Developers are much more engaged because they are constantly coding, not only observing.
- Fun - It is so much fun when you have all the above items together!
Martin Fowler: HumaneRegistry
Latest Martin Fowler’s post about HumaneRegistry mentions the first project I was involved working for ThoughtWorks. It was a SOA-Governance consulting with some development effort, and also some effort on harvesting information about services provided by different applications inside the organization, compiling and placing them on the wiki. The idea was to get both service builders and consumers to contribute, inputing information about the services they develop/consume aiming to build a solid service registry for all the services, with some highlighted features such as:
- Service description and what the user needs to use it.
- Who is the best person for the consumer to speak to, by looking the graph indicating who’s been contributing to the project.
- Who’s using it, by looking the graph indicating which applications has been invoking EJBs and consuming messages.
- And some other ones mentioned on Martin’s post.
This was such a rewarding experience to work with great professionals like Erik Dörnenburg and Halvard Skogsrud. And it was cool that Martin documented this on his bliki.
Black Cards (a.k.a. Evil Stories)
Are defined as tasks or features that represents something that needs to be fixed, because it represents a risk to the system in production (or going to).
Generally they represent acceptance criteria that was not defined during development. They should have higher priority over the other stories to be implemented.

Acceptance Tests With JBehave, Selenium & Page Objects
Since JBehave 2.0 was released in September, I’ve been using it on my current project to verify the acceptance criteria for the features we are implementing, ensuring that the web interface is following the right workflow, and is displaying the data as expected, as well as some other important elements.
What is JBehave?
JBehave is a framework for Behaviour-Driven Development, that allows customers and developers to work together more closely on features for the system. They get together to discuss and define a set of executable criteria (scenarios) for each of the features that will be used to determine if they are fully implemented or not. The cool thing is that the scenario execution produces an easy-to-read output, so that customers can keep track of the implementation status.
An Example
In this example, I’m not covering all the bits and pieces about writing and running acceptance tests with JBehave. If you want to see it in details, there’s a very good introduction article here. The intention is to show how we are doing it on my project, integrating with Selenium and using the Page Objects pattern.
New Feature
Suppose the customer wanted to provide exclusive content for the user of the website. For that, we would have to implement an authentication framework, so that we could guarantee that only registered users would access that content. So the story looks like this:
As an user I want to login into the website So that I can view the exclusive contents
Defining Scenarios
Scenario: Invalid Username Given the user is on the login page When the user types username wrong! And the user types password 123456 And clicks the login button Then the page should display Invalid Authentication message Scenario: Successful Login Given the user is on the login page When the user types username alexandre And the user types password 123456 And clicks the login button Then the user should be redirected to home page And the page should display welcome message to alexandre
Each scenario needs its own implementation, providing the necessary steps to be verified, in our case the LoginSteps class. Another improvement on version 2.0 is that it allows you to define multiple scenarios in a single file.
public class LoginScenarios extends Scenario {
public LoginScenarios() {
super(new LoginSteps());
}
}
Defining Steps (Integrating Selenium)
After defining the scenarios on the text file, it’s time to map each scenario step to its implementation. Once you start mapping them you will come across ones that are already mapped, and will realise that defining new scenarios is just a matter of combining existing steps.
Initially, for each step, we were extracting the code sniped from Selenium IDE record and placing into it. But it felt a bit clumsy, with code duplication in some spots. It quickly reminded me how hard it is to maintain a suite of tests when it starts evolve and there is not enough effort on refactoring. We wanted to avoid duplication and come up with a more elegant and reusable solution.
One day my friend Uday Rayala came up with the idea of using the Page Objects pattern for writing our acceptance tests, so that we could encapsulate the logic to interact and verify page state into these objects. The first time I heard about it was from Simon Stewart, when he was in Sydney for the JAOO conference. He said that they implemented WebDriver based on this pattern, and showed me some examples. Here is a definition, extracted from the WebDriver wikipage:
Within your web app’s UI there are areas that your tests interact with. A Page Object simply models these as objects within the test code. This reduces the amount of duplicated code and means that if the UI changes, the fix need only be applied in one place.
public class LoginSteps extends Steps {
@Given("the user is on the login page")
public void theUserIsOnTheLoginPage() {
LoginPage loginPage = new LoginPage();
loginPage.verifyPresenceOfUsernameAndPasswordFields();
loginPage.verifyPresenceOfLoginButton();
}
@When("the user types username $username")
public void theUserTypesUsername(String username) {
loginPage().typeUsername(username);
}
@When("the user types password $password")
public void theUserTypesPassword(String password) {
loginPage().typePassword(password);
}
@When("clicks the login button")
public void clicksTheLoginButton() {
loginPage().login();
}
@Then("the page should display $errorMessage message")
public void thePageShouldDisplayErrorMessage(String errorMessage) {
loginPage().verifyPresenceOfErrorMessage(errorMessage);
}
@Then("the user should be redirected to home page")
public void theUserShouldBeRedirectedToHomePage() {
HomePage homePage = new HomePage();
homePage.verifyPage();
}
@Then("the page should display welcome message to $user")
public void thePageShouldDisplayWelcomeMessage(String user) {
homePage().verifyPresenceOfWelcomeMessageTo(user);
}
private LoginPage loginPage() {
return (LoginPage) Page.current();
}
private HomePage homePage() {
return (HomePage) Page.current();
}
}

