Scaling: Local vs Full Vertical scaling

It’s funny, isn’t it? Everybody is still talking about ‘scaling agile’. A whole industry has been created on the premise that large companies need process structures to help them manage pushing very large projects through huge sets of development teams.

Luckily, the DevOps movement (and the continuous delivery movement, I’m not sure they’re really separate) happened early into that process, so in most of these large scale processes there’s at the very least lip service to the idea that quality needs to be high, and delivery needs to be automated, even if they don’t aim for continuous.

Unfortunately, most of the work on the other side of the workflow was not included. Even though a number of initiatives have started in the last five years to bring product, marketing and UX people more into the fold to really include the customer into the process, this is still a very rare occurrence.

This isn’t all that surprising, I suppose. The longer-term planning and significant coordination overhead is familiar and comforting. And the large organisations that start using LeSS, SAFe, etc., will actually be better off than they were before. They’ll deliver more predictably, they’ll get into production quicker and they will feel more in control. Not bad, actually.

But even though their products will be in the hands of customers somewhat faster, the feedback loops from their customers will still be too slow. And the people that should be the link to the customers, the people in Marketing, Sales and Product Management, are way too far from the action. Too far to get fast feedback from the customer directly, but also too far from development to start using all the possibilities of technology to get more information on that customer and their preferences.

We scale our development organizations but ignore the capacity of its customers to make use of it

We scale our development organizations but ignore the capacity of its customers to make use of it

The solution is, predictably, to bring those roles into the fold and create a combined team where marketeers, product manager, software developers, ux specialist, testers and operations people work together to deliver on business goals. We have already seen the game changing effects that occur when software developers, testers and operations truly combine their knowledge and efforts. This next step will have more impact, simply because the knowledge that is being combined in the team is much broader, and more directly linked to the customer.

There are new issues to resolve when we do this. Coordination on a product level needs to be done in a different way. And coordination on the level of the different areas of expertise also needs to be done in a different way. Much more thought needs to be put into matters of vision and strategy, and how those have to be communicated to the teams that are formed. Into how this translates into rewarding people. But we’ve solved those kinds of issues before, and we can tackle them again.

Stop trying to scale agile. Scale your organisation.

Specification By Example Training

On the 24 an 25 of May, my colleague and I organised and attended the Specification By Example course of Gojko Adzic at our company. We both very much appreciated Gojko’s book on the subject, and much of what he says fits very well with the style of dealing with requirements that I’ve used in the past. And takes it that much further.

As a trainer myself, it was very useful for me to see the excellent way Gojko has structured the training. He relies on a heavily participatory style, where the students take a very active roll. He specifically mentioned the book ‘Training from the Back of the Room’ as inspiration for this approach. In our own workshops we also try to keep audience interaction going throughout the day, and find it to be very effective in preventing sleepy students and getting stuck in theory. The reason this was doubly effective in this training is that many of the excercises Gojko gave us were techniques that are also effective for use when doing the things the training is about: facilitating communication on requirements and specifications.

I’ve listed some of the highlights for me below:

Diverge and Merge

Having recently listened to Michael Kennedy talk about Set Based Design seeing how the practice of ‘Diverge and Merge’ implements those principles within a single meeting was an eye-opener. The way this worked was that a problem or goal was posed, and the group was split into four smaller groups to work on a solution. An example of a problem was how to write good examples for a given feature.

We split-up, worked on the issue for a short period (20 minutes), and then centrally discussed the different solutions, and discussed what the best option would be. This would usually be “That one with some of the stuff from that other one included”. Doing this for discussion on design, requirements or code can be easily done in the normal one hour timeframe for a meeting and give much better and quicker results than the usual sitting around a table. Also, through the mechanism of separate groups, it automatically alleviates the influence of one very vocal participant dominating the group.

Process

There was plenty of talk about process. About who should be involved, how much time to spend in different situations, and when all this should happen. All good stuff, but for me mostly familiar. Someone new to the material would certainly pick up all that was needed to understand how to approach the requirements process for an agile project.

One interesting observation about Gojko’s approach is that he is very careful not to use any Agile of Lean terminology. His approach is obviously related to the one used in Kanban, and he repeatedly mentioned the Theory of Constraints: he stated that he preferred to guide customers step-by-step to solve their most pressing problems, without using a specific methodology to do so. Of course, what you then end-up with is very Lean and Kanban looking and feeling…

Examples

Naturally, in a course called ‘Specification by Example’, a lot of attention was given to specifying examples! This, also, was approached in a participatory fashion. We got handed a stack of specifications, and were asked to rate for helpfulness to support (separately) Shared Understanding, Test and Documentation. Though there were some differences in how we scored the specs on those separate measures, there was mostly agreement on what are good specs, and what… less so.

Another Diverge’n’Merge was used to let us try to determine the qualities in the specs that we were given that contributed to the spec being either good or bad. This was followed by a nice overview by Gojko, which contained everything we found, and a few we didn’t.

What makes a good spec, and what will make you get shot by angry developers

What makes a good spec, and what will make you get shot by angry developers

We then continued by taking one of the given bad specifications, and (again) splitting into three teams to create a version that would be better.

Diverged Specs

This exercise gave us some nice insights into different ways to solve this problem, and a nice confrontation with some of our automatic responses. Usually, fewer examples was good, but the right ones. And for me specifically: splitting was good, but not too far. I tend to try and make problems smaller, but in this case splitting too far made this problem harder to solve.

Effect Mapping

The last exercise (and I haven’t discussed them all, of course) that we did was the one I thought was most impressive: Effect Mapping. Effect mapping is a process to go from a goal or vision all the way to what to do to reach that goal. Gojko has recently released a ‘beta’ version of a short book about Effect Mapping on his website.

I found enough of interest to talk about on the subject of effect mapping that I’ll be writing a separate post on it, linked with some Lean Startup principles and Hoshin Kanri. Soon:-)

Our Effect Map

For now, the short description (again, read Gojko’s booklet for the full explanation) is that effect mapping is a joined Mind Mapping exercise where different levels of the mind-map are the answers to different questions:

  • Why? (The Goal)
  • Who? (Who can have a role in reaching that goal; Or preventing it)
  • How? (In what way can they help, business activities)
  • What? (What are the concrete software features to make; Or non-software actions to take)

By making the goal specific, and measurable, it then becomes possible to not only weigh the different possible ways that contribute to that goal and prioritise them, but also to verify if the goal was actually reached. On the inevitable question about making business goals measurable, the answer given was a reference to the book ‘How to measure anything‘, along with some choice examples.

All in all this was a great training, which for me resulted in some very powerful new tools to use in handling requirements at all levels.

XP is Classic Rock

A while back I had a little fun comparing Agile to Rock’n’Roll. It’s still one of my favourite posts, and after my recent talk on the benefits of TDD, I got the idea that the best follow-up on that is something about the XP practices.

Test Driven Development with Bonnie Riatt

The first artist that came up was Bonnie Riatt. This is mostly because Ron Jeffries has mentioned her a few times on the Scrum Development mailing list, and since that picture above is from his site, I figure I owe it to him. Oh, and it’s pretty good music!

She sings ‘I Will Not Be Broken‘, which is as good a summary of Test First development as one could wish for. And if you take into account lines such as ‘But I know where I’m not going‘, and ‘Pull me round; Push me to the limit’, then it’s perfectly clear we’re going through that TDD process cycle of Red, Green, Refactor in as small a steps as possible. Isn’t it?

Pair Programming with Aerosmith / The Beatles

I already mentioned ‘Come Together‘ in the last post, and to be honest, I can’t think of a better Pair Programming song. It does bring with it some of the oft heard objections to pairing, with ‘Hold you in his arms till you can feel his disease‘ being a succinct summary. These things have to be overcome, but you’ll end up with a classic that is covered by practically everyone. I’m going for the Aerosmith version, as their guitar work shows the advantages of having two great practitioners working together…

A great runner up was ‘Let Me Share The Ride‘, by The Black Crowes. All about how sharing the ride can be done with someone who isn’t a burden…

Refactoring with Eric Clapton

So how about Refactoring? Well, refactoring is all about removing duplication. There are many songs about duplicitive women and men, talking about how they’ve been done wrong, but apart from having a completely different meaning, I’d also have to save those for a special post about management practices. A much more suitable song is the classic ‘Double Trouble‘ blues song, which you can see below in a marvellous version by Eric Clapton together with Steve Winwood. This song fits so well because it reminds the young programmer of the dangers that duplication in code brings. ‘I have no job, laid of and I’m having Double Trouble

Simple Design with The Ramones / The Doors

Simple Design is not simple to do. We all have a strong tendency to try to take into account all kind of possible future scenarios when writing code. So the advice that comes out of the The Doors song ‘Take it as it comes’ is very apt. I’ve selected a cover version by The Ramones here, but the central message is the same: “Take it easy baby, take it as it comes. Don’t move too fast if you want your love to last”. Of course, read ‘code’ for ‘love’  there, but that should be automatic for any kind of real Craftsman…

Collective Code Ownership with The Red Hot Chili Peppers

Moving on from there we go on to the circle that deals with wider team alignment. It would be easy to slip in the ‘Internationale‘ here, but that really doesn’t do this practice justice. Another thought was ‘You Don’t Own Me’ by Dusty Springfield, but it really didn’t fit into the classic rock theme, and is much more about not being allowed to access the… object under discussion.
The answer was, of course, found with the Red Hot Chili Peppers song ‘Give It Away‘! Not only do they  know that sharing the code makes everyone wiser: “Realize I don’t want to be a miser;
Confide with sly you’ll be the wiser”, but they know that this practice is crucial to working Agile:
Lucky me swimmin’ in my ability
Dancin’ down on life with agility

Continuous Integration with Bruce Springsteen

Of course, you can’t have collective ownership without a good Continuous Integration system. This one is easy, ’cause that code is ‘Born to Run’!

Customer Tests with Led Zeppelin

Working closely with your customer is the best way to ensure that you’re building the right thing. And having the customer closely involved with defining the acceptance test is the answer to avoiding the dreaded ‘Communication Breakdown’ that has left so many project is shambles:
Communication breakdown, it’s always the same
Havin’ a nervous breakdown, a-drive me insane

Sustainable Pace with Queen

People who know me know I can’t resist a good Queen song. This one emphasises precisely the opposite of what we want, but a negative test case can be very effective at communicating the desired functionality, can’t it? With ‘The Show Must Go On‘, we are confronted with all the dysfuction we find when teams push too hard to deliver impossible projects. Working in empty offices after everyone else has gone home, trying to find that last bug before it’s ready for production:
Empty spaces – what are we living for
Abandoned places – I guess we know the score
On and on, does anybody know what we are looking for…
The classical heroic programmer, working as an unsung (until now!) hero:
Another hero, another mindless crime
Behind the curtain, in the pantomime
Hold the line, does anybody want to take it anymore
 
And that’s it, for this post. I really wanted to get into the XP Metaphor practice as well, but it ended up with me getting headaches trying to understand the hidden meanings of songs like Stairway to Heaven, and Hotel California. Better not go there…

Success

I recently wrote here about the benefits of failure. One of my recent failures reminded me about the importance of success. I thought that to be nicely circular enough to warrant a new post!

You see, while it’s important to embrace failure – how else are you going to learn? – it is just as important that you don’t set yourself up for failure too often.

One very popular way that agile teams do set themselves up for failure is by taking in too much work in a sprint. True, this wouldn’t be too bad if failure was better accepted: we’d just recognise we were not going to make it, and drop some stories from the sprint. And learn to take in less work for the next sprint. But this is not what happens. What happens is that we try to succeed anyway. And that we don’t stick to our own rules of work when doing so. So we work late (making the whole concept of velocity useless, a way I missed in my previous list of ways to do that), or we reduce quality. Or both, usually.

But here I am getting stuck on failure again. We were talking about success!

When a team is starting out with agile, they are bound to run into many issues. The short feedback cycles ensure that they’ll be confronted with all kinds of ways in which their current process is suboptimal. This is not always a nice experience and if it is not mitigated by successes in improving matters, a team can become discouraged, and let their agile experiment die off.

In the recent situation I was referring to, this is what happened. The team had quite a good grasp of what was wrong in their process. In fact, during our initial ‘Scrum Introduction’ workshop some clear issues came up. We always do such a workshop in the form of an extended retrospective, interlaced with some theory and games. In that retrospective part, one of the top issues that came up was that of team stability. Teams were reconfigured for every project, but people were also regularly reassigned in a running project. Some further questioning quickly unearthed frequent quality issues in both requirements and code, causing people to be needed for projects in trouble after release or in ‘user acceptance testing’.

Note: UAT is not supposed to be a process where your users are the first people to test your code!

So, knowing that the underlying issue was one of quality we started by focusing on quality. Can’t go wrong, right? But the feedback loop from the quality issues to the ‘reassignment’ issue was very long. Also, since the reassignment was to other teams, that were already in trouble, the improvements we could make had no possible influence on the stability of the team. And so, when during a planning meeting for the third sprint the third person was ‘temporarily’ moved to another team, we figured out that we had set this team up to fail.

So what should we have done? ‘We’ being me as a coach, or the team involved in a – management approved – change process. We should have gone to the company management before starting any sprints (so right after that retro/workshop) and asked for their support, guaranteeing that this team would be left intact for the duration of the project. We should at the same time have advised working on the widespread quality issues.  I should add that it would have been exceedingly unlikely that that broader support would have been given, but then at least it would have saved everyone some work and more importantly, disappointment.

The lesson here is that when you find your impediments, you should make them visible to the wider environment, and make sure that you actively work to remove them in as short a time as is possible. This most definitely includes involving management, and will underline their support for the agile transition in progress. Not doing that is denying the team a chance to experience success. And that’s a great way to sabotage your change process.

On Discipline, Feedback and Management

Change is hard. If we know that about 80% of organisational change programs fail, then it’s easy to appreciate just how hard. Why is that? And, more importantly, what can we do to make it easier?

Recently, I saw a tweet come by from Alan Shalloway. He wrote that, back in the days, people were saying: Waterfall (though they didn’t call it that, back then, I think) is fine, people are just not doing it right. All we need is apply enough discipline, and a little common sense, and it will work perfectly! I think Alan was commenting on an often heard sound in the Agile community about failing Scrum adoptions: You’re just not doing it right! You need to have more discipline!

This is, actually, a valid comment. In fact, both views are valid. On the one hand, just saying that people are not doing it right is not very helpful. Saying you need to be more disciplined is certainly not helpful. (Just look at the success rate of weight loss programs (or abstinence programs against teen pregnancies).  Change is hard, because it requires discipline. Any process requires discipline. The best way to ensure a process is successfully adopted is to make sure the process supports discipline. This is, again, hard.

This post talks about discipling. About how it can be supported by your process. About how it’s often not supported for managers in Agile organisations, and then of course how to ensure that management does get that kind of support in their work.

In Support Of Discipline

Take a look at Scrum, throw in XP for good measure, and let’s have a look at what kind of discipline we need to have, and how the process does (or does not!) support that discipline.

Agile Feedback Loops

Agile Feedback Loops

The eXtreme Programming practices often generate a lot of resistence. Programmers were, and are, very hesitant in trying them out, and some require quite a bit of practice to do well. Still, most of these practices have gained quite a wide acceptance. Not having unit-testing in place is certainly frowned upon nowadays. It may not be done in every team, but at least they usually feel some embarrassment about that. Lack of Continuous Integration is now an indication that you’re not taking things seriously.

Working structurally using TDD, and Pair Programming, have seen slower adoption.

Extreme Programming Practices

Extreme Programming Practices from XProgramming.com

If we look at some practices from Scrum, we can see a similar distribution of things that are popularly adopted, and some things that are… less accepted.  The Daily Stand-Up, for instance can usually be seen in use, even in teams just getting started with Scrum. Often, so it the Scrum Board. The Planning Meeting comes next, but the Demo/Review and certainly the Retrospective, are much less popular.

Why?

All of these practices require discipline, but some require more discipline than others. What makes something require less discipline?

  • It’s easy!
  • Quick Feedback: It obviously and quickly shows it’s worth the effort
  • Shared Responsibility: The responsibility of being disciplined is shared by a larger group

Let’s see how this works for some of the practices we mentioned above. The Daily Stand-Up, for instance, scores high on all three items. It’s pretty easy to do, you do it together with the whole team, and the increased communication is usually immediately obvious and useful. Same for the Scrum Board.

The Planning Meeting also scores on all three, but scores lower for the first two. It’s not all that easy, as the meetings often are quite long, especially at the start. And though it’s obvious during the planning meeting that there is a lot of value in the increased communication and clarity of purpose, the full effect only becomes apparent during the course of the sprint.

The Demo is also not all that easy, and the full effect of it can take multiple sprints to become apparent. Though quick feedback on the current sprint will help the end-result, and the additional communication with stakeholders will benefit the team in the longer run, these are mostly advantages over the longer term. To exacerbate this effect, responsibility for the demo is often pushed to one member of the team (often the scrum master), which can make the rest of the team give it less attention than is optimal.

Retrospectives are, of course, the epitome of feedback. Or they should be. Often, though, this is one of the less successful practices in teams new to Scrum. The reasons for that are surprisingly unsurprising: there is often no follow-up on items brought forward in the retrospective (feedback on the feedback!), solving issues is not taken up as a responsibility for the whole team, and quite a few issues found are actually hard to fix!

The benefits of Continuous Integration are usually quite quickly visible to a development team. Often, they’re visible even before the CI is in use, as many teams will be suffering from many ‘integration issues’ that come out late in the process. It’s not all that hard to set-up, and though one person can set it up, ‘not breaking the build’ is certainly shared by the whole team.

Unit testing can be very hard to get started with, but again the advantages *if* you use it are immediately apparent, and provide value for the whole team. Refactoring. Well, anyone who has refactored a bit of ugly code, can attest how nice it feels to clean things up. In fact, in the case of refactoring the problem is often ensuring that teams don’t drop everything just to go and refactor everything… Still, additional feedback mechanisms, like code statistics using Sonar or similar tools, can help in the adoption of code cleaning.

Pairing shows quick feedback, and is shared by at least one other person, but it’s often very hard, and has to deal with other things: management misconceptions. We’ll talk about that a little later. TDD‘s advantages are more subtle than just testing at all. So the benefit is less obvious and quick. It’s also a lot harder, and has no group support. These practices do reinforce each other, testing, TDD, and refactoring are easier to do if done together, pairing.

So we can see at least some correlation between adoption and the way a practice supports discipline. This makes a lot of sense: The easier something is to do, the more obvious its benefits, and the more shared its burdens by a group, the better is supports its users, and the more it is adopted.

Feedback within the team

One large part of this is: feedback rules. This is not a surprise for most Agile practitioners, as it’s one of the bases of Agile processes. But it is good to always keep in mind: if you want to achieve change, focus on supporting it with some form of feedback. One form of feedback that is used e.g. Scrum and Kanban, is the visualisation of the work. Use of a task board, or a Kanban board, especially a real, physical one, has a remarkable effect on the way people do their work. It’s still surprising to me how far the effects of this simple device go in changing behaviour in a team.

Seeing how feedback and shared responsibility help in adoption of practices within the team, we could look at the various team practices and find ways to increase adoption by increasing the level of feedback, or sharing the responsibility.

The Daily Stand-Up can be improved by emphasising shared responsibility: rotating the chore of updating the burn-down, ensuring that there’s not a reporting-to-scrum-master feel by passing around a token.

The Planning Meeting could be made easier by using something different from Planning Poker if many stories need to be estimated, or this estimation could be done in separate ‘Grooming’ sessions. Feedback could be earlier by ensuring Acceptance Criteria are defined during the planning meeting (or before), so we get feedback for every story as soon as it gets picked up. Or we can stop putting hourly estimates on tasks to make the meeting go by quicker.

Retrospectives could be improved by creating a Big Visual Improvement backlog, and sticking it to the wall in the team room. And by taking the top item(s) from that backlog into the next sprint as work for the whole team to do. If it’s a backlog, we might as well start splitting those improvements up into smaller steps, to see if we can get results sooner.

All familiar advice for anyone that’s been working Agile! But how about feedback on the Agile development process as it is experienced by management?

Agile management practices

Probably the most frequently sited reason for failure of Agile initiatives, is lack of support from management. This means that an Agile process requires changes in behaviour of management. Since we’ve just seen that such changes in behaviour require discipline, we should have a look at how management is supported in that changed behaviour by feedback and sharing of responsibility.

First though, it might be good to inventory what the recommended practices for Agile Managers are. As we’ve seen, Scrum and XP provide enough guidance for the work within the team. What behaviour outside the team should they encourage? There’s already a lot that’s been written about this subject. This article by Lyssa Adkins and Michael Spayd , for instance, gives a high-level overview of responsibilities for a manager in an Agile environment. And Jurgen Apello has written a great book about the subject. For the purposes of this article, I’ll just pick three practices that are fairly concrete, and that I find particularly useful.

Focus on quality: As was also determined to be the subject requiring the most attention at the 2011 reunion of the writing of the Agile Manifesto, technical excellence is a requirement for any team that want to be Agile (or just be delivering software…) for the long term. Any manager that is dealing with an Agile team should keep stressing the importance of quality in all its forms above speed. If you go for quality first, speed will follow. And the inverse is also true: if you don’t keep quality high, slowing down until nothing can get done is assured.

Appreciate mistakes: Agile doesn’t work without feedback, but feedback is pretty useless without experimentation. If you want to improve, you need to try new things all the time. A culture that makes a big issue of mistakes, and focuses on blame will smother an Agile approach very quickly.

Fix impediments: The best way to make a team feel their own (and their works)  importance is to take anything they consider getting in the way of that very seriously. Making the prioritised list of impediments that you as a manager are working on visible, and showing (and regularly reporting) on their progress is a great way of doing that.

Note that I’ve not talked about stakeholder management, portfolio management, delivering projects to planning, or negotiating with customers. These are important, but are more in the area of the Product Owner. The same principles should apply there, though.

Let’s see how these things rate on ease, speed of feedback, and shared responsibility.

Focus on Quality. Though stressing the importance of quality to a team is not all that difficult, I’ve noticed that it can be quite difficult to get the team to accept that message. Sticking to it, and acting accordingly in the presence of outside pressures can be hard to do. Feedback will not be quick. Though there can be improvements noticeable within the team, from the outside a manager will have to wait on feedback from other parties (integration testing, customer support, customers directly, etc.) If the Agile transition is a broad organisational initiative, then the manager can find support and shared responsibility from his peers. If that’s not the case, the pressure from those peers could be in quite a different direction…

Appreciate mistakes. Again, this practice is one in which gratification is delayed. Some experiments will succeed, some will fail. The feedback from the successful ones will have to be enough to sustain the effort. The same remarks as above can be given with regards to the peer support. Support from within a team, though less helpful than from peers, can be a positive influence.

Fix impediments. The type of impediments that end on a manager’s desk are not usually the easy-to-fix ones. Still, the gratification of removing problems, make this a practice well supported by  quick feedback. And there is usually both gratitude from the team and respect for action from peers.

We can see that these management practices are much less supported by group responsibility and quick feedback loops. This is one of the reasons why managers often are the place where Agile transitions run into problems. Not because of lack of will (we all lack sufficient willpower:-), but because any change requires discipline, and discipline needs to be supported by the process

Management feedback

If we see that some important practices for managers are not sufficiently supported by our process, then the obvious question is going to be: how do we create that support?

We’ve identified two crucial aspects of supporting the discipline of change: early feedback, and shared responsibility. Both of those are not natural fits in the world of management. Managers usually do not work as part of a closely knit team. They may be part of a management team, but the frequency and intensity of communication is mostly too low to have a big impact. Managers are also expected to think of the longer term. And they should! But this does make any change more difficult to sustain, since the feedback on whether the change is successful is too far off.

By the way, if that feedback is that slow, the risk is also that change that is not  successful is kept for too long. That might be even worse…

When we talk about scaling Agile, we very quickly start talking about things such as the (much debated) Scrum of Scrums, ‘higher level’ or ‘integration’ stand-up meetings, Communities of Practice, etc. Those are good ideas, but are mostly seen as instruments to scale scrum to larger projects, and align multiple teams to project goals (and each other).  These practices help keep transparency over larger groups, but also through hierarchical lines. They help alignment between teams, by keeping other teams up-to-date of progress and issues, and help arrange communication on specialist areas of interest.

What I’m discussing in this post seems to indicate that those kind of practices are not just important in the scenario of a large project scaled over multiple teams, but are just as important for team working separately and their surrounding context.

So what can we recommend as ideas to help managers get enough feedback and support to sustain an Agile change initiative?

Work in a team. Managers need the support and encouragement (and social pressure…) that comes of working in a team context as much as anyone. This can partly be achieved by working more closely together within a management team. I’ve had some success with a whole C-level management team working as a Scrum team, for instance.

Be close to the work. At the same time, managers should be more directly following the work on the development teams. Note that I said ‘following’. We do not want to endanger the teams self-organization. I think a manager should be welcome at any team stand-up, and should also be able to speak at one. But I do recognise that there are many situations where this has led to problems, such as undue pressure being put on a team. A Scrum of Scrums, of multi-level stand-up approach can be very effective here. Even if there’s only one team, having someone from the team talk to management one level up daily can be very effective.

Visualise management tasks. Managers can not only show support for the transition in this way, they can immediately profit from it themselves. Being very visible with an impediment backlog is a big help, both to get the impediments fixed, and showing that they’re not forgotten. Starting to use a task board (or Kanban, for the more advanced situations) for the management team work is highly effective. And if A3 sheets are being put on the wall to do analysis of issues and improvement experiments, you’re living the Agile dream…

Visualise management metrics. Metrics are always a tricky subject. They can be very useful, are necessary, but can also tempt you to manage them directly (Goodhart’s Law). Still, some metrics are important to managers, and those should be made important to the teams they manage. Visualising is a good instrument to help with that. For some ideas read Esther Derby’s post on useful metrics for Agile teams. Another aspect of management, employee satisfaction, could be continuously visualised with Henrik Kniberg’s Happiness Matrix, or Jim Benson’s refinement of that.

A Cucumber Experiment

Having used the GildedRose recently as the subject of a coding dojo, I thought it would also make an interesting subject for some experimentation with Cucumber. Cucumber is a tool that allows you to use natural language to specify executable Acceptance Tests. The GildedRose exercise, originally created by Bobby Johnson, can be found on github, in both C# (the original), and Java (my copy). This code kata is a refactoring assignment, where the requirements are given together with a piece of existing code and the programmer is expected to add some functionality. If you take one look at that existing code, though, you’ll see that you really need to clean it up before adding that extra feature:

    public static void updateQuality()
    {
        for (int i = 0; i < items.size(); i++)
        {
            if ((!"Aged Brie".equals(items.get(i).getName())) && !"Backstage passes to a TAFKAL80ETC concert".equals(items.get(i).getName()))
            {
                if (items.get(i).getQuality() > 0)
                {
                    if (!"Sulfuras, Hand of Ragnaros".equals(items.get(i).getName()))
                    {
                        items.get(i).setQuality(items.get(i).getQuality() - 1);
                    }
                }
            }
            else
            {
                if (items.get(i).getQuality() < 50)
                {
                    items.get(i).setQuality(items.get(i).getQuality() + 1);

                    if ("Backstage passes to a TAFKAL80ETC concert".equals(items.get(i).getName()))
                    {
                        if (items.get(i).getSellIn() < 11)
                        {
                            if (items.get(i).getQuality() < 50)
                            {
                                items.get(i).setQuality(items.get(i).getQuality() + 1);
                            }
                        }

                        if (items.get(i).getSellIn() < 6)
                        {
                            if (items.get(i).getQuality() < 50)
                            {
                                items.get(i).setQuality(items.get(i).getQuality() + 1);
                            }
                        }
                    }
                }
            }

            if (!"Sulfuras, Hand of Ragnaros".equals(items.get(i).getName()))
            {
                items.get(i).setSellIn(items.get(i).getSellIn() - 1);
            }

            if (items.get(i).getSellIn() < 0)
            {
                if (!"Aged Brie".equals(items.get(i).getName()))
                {
                    if (!"Backstage passes to a TAFKAL80ETC concert".equals(items.get(i).getName()))
                    {
                        if (items.get(i).getQuality() > 0)
                        {
                            if (!"Sulfuras, Hand of Ragnaros".equals(items.get(i).getName()))
                            {
                                items.get(i).setQuality(items.get(i).getQuality() - 1);
                            }
                        }
                    }
                    else
                    {
                        items.get(i).setQuality(items.get(i).getQuality() - items.get(i).getQuality());
                    }
                }
                else
                {
                    if (items.get(i).getQuality() < 50)
                    {
                        items.get(i).setQuality(items.get(i).getQuality() + 1);
                    }
                }
            }
        }
    }

Having gone through the exercise a few times, I already had a version lying around that had the requirements implemented as a bunch of junit regression tests, and some real unit tests for my implementation, of course. A good starting point to get going with Cuke, though in many real-life situations I’ve found that those regression tests are not available…

Adding Cucumber to the maven build

To prepare for the use of Cucumber, I first had to set it up so that I had all the dependencies for cucumber, and have it run in the maven integration-test phase. The complete Maven pom.xml is also on GitHub.

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>GildedRoseJava</groupId>
    <artifactId>GildedRoseJava</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.8.2</version>
            <type>jar</type>
            <scope>test</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.picocontainer</groupId>
            <artifactId>picocontainer</artifactId>
            <version>2.10.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>cuke4duke</groupId>
            <artifactId>cuke4duke</artifactId>
            <version>0.4.4</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <repositories>
        <repository>
            <id>codehaus</id>
            <url>http://repository.codehaus.org</url>
        </repository>
        <repository>
            <id>cukes</id>
            <url>http://cukes.info/maven</url>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>cukes</id>
            <url>http://cukes.info/maven</url>
        </pluginRepository>
    </pluginRepositories>
    <build>
        <plugins>
            <plugin>
                <groupId>cuke4duke</groupId>
                <artifactId>cuke4duke-maven-plugin</artifactId>
                <configuration>
                    <jvmArgs>
                        <jvmArg>
                            -Dcuke4duke.objectFactory=cuke4duke.internal.jvmclass.PicoFactory
                        </jvmArg>
                        <jvmArg>-Dfile.encoding=UTF-8</jvmArg>
                    </jvmArgs>
                    <!-- You may not need all of these arguments in your
          own project. We have a lot here for testing purposes... -->
                    <cucumberArgs>
                        <cucumberArg>--backtrace</cucumberArg>
                        <cucumberArg>--color</cucumberArg>
                        <cucumberArg>--verbose</cucumberArg>
                        <cucumberArg>--format</cucumberArg>
                        <cucumberArg>pretty</cucumberArg>
                        <cucumberArg>--format</cucumberArg>
                        <cucumberArg>junit</cucumberArg>
                        <cucumberArg>--out</cucumberArg>
                        <cucumberArg>${project.build.directory}/cucumber-reports</cucumberArg>
                        <cucumberArg>--require</cucumberArg>
                        <cucumberArg>${basedir}/target/test-classes</cucumberArg>
                    </cucumberArgs>
                    <gems>
                        <gem>install cuke4duke --version 0.3.2</gem>
                    </gems>
                </configuration>
                <executions>
                    <execution>
                        <id>run-features</id>
                        <phase>integration-test</phase>
                        <goals>
                            <goal>cucumber</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Adding a Feature

To start with cucumber, you create a feature file that contains a Feature, which is expected to be in the User Story schema, and contains all the Acceptance Tests for that story in the Gherkin format.

The feature file is placed in the {$project.root}/features directory. The Story looks as follows:

Feature: Quality changes with sell-in date Feature
         In order to keep track of quality of items in stock
         As a ShopKeeper
         I want quality to change as the sell-in date decreases

A Scenario

This doesn’t do anything, until you start adding some scenarios, which can be seen as the acceptance criteria for the story/feature. For now, if you do

mvn integration-test

you’ll get confirmation that Cucumber has found your feature, and that there were no test scenarios to run:

[INFO] Code:
[INFO]
[INFO] Features:
[INFO]   * features/quality_decrease.feature
[INFO] Parsing feature files took 0m0.111s
[INFO]
[INFO] Code:
[INFO]   * /home/wouter/data/eclipse/kata/GildedRoseGitHub/target/test-classes/org/geenz/gildedrose/BackstagePassStoreKeepingItemTest.class
[INFO]   * /home/wouter/data/eclipse/kata/GildedRoseGitHub/target/test-classes/org/geenz/gildedrose/GildedRoseRegressionTest.class
[INFO]   * /home/wouter/data/eclipse/kata/GildedRoseGitHub/target/test-classes/org/geenz/gildedrose/GildedRoseTest.class
[INFO]   * /home/wouter/data/eclipse/kata/GildedRoseGitHub/target/test-classes/org/geenz/gildedrose/ImmutableItemTest.class
[INFO]   * /home/wouter/data/eclipse/kata/GildedRoseGitHub/target/test-classes/org/geenz/gildedrose/ItemFactoryTest.class
[INFO]   * /home/wouter/data/eclipse/kata/GildedRoseGitHub/target/test-classes/org/geenz/gildedrose/StoreKeepingItemTest.class
[INFO]   * /home/wouter/data/eclipse/kata/GildedRoseGitHub/target/test-classes/org/geenz/gildedrose/cucumber/BasicFeature.class
[INFO]
[INFO] Feature: Quality changes with sell-in date Feature
[INFO]   In order to keep track of quality of items in stock
[INFO]   As a ShopKeeper
[INFO]   I want quality to change as the sell-in date decreases
[INFO]
[INFO] 0 scenarios
[INFO] 0 steps
[INFO] 0m0.062s

Now, let’s add a scenario, let’s say a scenario for the basic situation of quality decreasing by one if the sell-in date decreases by one:

Feature: Quality changes with sell-in date Feature
        In order to keep track of quality of items in stock
        As a ShopKeeper
        I want quality to change as the sell-in date decreases

        Scenario: Decreasing Quality of a Basic Item
                Given a Store Keeping Item with name "+5 Dexterity Vest"
                And a sellIn date of 5
                And a quality of 7
                When the Item is updated
                Then the sellIn is 4
                And the quality is 6

There’s a few things to notice here. First of all, this is readable. This scenario can be read by people that have no programming experience, and understood well if they have some knowledge of the domain of the application. That means that scenarios like this one can be used to talk about the requirements/expected behaviour of the application. Second is that this is a Real Life example of the workings of the application. Making it a specific example, instead of a generic rule, makes the scenario easier to understand, and thus more useful as a communication device.

Glue

So what happens when we try to run the integration-test phase again? Will we magically see this scenario work? Well, no, there’s still some glue to provide, but we do get some help with that:

[INFO] Code:
[INFO]
[INFO] Features:
[INFO]   * features/quality_decrease.feature
[INFO] Parsing feature files took 0m0.077s
[INFO]
[INFO] Code:
[INFO]   * /home/wouter/data/eclipse/kata/GildedRoseGitHub/target/test-classes/org/geenz/gildedrose/BackstagePassStoreKeepingItemTest.class
[INFO]   * /home/wouter/data/eclipse/kata/GildedRoseGitHub/target/test-classes/org/geenz/gildedrose/GildedRoseRegressionTest.class
[INFO]   * /home/wouter/data/eclipse/kata/GildedRoseGitHub/target/test-classes/org/geenz/gildedrose/GildedRoseTest.class
[INFO]   * /home/wouter/data/eclipse/kata/GildedRoseGitHub/target/test-classes/org/geenz/gildedrose/ImmutableItemTest.class
[INFO]   * /home/wouter/data/eclipse/kata/GildedRoseGitHub/target/test-classes/org/geenz/gildedrose/ItemFactoryTest.class
[INFO]   * /home/wouter/data/eclipse/kata/GildedRoseGitHub/target/test-classes/org/geenz/gildedrose/StoreKeepingItemTest.class
[INFO]   * /home/wouter/data/eclipse/kata/GildedRoseGitHub/target/test-classes/org/geenz/gildedrose/cucumber/BasicFeature.class
[INFO]
[INFO] Feature: Quality changes with sell-in date Feature
[INFO]   In order to keep track of quality of items in stock
[INFO]   As a ShopKeeper
[INFO]   I want quality to change as the sell-in date decreases
[INFO]
[INFO]   Scenario: Decreasing Quality of a Basic Item               # features/quality_decrease.feature:6
[INFO]     Given a Store Keeping Item with name "+5 Dexterity Vest" # features/quality_decrease.feature:7
[INFO]     And a sellIn date of 5                                   # features/quality_decrease.feature:8
[INFO]     And a quality of 7                                       # features/quality_decrease.feature:9
[INFO]     When the Item is updated                                 # features/quality_decrease.feature:10
[INFO]     Then the sellIn is 4                                     # features/quality_decrease.feature:11
[INFO]     And the quality is 6                                     # features/quality_decrease.feature:12
[INFO]
[INFO] 1 scenario (1 undefined)
[INFO] 6 steps (6 undefined)
[INFO] 0m0.221s
[INFO]
[INFO] You can implement step definitions for undefined steps with these snippets:
[INFO]
[INFO] @Given ("^a Store Keeping Item with name \"([^\"]*)\"$")
[INFO] @Pending
[INFO] public void aStoreKeepingItemWithName+5DexterityVest_(String arg1) {
[INFO] }
[INFO]
[INFO] @Given ("^a sellIn date of 5$")
[INFO] @Pending
[INFO] public void aSellInDateOf5() {
[INFO] }
[INFO]
[INFO] @Given ("^a quality of 7$")
[INFO] @Pending
[INFO] public void aQualityOf7() {
[INFO] }
[INFO]
[INFO] @When ("^the Item is updated$")
[INFO] @Pending
[INFO] public void theItemIsUpdated() {
[INFO] }
[INFO]
[INFO] @Then ("^the sellIn is 4$")
[INFO] @Pending
[INFO] public void theSellInIs4() {
[INFO] }
[INFO]
[INFO] @Then ("^the quality is 6$")
[INFO] @Pending
[INFO] public void theQualityIs6() {
[INFO] }
[INFO]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 9.500s
[INFO] Finished at: Fri Sep 16 14:27:29 CEST 2011
[INFO] Final Memory: 5M/106M
[INFO] ------------------------------------------------------------------------

Ok! The build is successful, the new scenario is found, but apparently ‘undefined’, and there’s a load of javacode dumped! Things are moving along…

We copy-past-clean-up the java code into a test class, such as this:

package org.geenz.gildedrose.cucumber;

import cuke4duke.annotation.I18n.EN.Given;
import cuke4duke.annotation.I18n.EN.Then;
import cuke4duke.annotation.I18n.EN.When;
import cuke4duke.annotation.Pending;
import org.geenz.gildedrose.ItemFactory;
import org.geenz.gildedrose.StoreKeepingItem;

import static org.junit.Assert.*;

public class BasicFeature {

	 @Given ("^a Store Keeping Item with name \"([^\"]*)\"$")
	 @Pending
	 public void aStoreKeepingItemWithName+5DexterityVest_(String arg1) {
	 }

	 @Given ("^a sellIn date of 5$")
	 @Pending
	 public void aSellInDateOf5() {
	 }

	 @Given ("^a quality of 7$")
	 @Pending
	 public void aQualityOf7() {
	 }

	 @When ("^the Item is updated$")
	 @Pending
	 public void theItemIsUpdated() {
	 }

	 @Then ("^the sellIn is 4$")
	 @Pending
	 public void theSellInIs4() {
	 }

	 @Then ("^the quality is 6$")
	 @Pending
	 public void theQualityIs6() {
	 }
}

Pending

And, after noticing and correcting that a ‘+’ sign can’t be part of a Java method name, we run it again, Sam.

Oh dear:

[INFO] Feature: Quality changes with sell-in date Feature
[INFO] In order to keep track of quality of items in stock
[INFO] As a ShopKeeper
[INFO] I want quality to change as the sell-in date decreases
[INFO]
[INFO] Scenario: Decreasing Quality of a Basic Item # features/quality_decrease.feature:6
[INFO] Given a Store Keeping Item with name "+5 Dexterity Vest" # BasicFeature.aStoreKeepingItemWithNamePlus5DexterityVest_(String)
[INFO] TODO (Cucumber::Pending)
[INFO] /home/wouter/.m2/repository/.jruby/gems/cucumber-0.8.7/lib/cucumber/step_match.rb:26:in `invoke'
[INFO] /home/wouter/.m2/repository/.jruby/gems/cucumber-0.8.7/lib/cucumber/ast/step_invocation.rb:62:in `invoke'
[INFO] /home/wouter/.m2/repository/.jruby/gems/cucumber-0.8.7/lib/cucumber/ast/step_invocation.rb:41:in `accept'
[INFO] /home/wouter/.m2/repository/.jruby/gems/cucumber-0.8.7/lib/cucumber/ast/tree_walker.rb:99:in `visit_step'
[INFO] /home/wouter/.m2/repository/.jruby/gems/cucumber-0.8.7/lib/cucumber/ast/tree_walker.rb:164:in `broadcast'
[INFO] /home/wouter/.m2/repository/.jruby/gems/cucumber-0.8.7/lib/cucumber/ast/tree_walker.rb:98:in `visit_step'
[INFO] /home/wouter/.m2/repository/.jruby/gems/cucumber-0.8.7/lib/cucumber/ast/step_collection.rb:15:in `accept'
[IN
.....

Just what a Java developer likes: Ruby stackstraces! Luckily, the first entry is fairly clear: TODO (Cucumber::Pending).
And indeed, now that we take another look at it, the methods we just created all have a @Pending annotation. If we remove that, the scenario ‘runs’ successfully:

[INFO] Feature: Quality changes with sell-in date Feature
[INFO]   In order to keep track of quality of items in stock
[INFO]   As a ShopKeeper
[INFO]   I want quality to change as the sell-in date decreases
[INFO]
[INFO]   Scenario: Decreasing Quality of a Basic Item               # features/quality_decrease.feature:6
[INFO]     Given a Store Keeping Item with name "+5 Dexterity Vest" # BasicFeature.aStoreKeepingItemWithNamePlus5DexterityVest_(String)
[INFO]     And a sellIn date of 5                                   # BasicFeature.aSellInDateOf5()
[INFO]     And a quality of 7                                       # BasicFeature.aQualityOf7()
[INFO]     When the Item is updated                                 # BasicFeature.theItemIsUpdated()
[INFO]     Then the sellIn is 4                                     # BasicFeature.theSellInIs4()
[INFO]     And the quality is 6                                     # BasicFeature.theQualityIs6()
[INFO]
[INFO] 1 scenario (1 passed)
[INFO] 6 steps (6 passed)
[INFO] 0m0.269s

Adding code

Of course, it doesn’t actually test anything yet! But we can take a look at the way the text of the scenario is translated into executable code. For instance:

	 @Given ("^a sellIn date of 5$")
	 public void aSellInDateOf5() {
	 }

This looks straightforward. The @Given annotation gets a regular expression passed to it, which matches a particular condition. If the method actually set a sell-in value on some object, this would be a perfectly valid step in performing some test.

So let’s see where we can create such a sellable item. This other method looks promising:

	 @Given ("^a Store Keeping Item with name \"([^\"]*)\"$")
	 public void aStoreKeepingItemWithNamePlus5DexterityVest_(String arg1) {
	 }

For the non-initiated into the esoteric realm of regular expressions, the regexp here looks a little more scary. It really isn’t all that bad, though. The backslashes (\) are there to escape out the quotes (“). The brackets (()) are there to capture a specific region to be passed into the method: anything within those brackets is passed in as the first parameter of the method (out arg1 String parameter). And to specify what we want to capture, the [^\”]* simply means any character that is not a quote. So this captures everything within the quotes in our scenario, which happens to be the name of the item.

So let’s change that into:

    private StoreKeepingItem item = null;

    @Given ("^a Store Keeping Item with name \"([^\"]*)\"$")
    public void aStoreKeepingItemWithName(String name) {
        item = ItemFactory.create(name, 0, 0);
    }

Now our first line will create a new Item, with the correct name! That was easy!
Now we can fix the earlier method:

	 @Given ("^a sellIn date of 5$")
	 public void aSellInDateOf5() {
             item.setSellIn(5);
	 }

But, since I now already know how to parameterise these annotations, let’s doe that immediately:

    @Given("^a sellIn date of ([0-9]*)$")
    public void aSellInDateOf(int sellIn) {
        item.setSellIn(sellIn);
    }

Much better. Now let’s imagine we’ve done this for the rest as well (click to see):

package org.geenz.gildedrose.cucumber;

import cuke4duke.annotation.I18n.EN.Given;
import cuke4duke.annotation.I18n.EN.Then;
import cuke4duke.annotation.I18n.EN.When;
import cuke4duke.annotation.Pending;
import org.geenz.gildedrose.ItemFactory;
import org.geenz.gildedrose.StoreKeepingItem;

import static org.junit.Assert.*;

public class BasicFeature {

    private StoreKeepingItem item = null;

    @Given ("^a Store Keeping Item with name \"([^\"]*)\"$")
    public void aStoreKeepingItemWithName(String name) {
        item = ItemFactory.create(name, 0, 0);
    }

    @Given("^a sellIn date of ([0-9]*)$")
    public void aSellInDateOf(int sellIn) {
        item.setSellIn(sellIn);
    }

    @Given("^a quality of ([0-9]*)$")
    public void aQualityOf(int quality) {
        item.setQuality(quality);
    }

    @When("^the Item is updated$")
    public void theItemIsUpdated() {
        item.doDailyInventoryUpdate();
    }

    @Then("^the sellIn is (.*)$")
    public void theSellInIs(int expectedSellIn) {
        assertEquals(expectedSellIn, item.getSellIn());
    }

    @Then("^the quality is ([0-9]*)$")
    public void theQualityIs(int expectedQuality) {
        assertEquals(expectedQuality, item.getQuality());
    }
}

The test still passes, so this seems to work! For the rest of the scenarios, see the checked-in feature file on GitHub. Take a look at that file, and compare it to the README. Which one is clearer to you? Do they both contain all the information you need?

The odd one out

Note that there is one scenario there that is not covered by the methods that we have, so once you try to run this particular scenario, things fall apart:

        Scenario: Quality and SellIn of a Sulfuras item does not change
                Given a Store Keeping Item with name "Sulfuras, Hand of Ragnaros" with a sellIn date of 5, a quality of 7
                When the Item is updated
                Then the sellIn is 5
                And the quality is 7

Since this item is supposed to be immutable, I can’t really go and set the sellIn or quality after it’s been created. So I made a separate method to pass-in the sell-in and quality at initialisation time:

    /**
     * Separate when clause to indicate initial state, since some items can't be changed after initial creation.
     */
    @Given ("^a Store Keeping Item with name \"([^\"]*)\" with a sellIn date of ([0-9]*), a quality of ([0-9]*)$")
    public void aStoreKeepingItemWithNameAndSellInDateAndQualityOf(String name, int sellIn, int quality) {
        item = ItemFactory.create(name, sellIn, quality);

There could be a nicer way to do this, either by creating all items in this way, or by changing the way the immutable items work, but this was easy enough to do that I didn’t look any further.

So when we run all the scenarios, we get:

[INFO] Feature: Quality changes with sell-in date Feature
[INFO]   In order to keep track of quality of items in stock
[INFO]   As a ShopKeeper
[INFO]   I want quality to change as the sell-in date decreases
[INFO]
[INFO]   Scenario: Decreasing Quality of a Basic Item               # features/basic.feature:6
[INFO]     Given a Store Keeping Item with name "+5 Dexterity Vest" # BasicFeature.aStoreKeepingItemWithName(String)
[INFO]     And a sellIn date of 5                                   # BasicFeature.aSellInDateOf(int)
[INFO]     And a quality of 7                                       # BasicFeature.aQualityOf(int)
[INFO]     When the Item is updated                                 # BasicFeature.theItemIsUpdated()
[INFO]     Then the sellIn is 4                                     # BasicFeature.theSellInIs(int)
[INFO]     And the quality is 6                                     # BasicFeature.theQualityIs(int)
[INFO]
[INFO]   Scenario: Quality decrease doubles after sell-in has passed # features/basic.feature:14
[INFO]     Given a Store Keeping Item with name "+5 Dexterity Vest"  # BasicFeature.aStoreKeepingItemWithName(String)
[INFO]     And a sellIn date of 0                                    # BasicFeature.aSellInDateOf(int)
[INFO]     And a quality of 10                                       # BasicFeature.aQualityOf(int)
[INFO]     When the Item is updated                                  # BasicFeature.theItemIsUpdated()
[INFO]     Then the sellIn is -1                                     # BasicFeature.theSellInIs(int)
[INFO]     And the quality is 8                                      # BasicFeature.theQualityIs(int)
[INFO]
[INFO]   Scenario: Quality never becomes negative                   # features/basic.feature:22
[INFO]     Given a Store Keeping Item with name "+5 Dexterity Vest" # BasicFeature.aStoreKeepingItemWithName(String)
[INFO]     And a sellIn date of 0                                   # BasicFeature.aSellInDateOf(int)
[INFO]     And a quality of 0                                       # BasicFeature.aQualityOf(int)
[INFO]     When the Item is updated                                 # BasicFeature.theItemIsUpdated()
[INFO]     Then the sellIn is -1                                    # BasicFeature.theSellInIs(int)
[INFO]     And the quality is 0                                     # BasicFeature.theQualityIs(int)
[INFO]
[INFO]   Scenario: Quality of Aged Brie increases with age  # features/basic.feature:30
[INFO]     Given a Store Keeping Item with name "Aged Brie" # BasicFeature.aStoreKeepingItemWithName(String)
[INFO]     And a sellIn date of 5                           # BasicFeature.aSellInDateOf(int)
[INFO]     And a quality of 1                               # BasicFeature.aQualityOf(int)
[INFO]     When the Item is updated                         # BasicFeature.theItemIsUpdated()
[INFO]     Then the sellIn is 4                             # BasicFeature.theSellInIs(int)
[INFO]     And the quality is 2                             # BasicFeature.theQualityIs(int)
[INFO]
[INFO]   Scenario: Quality of Aged Brie never increases past 50 # features/basic.feature:38
[INFO]     Given a Store Keeping Item with name "Aged Brie"     # BasicFeature.aStoreKeepingItemWithName(String)
[INFO]     And a sellIn date of 5                               # BasicFeature.aSellInDateOf(int)
[INFO]     And a quality of 50                                  # BasicFeature.aQualityOf(int)
[INFO]     When the Item is updated                             # BasicFeature.theItemIsUpdated()
[INFO]     Then the sellIn is 4                                 # BasicFeature.theSellInIs(int)
[INFO]     And the quality is 50                                # BasicFeature.theQualityIs(int)
[INFO]
[INFO]   Scenario: Quality of Backstage Passes increases by 1 if sell-in is greater than 10 # features/basic.feature:46
[INFO]     Given a Store Keeping Item with name "Backstage passes to a TAFKAL80ETC concert" # BasicFeature.aStoreKeepingItemWithName(String)
[INFO]     And a sellIn date of 11                                                          # BasicFeature.aSellInDateOf(int)
[INFO]     And a quality of 20                                                              # BasicFeature.aQualityOf(int)
[INFO]     When the Item is updated                                                         # BasicFeature.theItemIsUpdated()
[INFO]     Then the quality is 21                                                           # BasicFeature.theQualityIs(int)
[INFO]
[INFO]   Scenario: Quality of Backstage Passes increases by 2 if sell-in is less than 10 but more than 5 # features/basic.feature:53
[INFO]     Given a Store Keeping Item with name "Backstage passes to a TAFKAL80ETC concert"              # BasicFeature.aStoreKeepingItemWithName(String)
[INFO]     And a sellIn date of 6                                                                        # BasicFeature.aSellInDateOf(int)
[INFO]     And a quality of 20                                                                           # BasicFeature.aQualityOf(int)
[INFO]     When the Item is updated                                                                      # BasicFeature.theItemIsUpdated()
[INFO]     Then the quality is 22                                                                        # BasicFeature.theQualityIs(int)
[INFO]
[INFO]   Scenario: Quality of Backstage Passes increases by 3 if sell-in is 5 or less but more than 0 # features/basic.feature:60
[INFO]     Given a Store Keeping Item with name "Backstage passes to a TAFKAL80ETC concert"           # BasicFeature.aStoreKeepingItemWithName(String)
[INFO]     And a sellIn date of 5                                                                     # BasicFeature.aSellInDateOf(int)
[INFO]     And a quality of 20                                                                        # BasicFeature.aQualityOf(int)
[INFO]     When the Item is updated                                                                   # BasicFeature.theItemIsUpdated()
[INFO]     Then the quality is 23                                                                     # BasicFeature.theQualityIs(int)
[INFO]
[INFO]   Scenario: Quality of Backstage Passes is 0 after the concert (sell-in) passes      # features/basic.feature:67
[INFO]     Given a Store Keeping Item with name "Backstage passes to a TAFKAL80ETC concert" # BasicFeature.aStoreKeepingItemWithName(String)
[INFO]     And a sellIn date of 0                                                           # BasicFeature.aSellInDateOf(int)
[INFO]     And a quality of 20                                                              # BasicFeature.aQualityOf(int)
[INFO]     When the Item is updated                                                         # BasicFeature.theItemIsUpdated()
[INFO]     Then the quality is 0                                                            # BasicFeature.theQualityIs(int)
[INFO]
[INFO]   Scenario: Quality and SellIn of a Sulfuras item does not change                                             # features/basic.feature:74
[INFO]     Given a Store Keeping Item with name "Sulfuras, Hand of Ragnaros" with a sellIn date of 5, a quality of 7 # BasicFeature.aStoreKeepingItemWithNameAndSellInDateAndQualityOf(String,int,int)
[INFO]     When the Item is updated                                                                                  # BasicFeature.theItemIsUpdated()
[INFO]     Then the sellIn is 5                                                                                      # BasicFeature.theSellInIs(int)
[INFO]     And the quality is 7                                                                                      # BasicFeature.theQualityIs(int)
[INFO]
[INFO]   Scenario: Quality of Conjured items goes down twice as fast as a normal item before sell-in # features/basic.feature:80
[INFO]     Given a Store Keeping Item with name "Conjured Mana Cake"                                 # BasicFeature.aStoreKeepingItemWithName(String)
[INFO]     And a sellIn date of 5                                                                    # BasicFeature.aSellInDateOf(int)
[INFO]     And a quality of 20                                                                       # BasicFeature.aQualityOf(int)
[INFO]     When the Item is updated                                                                  # BasicFeature.theItemIsUpdated()
[INFO]     Then the quality is 18                                                                    # BasicFeature.theQualityIs(int)
[INFO]
[INFO]   Scenario: Quality of Conjured items goes down twice as fast as a normal item after sell-in # features/basic.feature:87
[INFO]     Given a Store Keeping Item with name "Conjured Mana Cake"                                # BasicFeature.aStoreKeepingItemWithName(String)
[INFO]     And a sellIn date of 0                                                                   # BasicFeature.aSellInDateOf(int)
[INFO]     And a quality of 20                                                                      # BasicFeature.aQualityOf(int)
[INFO]     When the Item is updated                                                                 # BasicFeature.theItemIsUpdated()
[INFO]     Then the quality is 16                                                                   # BasicFeature.theQualityIs(int)
[INFO]
[INFO] 12 scenarios (12 passed)
[INFO] 64 steps (64 passed)
[INFO] 0m1.617s
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 10.861s
[INFO] Finished at: Fri Sep 16 15:57:23 CEST 2011
[INFO] Final Memory: 5M/106M
[INFO] ------------------------------------------------------------------------

So now we have a full set of acceptance tests, covering the whole of the requirements, and with only very limited amount of code needed. Of course, the small amount of code needed is for a large part because I already refactored the original to something more managable. I would be a nice next experiment to start with these scenarios, and grow the code from there. If you do this, let me know, and send a pull request!

Parameterization

For some type of tests, it makes sense to have a scenario where you put in different types of data, and expect different results. By separating the scenario from the input and output data, you can make thes kind of tests much more readable. In the case of our example, you can find the same tests in the parameterised.feature file, but it’s small enough to simply include here:

Feature: Quality changes with sell-in date Feature
        In order to keep track of quality of items in stock
        As a ShopKeeper
        I want quality to change as the sell-in date decreases

        Scenario Outline: Changing Quality of an Item
                Given a Store Keeping Item with name "<item name>"
                And a sellIn date of <sell in>
                And a quality of <quality>
                When the Item is updated
                Then the sellIn is <expected sell in>
                And the quality is <expected quality>

		Examples:
		| item name			| sell in	| quality	| expected sell in	| expected quality	|
		| +5 Dexterity Vest	| 5			| 7			| 4					| 6					|
		| +5 Dexterity Vest	| 0			| 10		| -1				| 8					|
		| +5 Dexterity Vest	| 0			| 0			| -1				| 0					|
		| Aged Brie			| 5			| 1			| 4					| 2					|
		| Aged Brie			| 5			| 50		| 4					| 50				|
		| Backstage passes to a TAFKAL80ETC concert	| 11 | 20 | 10		| 21				|
		| Backstage passes to a TAFKAL80ETC concert	| 6  | 20 | 5		| 22				|
		| Backstage passes to a TAFKAL80ETC concert	| 5  | 20 | 4		| 23				|
		| Backstage passes to a TAFKAL80ETC concert	| 0  | 20 | -1		| 0					|
		| Conjured Mana Cake| 5			| 20		| 4					| 18				|
		| Conjured Mana Cake| 0			| 20		| -1				| 16				|

As you can see, this is much shorter. It does skip on the detailed text for each scenario, though, which I thought to be somewhat of a loss in this particular case. For tests with larger sets of data, this is probably a great feature, though. For this example I though the feature was clearer with the more verbose scenarios.

If you want to know more, a great resource is the cuke4ninja free on-line book. The Cucumber wiki, and additional tutorials list are also great sources of knowledge.

Setting up Selenium with Maven

In the team I’m currently working with, the need for regression testing was becoming obvious. The team is working on a web MVC-type framework, and has been running into the results of limited testing: quality wasn’t just low, it was unknown. The usual excuses were there, pressure to release, and interruptions by unplanned work. Usually, the unplanned work is caused by the same lack of quality that is probably caused by pressure to release.

Since this is a web-intensive project where the front-end is not just important, but actually a core part of the software, we decided the first order of business would be to get Selenium tests running on the test/showcase applications. I’ve worked with Selenium before, but not with the GWT front-end technology, and not with the Selenium’s WebDriver APIs. I thought I’d share the process, and some of the issues encountered. In this post, I’ll describe how to get selenium running from a local maven build while still being able to run the unit/micro-tests separately.

Integration into the build

The project is built using Maven, so the first step is to get both the selenium dependencies in there, and be able to run a simple Hello World test from the maven build. The Hello World test was simply an empty Selenium JUnit test that opened the test-showcase, the hello world applet within that, and checked the window title.

package com.qualogy.selenium;

import java.util.concurrent.TimeUnit;

import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import static org.junit.Assert.*;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;

public class HelloWorldTest {

	WebDriver driver = new FirefoxDriver();
	// WebDriver driver = new HtmlUnitDriver(true);

	String baseUrl = "http://localhost:7070";

	@Before
	public void setUp() throws Exception {
		driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
	}

	@Test
	@Ignore
	public void testTestQafe() throws Exception {
		driver.get(baseUrl + "/test-showcaseapp/QAFEGWTWeb.jsp");
		
		// Open HelloWorld Applet
		driver.findElement(By.id("qafe_menu_applications|system_app")).click();
		driver.findElement(By.id("HelloWorld")).click();
		driver.findElement(By.id("window1|HelloWorld")).click();

		assertEquals("Hello World!", driver.getTitle());
	}

	@After
	public void tearDown() throws Exception {
		driver.quit();
	}
}

Getting this to compile requires you to add the selenium-java dependency into your maven pom.xml file:

	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
		</dependency>
		<dependency>
			<groupId>org.seleniumhq.selenium</groupId>
			<artifactId>selenium-java</artifactId>
			<version>2.4.0</version>
			<scope>test</scope>
		</dependency>
	</dependencies>

Note: I initially used the 2.3.0 version of selenium. That version does not work together with FireFox 6, though, and that broke my tests for a bit when I installed that update.

At this point, as long as the application under test is running outside the build, just doing a mvn clean install will run you selenium test, and you’ll see Firefox starting up, doing whatever you’ve defined in the test, and quitting again. Success!

Next, I would really like to get this running without depending on the external process of starting your application outside of your build. I won’t go into the troubles you can have if you’ve tailored your build process for deployment on some proprietary application server (check out the cargo plugin, as a starting point). But luckily, in this case, the system started without any problems by simply doing:

mvn jetty:run

This starts jetty with the default configuration, which mean port 8080, which I don’t want happening when we’ll be running this later on our build server, since that one uses port 8080 itself. More importantly, I don’t want to run these tests with every build. Integration tests using a deployed application are simply too slow to run with every build. Developers should be able to run them locally, but not when they’ve only added new unit-test (and any production code that came with those).

The way to deal with this is to use a maven profile where you can switch certain phases of the build on and off. Another way would be to create a separate maven (sub) project that is there only to run the integration test build, but that was not the direction I chose. So what does such a profile look like?


	<profiles>
		<!-- Profile to enable integration test execution Should be enabled given 
			a -Dintegration.test option when running the build -->
		<profile>
			<id>integration-test</id>
			<activation>
				<property>
					<name>integration.test</name>
				</property>
			</activation>
			<build>
				<plugins>
					<plugin>
						<groupId>org.mortbay.jetty</groupId>
						<artifactId>maven-jetty-plugin</artifactId>
						<version>${org.mortbay.jetty}</version>
						<configuration>										
							<webAppSourceDirectory>${project.build.directory}/${artifactId}-${version}</webAppSourceDirectory>									
							<webXml>${project.build.directory}/${artifactId}-${version}/WEB-INF/web.xml</webXml>
							<scanIntervalSeconds>10</scanIntervalSeconds>
							<stopKey>foo</stopKey>
							<stopPort>9999</stopPort>
							<connectors>
								<connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
									<port>7070</port>
								</connector>
							</connectors>
						</configuration>
						<executions>
							<execution>
								<id>start-jetty</id>
								<phase>pre-integration-test</phase>
								<goals>
									<goal>run</goal>
								</goals>
								<configuration>
									<scanIntervalSeconds>0</scanIntervalSeconds>
									<daemon>true</daemon>
								</configuration>
							</execution>
							<execution>
								<id>stop-jetty</id>
								<phase>post-integration-test</phase>
								<goals>
									<goal>stop</goal>
								</goals>
							</execution>
						</executions>
					</plugin> 
					<plugin>
						<groupId>org.apache.maven.plugins</groupId>
						<artifactId>maven-surefire-plugin</artifactId>
						<configuration>
							<!-- Skip the normal tests, we'll run the integration-tests only -->
							<skip>true</skip>
							<excludes>
							</excludes>
							<includes>
								<include>com/example/selenium/**</include>
							</includes>
						</configuration>
						<executions>
							<execution>
								<phase>integration-test</phase>
								<goals>
									<goal>test</goal>
								</goals>
								<configuration>
									<skip>false</skip>
									<includes>
										<include>com/example/selenium/**</include>
									</includes>
									<excludes>
									</excludes>
								</configuration>
							</execution>
						</executions>
					</plugin>
				</plugins>
			</build>
		</profile>
		<profile>
			<!-- Added a micro/unit test profile that is run by default
				 so that we can override the surefire excludes in an
				 integration test build -->
			<id>micro-test</id>
			<activation>
				<property>
					<name>!integration.test</name>
				</property>				
			</activation>
			<build>
				<plugins>
					<plugin>
						<groupId>org.apache.maven.plugins</groupId>
						<artifactId>maven-surefire-plugin</artifactId>
						<configuration>
							<excludes>
								<exclude>com/example/selenium/**</exclude>
							</excludes>
						</configuration>
					</plugin>
				</plugins>
			</build>
		</profile>
	</profiles>	

That’s quite a lot of XML, but in short the integrationt-test profile does the following:

  • Activate the integration-test profile when the -Dintegration.test property is set
  • Start jetty (jetty:run) before doing the integration-test phase
  • Stop jetty after the integration-test phase
  • Do NOT run any unit tests if the integration-test profile is enabled
  • DO run all the integration tests in the package com.example.selenium when the integration-test profile is enabled

Which is great, and works. But when we then run the normal build, the selenium tests are still run (and fail). So that’s where the micro-test profile in the snippet above comes in: it excludes the selenium tests from the normal surefire testrun.

So now if we do mvn clean install all our normal micro-tests are run, and if we do mvn -Dintegration.test clean install the micro-tests are skipped and the selenium tests are run.

Now we are ready to write a real test, but I’ll save that for a future post.

My First Coding Dojo

Last week Wednesday, I organised my first Code Dojo! For those that are not familiar with the concept, a Code Dojo is when programmers get together to exercise their craft by solving a problem together. The problem is called a ‘Kata’, analogous to the way these concepts are used in the Karate world.

As a problem, I had selected the ‘Gilded Rose’ Kata, for which I have created a Java version a while back. I figured that since this is a refactoring Kata, the type of problem would be all too familiar to my colleagues

While preparing for the Dojo, I asked for advice on twitter. Luckily, Mark Levison reacted, and had some good advice (“Keep It Simple!”). What’s more, he had documented his own first experiences (first and second dojo) very thoroughly! We had enough pizza.

Based on that advice, I tried to simplify the kata a little, giving us a headstart by starting off with some already implemented acceptance tests. (See my FirstTry branch to look at the integration tests. I didn’t do that try test-driven (tsk!)). The idea was that this would save us some time, and let us jump right in to TDD-ing the refactoring.

I also figured that it would be wise to do a little introductory presentation on what a Coding Dojo is, and what is important for Pair Programming and TDD. I found a nicely made presentation on slideshare by Serge Rehem. Unfortunately, it was in Portuguese, which I don’t speak. A little Google Translate, and imagination, helped though, and I created a translated version.

On the evening itself, after Ciarán got everyone warmed-up and enthusiastic with a run through Boris Gloger the Ball-Point-Game, we started the dojo with the 5 minute (well, at my speed, is was about 15-20 minutes) introduction using those sheets, and going into the specifics of working with TDD. Then we briefly discussed the kata, and got going.

At this point I was very happy with the ‘Keep It Simple’ advice, since we obviously needed time to really get started. We were working with 5 minute turns at the keyboard, but since we were still getting the hang of this, those sometimes turned out to be a little longer. Unfortunately, this meant that not everyone got their chance on driving, but the whole group did join in the discussion.

We also got some discussion going about the why and how of working Test Driven, which was a lot of fun, and precisely the point of the exercise, of course.

So what are we going to be doing different next time?

  • We’re going to plan more time. We had about 90 minutes, including the introductory presentation and discussion of the Kata, that didn’t leave us enough time to get through the problem
  • We’ll need to pick a smaller Kata. The refactoring Kata is fun, but it is not small enough, especially when starting out with Coding Dojos.
  • I will not write tests in advance! This helped keep the assignment small, but not small enough, and it allowed us to go too quickly to coding, without really understanding the assignment. This was actually one of the main complaints: the goal of the exercise wasn’t clear enough!
  • We’ll ask everyone to try the Kata in advance, so that we can focus on the process of writing code together, instead of on understanding the problem
  • We’ll time-box the pair-rotating more carefully, so everyone gets a turn

Overall, though, it was still a lot of fun, and most people really liked the idea of doing real hands-ons learning during our regular get-togethers withing Qualogy.

Code Cleaning: A Refactoring Example In 50 Easy Steps

One of the things I find myself doing at work is looking at other peoples code. This is not unusual, of course, as every programmer does that all the time. Even if the ‘other people’ is him, last week. As all you programmers know, rather often ‘other people’s code’ is not very pretty. Partly, this can be explained because every programmer knows, no one is quite as good at programming as himself… But very often, way too often, the code really is not all that good.

This can be caused by many things. Sometimes the programmers are not very experienced. Sometimes the pressure to release new features is such that programmers feel pressured into cutting quality. Sometimes the programmers found the code in that state, and simply didn’t know where to start to improve things. Some programmers may not even have read Clean Code, Refactoring, or the Pragmatic Programmer! And maybe no one ever told them they should.

Recently I was asked to look at a Java codebase, to see if it would be possible for our company to take that into a support contract. Or what would be needed to get it to that state. This codebase had a number of problems, with lack of tests, lots of code duplication and a very uneven distribution in complexity (lots of ‘struct’ classes and the logic that should be in them spread out, and duplicated, over the rest). There was plenty wrong, and sonar quickly showed most of them.

Sonar status

When discussing the issues with this particular code base, I noticed that the developers already knew quite a few of the things that were wrong. They did not have a clear idea of how to go from there towards a good state, though. To illustrate how one might approach this, I spent a day making an example out of one of the high complexity classes (cyclomatic complexity of 98).

Larger examples of refactoring are fairly rare out there, so I figured I’d share this. Of course, package and class names (and some constants/variables) have been altered to protect the innocent.

I’d like to emphasize that none of this is very special. I’m not a wizard at doing this, by any standard. I don’t even code full time nowadays. That’s irrelevant: The point here is precisely that by taking a series of very simple and straightforward steps, you can improve your code tremendously. Anyone can do this! Everyone should…

I don’t usually shield off part of my posts under a ‘read-more’ link, but this post had become HUGE, and I don’t want to harm any unsuspecting RSS readers out there. Please, do read the whole thing. And: Let me (and my reader and colleagues) know how this can be done better!

Contine reading

Ken Schwaber Tech Talk

I’ve just finished watching a Google Tech Talk by Ken Schwaber: Scrum et al, through the ‘running agile blog.

This was the first time I’ve seen Schwaber talk, though I’ve been reading his blog. It was a good talk, with plenty of humour, and some very recognisable stories.

Some highlights (paraphrased from memory, I’m lazy):

“In Scrum there’s this role called the ‘ScrumMaster’. Otherwise often known as ‘the prick’. This is the guy who needs to ensure that the team does not compromise on quality. He’s the one that has to say, when some item has not been finished to the agreed level of quality: ‘Sorry, this is not going to be demoed’ to the team, and ‘Sorry, this will not be delivered until the end of the next sprint’ to the Product Owner. You can imagine how popular this makes this guy. They usually burn out after 12 to 15 months.”

Thanks for that last bit, Ken. And I was really liking my new career, so far…

Another very interesting bit was the part (starting at arounf the 35 minute mark) where he talks about how companies can be held back by the state of their ‘core functionality’, the wrong distribution between people working on new functionality, and those maintaining (and extending) the core, and how you can get there. Of course, the how you can get there is more familiar to most of us then we would like to admit…

He explains how you normally get to this state, using a very normal process of overcommitting (pressure…), quality declining, velocity declining… Rince and repeat!

Very much worth watching.