<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-5094340343398123932</id><updated>2012-02-16T18:50:47.983+01:00</updated><category term='feature tests'/><category term='lean'/><category term='Code Kata'/><category term='xp2009'/><category term='feminism'/><category term='selenium'/><category term='teaching programming'/><category term='GothPy'/><category term='geek points'/><category term='pyUseCase'/><category term='TDD'/><category term='scrum'/><category term='agile'/><category term='XP2012'/><category term='Ruby'/><category term='python'/><category term='clean code'/><category term='BDD'/><category term='testing quadrants'/><category term='JUseCase'/><category term='design'/><category term='testing'/><category term='Coding Dojo'/><category term='code retreat'/><category term='Bache Consulting'/><category term='TextTest'/><category term='conferences'/><category term='ATDD'/><title type='text'>coding is like cooking</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>99</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-2074429480407332828</id><published>2011-12-20T15:00:00.002+01:00</published><updated>2012-01-10T07:44:07.327+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='code retreat'/><category scheme='http://www.blogger.com/atom/ns#' term='clean code'/><category scheme='http://www.blogger.com/atom/ns#' term='Code Kata'/><category scheme='http://www.blogger.com/atom/ns#' term='Coding Dojo'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><title type='text'>Global Day of Code Retreat</title><content type='html'>A little while back I was back in Stockholm facilitating another Code Retreat, (see &lt;a href="http://emilybache.blogspot.com/2011/09/code-retreat-stockholm.html" target="_blank"&gt;previous post&lt;/a&gt;), this time as part of Global Day of Code Retreat, (GDCR). (Take a look at &lt;a href="http://coderetreat.com/"&gt;Corey Haines' site&lt;/a&gt; for loads of information about this global event that comprised meetings in over 90 cities worldwide, with over 2000 developers attending.)&lt;br /&gt;&lt;br /&gt;I think the coding community could really do with more people who know how to do TDD and think about good design, so I'm generally pretty encouraged by the success of this event. I do feel a bit disappointed about some aspects of the day though, and this post is my attempt to outline what I think could be improved.&lt;br /&gt;&lt;br /&gt;I spent most of the Global Day of Code Retreat walking around looking over people's shoulders and giving them feedback on the state of their code and tests. I noticed that very few pairs got anywhere close to solving the problem before they deleted the code at the end of each 45 minute session. Corey says that this is very much by design. You know you don't have time to solve the problem, so you can de-stress: no-one will demand delivery of anything. You can concentrate on just writing good tests and code. &lt;br /&gt;&lt;br /&gt;In between coding sessions, I spent quite a lot of effort reminding people about simple design, SOLID principles, and how to do TDD (&lt;a href="http://emilybache.blogspot.com/2011/05/tdd-in-terms-of-states-and-moves.html"&gt;in terms of states and moves&lt;/a&gt;). Unfortunately I found people rarely wrote enough code for any of these ideas to really be applicable, and TDD wan't always helping people.&lt;br /&gt;&lt;br /&gt;I saw a lot of solutions that started with the "Cell" class, that had an x and y coordinate, and a boolean to say whether it was alive or not. Then people tended to add a "void tick(int liveNeighbourCount)" method, and start to implement code that would follow the four rules of Conway's Game of Life to work out if the cell should flip the state of its boolean or not. At some point they would create a "World" class that would hold all the cells, and "tick()" them. Or some variant of that. Then, (generally when the 45 minutes were running out), people started trying to find a data structure to hold the cells in, and some way to find out which were neighbours with each other. Not many questioned whether they actually needed a Cell class in the first place.&lt;br /&gt;&lt;br /&gt;Everyone at the code retreat deleted their code afterwards, of course, but you can see an example of a variant on this kind of design by Ryan Bigg &lt;a href="https://github.com/radar/screencasts/blob/master/000-game-of-life/gol_spec.rb"&gt;here&lt;/a&gt; (a work in progress, he has a &lt;a href="https://s3.amazonaws.com/ryanbigg_screencasts/Game+of+Life+-+Full.mov"&gt;screencast&lt;/a&gt; too).&lt;br /&gt;&lt;br /&gt;Of course, as facilitator I spent a fair amount of time trying to ask the kind of questions that would push people to reevaluate their approach. I had partial success, I guess. Overall though, I came away feeling a bit disillusioned, and wanting to improve my facilitation so that people would learn more about using TDD to actually solve problems. &lt;br /&gt;&lt;br /&gt;At the final retrospective of the day, everyone seemed to be very positive about the event, and most people said they learnt more about pair programming, TDD, and the language and tools they were working with. We all had fun. (If you read Swedish, Peter Lind wrote up the retrospective in &lt;a href="http://www.valtechlabs.se/global-day-of-coderetreat-retrospektiv"&gt;Valtech's blog&lt;/a&gt;) This is great, but could we tweak the format to encourage even more learning?&lt;br /&gt;&lt;br /&gt;I think to solve Conway's Game of Life adequately, you need to find a good datastructure to represent the cells, and an efficient algorithm to "tick" to the next generation. Just having well named classes and methods, although a good idea, probably won't be enough.&lt;br /&gt;&lt;br /&gt;For me, TDD is a good method for designing code when you already mostly know what you're doing. I don't think it's a good method for discovering algorithms. I'm reminded of the debate a few years back when Peter Norvig posted an excellent Sudoku solver (&lt;a href="http://norvig.com/sudoku.html"&gt;here&lt;/a&gt;) and people thought it was much better than Ron Jeffries' TDD solution to the same problem (&lt;a href="http://xprogramming.com/xpmag/OkSudoku"&gt;here&lt;/a&gt;). Peter was later interviewed about whether this proved that TDD was not useful. Dr Norvig said he didn't think that it proved much about TDD at all, since&lt;br /&gt;&lt;br /&gt;"you can test all you want and if you don’t know how to approach the problem, you’re not going to get a solution"&amp;nbsp; &lt;br /&gt;&lt;i&gt;(from Peter Siebel's book "Coders At Work", an extract of which is available in &lt;a href="http://gigamonkeys.wordpress.com/2009/10/05/coders-unit-testing/"&gt;his blog&lt;/a&gt;)&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;I felt that most of the coders at the code retreat were messing around without actually knowing how to solve the problem. They played with syntax and names and styles of tests without ever writing enough code to tell whether their tests were driving a design that would ultimately solve the problem.&lt;br /&gt;&lt;br /&gt;Following the GDCR, I held a coding dojo where I experimented with the format a little. I only had time to get the participants do two 45 minute coding sessions on the Game of Life problem. At the start, as a group we discussed the Game of Life problem, much as Corey recommends for a Code Retreat introduction. However, in addition, I explained my favoured approach to a solution - the data structure and algorithm I like to use. I immediately saw that they started their TDD sessions with tests and classes that could lead somewhere. I feel that if they had continued coding for longer, they should have ended up with a decent solution. Hopefully it would also have been possible to refactor it from one datastructure to another, and to switch elements of the algorithm without breaking most of the tests. &lt;br /&gt;&lt;br /&gt;I think this is one way to improve the code retreat. Just give people more clues at the outset as to how to tackle the problem. In real life when you sit down to do TDD you'll often already know how to solve similar problems. This would be a way for the facilitator to give everyone a leg-up if they havn't worked on any rule-based games involving a 2D infinite grid before.&lt;br /&gt;&lt;br /&gt;Rather than just explaining a good solution up front, we could spend the first session doing a "Spike Solution". This is one of the practices of XP:&lt;br /&gt;&lt;br /&gt;"the idea is just to drive through the entire problem in one blow, not to craft the perfect solution first time out."&lt;br /&gt;&lt;i&gt;From "Extreme Programming Installed" by Jeffries, Anderson, Hendrickson, p41&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Basically, you hack around without writing any tests or polishing your design, until you understand the problem well enough to know how you plan to solve it. Then you throw your spike code away, and start over with TDD.&lt;br /&gt;&lt;br /&gt;Spending the first 45 minute session spiking would enable people to learn more about the problem space in a shorter amount of time than you generally do with TDD. By dropping the requirement to write tests or good names or avoid code smells, you could hopefully hack together more alternatives, and maybe find out for yourself what would make a good data structure for easily enumerating neighbouring cells.&lt;br /&gt;&lt;br /&gt;So the next time I run a code retreat, I think I'll start with a "spiking" session and encourage people to just optimize for learning about the problem, not beautiful code. Then after that maybe I'll sketch out my favourite algorithm, in case they didn't come up with anything by themselves that they want to pursue. Then in the second session we could start with TDD in earnest.&lt;br /&gt;&lt;br /&gt;I always say that the code you end up with from doing a Kata is not half as interesting as the route you took to get there. To this end I've published a &lt;a href="http://vimeo.com/34732838" target="_blank"&gt;screencast&lt;/a&gt; of myself doing the Game of Life Kata in Python. (The code I end up with is also published, &lt;a href="https://github.com/emilybache/Screencast-Katas/tree/master/game_of_life" target="_blank"&gt;here&lt;/a&gt;). I'm hoping that people might want to prepare for a Code Retreat by watching it. It could be an approach they try to emulate, improve on or criticise. On the other hand, showing my best solution like this is probably breaking the neutrality of how a code retreat facilitator is supposed to behave. I don't think Corey has ever published a solution to this kata, and there's probably a reason for that.&lt;br /&gt;&lt;br /&gt;I have to confess, I already broke all the rules of being a facilitator, when I spent the last session of the Global Day of Code Retreat actually coding. There was someone there who really wanted to do Python, and no-one else seemed to want to pair with him. So I succombed. In 45 minutes we very nearly had a working solution, mostly because I had hacked around and practiced how to do it several times before. It felt good. I think more people should experience the satisfaction of actually completing a useful piece of code using TDD at a Code Retreat. &lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-2074429480407332828?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/2074429480407332828/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=2074429480407332828' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/2074429480407332828'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/2074429480407332828'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2011/12/global-day-of-code-retreat.html' title='Global Day of Code Retreat'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-842297465020612321</id><published>2011-12-20T13:11:00.000+01:00</published><updated>2011-12-20T13:27:40.057+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='teaching programming'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>Scandinavian Developer Conference</title><content type='html'>Scandinavian Developer Conference will be held in Göteborg in April, and last week we launched the &lt;a href="http://www.scandevconf.se/2012/conference/detailed-program/"&gt;detailed programme&lt;/a&gt; on the website. I've been involved with the conference ever since the first event in 2009, but this year I've taken on increased responsibilities, acting as Programme Chair.&lt;br /&gt;&lt;br /&gt;When P-A Freiholtz, the Managing Director at &lt;a href="http://apper.se/en/"&gt;Apper Systems&lt;/a&gt;*, (the company behind the conference), approached me about taking this role, I jumped at the chance. My business is all about professional development for software developers, and a conference in Göteborg is a really good opportunity for a lot of local people to hear about what's going on in the world outside. Many of the developers I meet in my work don't often get away from their desks, spending the majority of their time caught up in the intrigues and deadlines of a single project and company environment. SDC2012 will be a chance for a lot of local people to broaden their horizons without it costing their boss a fortune, or disrupting their usual schedule too much. &lt;br /&gt;&lt;br /&gt;I wrote an &lt;a href="http://www.scandevconf.se/"&gt;editorial&lt;/a&gt; on the front page of the conference website which explains more about what's on the programme and who should come. Everyone involved in software development, basically :-)&lt;br /&gt;&lt;br /&gt;These days, we compete in a global marketplace for software development. I'm hopeful about the future, I'm enthusiastic about Swedish working culture, and I think Scandinavian Developer Conference is helping Göteborg grow as a center of competence. Please do &lt;a href="http://www.scandevconf.se/2012/registration/"&gt;join us at the conference&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;* formerly named Iptor - now under new ownership.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-842297465020612321?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/842297465020612321/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=842297465020612321' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/842297465020612321'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/842297465020612321'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2011/12/scandinavian-developer-conference.html' title='Scandinavian Developer Conference'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-5541246745178872208</id><published>2011-11-27T20:58:00.001+01:00</published><updated>2011-11-27T21:01:23.187+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XP2012'/><title type='text'>XP2012 Team Challenge</title><content type='html'>At a conference about software development, wouldn’t it be useful to have some people there actually develop software? We want to invite you to bring your whole team, and show off how agile you are. Set up your team information radiators, pair programming stations and servers, and spend part of the conference actually developing your product! With any luck, some of the excellent agilists at the conference will come and pair with you.&lt;br /&gt;&lt;br /&gt;The only rules are that you must be agile, and you must deploy into production during the conference. If you deploy several times a day and the product is generally available for conference delegates to use and try the new features, all the better. :-)&lt;br /&gt;&lt;br /&gt;See this as a challenge for your team. If you’re going to be able to show your process off to a whole conference of agilists, wouldn’t you like to have the best possible process? Wouldn’t you like all your team members to work effectively with the latest tools and techniques? Wouldn’t the challenge of having to be ready to show off what you can do at &lt;a href="http://xp2012.org/"&gt;XP2012&lt;/a&gt; be a great way to motivate your team to improve over the next 6 months?&lt;br /&gt;&lt;br /&gt;This is the challenge that the team behind &lt;a href="http://blocket.se/"&gt;http://blocket.se&lt;/a&gt; (one of Sweden’s biggest ecommerce sites), and a team from &lt;a href="http://www.blogger.com/%20http://www.saabgroup.com/"&gt;SAAB Gripen&lt;/a&gt;, (software for jet fighters), have already accepted. Will you &lt;a href="http://xp2012.org/submit/submit"&gt;join them&lt;/a&gt;, and take up the XP2012 team challenge?&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-5541246745178872208?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/5541246745178872208/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=5541246745178872208' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/5541246745178872208'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/5541246745178872208'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2011/11/xp2012-team-challenge.html' title='XP2012 Team Challenge'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-3814218638024947930</id><published>2011-11-27T20:55:00.001+01:00</published><updated>2011-11-27T21:03:34.563+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XP2012'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>Tech Demos at XP2012</title><content type='html'>At XP2011 we introduced a new kind of presentation - the tech demo. The idea was to give people 30 minutes to demonstrate a new tool or technique. For example, some people performed code katas in diverse languages, and others showed various productivity-boosting frameworks. &lt;br /&gt;&lt;br /&gt;For XP2012 we want to continue with these kinds of demos, but with an additional rule. You can’t touch the keyboard yourself when you present. We want you to co-present with someone else, drawn from the audience, who will do the typing and demonstrate the tool or technique. Your job is to coach them into doing the demo you've planned, and to explain to everyone what’s going on.&lt;br /&gt;&lt;br /&gt;Your co-presenter could be someone drawn from the audience who you’ve never met before. You’ll have to expertly coach them into demonstrating what you aim to show to the rest of the audience. If you choose this route, it will certainly be a big test of your skills of coaching and pedagogy.&lt;br /&gt;&lt;br /&gt;Alternatively you can come to the conference and find a volunteer in advance of the presentation. You could make time for a practice run or two before the presentation. Again, you’ll be showing not only your tool or techique, but also how easy it is for a good programmer to learn.&lt;br /&gt;&lt;br /&gt;If you’re thinking this sounds like an awfly scary way to do a demo, then you may be right. We think it’s also a very good way to have demos that engage the audience and really show off what you’re capable of.&lt;br /&gt;&lt;br /&gt;If you know someone else who’ll be at the conference you could of course prepare the demo with them well in advance. You’d be able to work out exactly what pitfalls they will fall into, and have a slick commentary ready. Just having one person typing and the other talking is a great advantage in a demo, and this would probably still be good to watch. It might not be quite as challenging though :-)&lt;br /&gt;&lt;br /&gt;Will &lt;a href="http://xp2012.org/"&gt;you accept the XP2012 Tech Demo challenge&lt;/a&gt;?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-3814218638024947930?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/3814218638024947930/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=3814218638024947930' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/3814218638024947930'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/3814218638024947930'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2011/11/tech-demos-at-xp2012.html' title='Tech Demos at XP2012'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-6572688054861657659</id><published>2011-11-27T20:45:00.001+01:00</published><updated>2011-11-27T21:08:06.133+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='XP2012'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>Presenting a session at XP2012</title><content type='html'>The &lt;a href="http://xp2012.org/cfp"&gt;Call for Papers&lt;/a&gt; for XP2012 is currently open, and this year we’re doing things a little differently*. I'm one of the co-chairs responsible for programme design, and also involved in reviewing session proposals. (You might be interested in &lt;a href="http://emilybache.blogspot.com/2010/12/xp2011.html"&gt;my post about XP2011&lt;/a&gt;, which I was also involved in organizing)&lt;br /&gt;&lt;br /&gt;Most proposals are going through what will hopefully be a more transparent, agile and effective review process than we’ve had in the past. The idea is that everyone sends in a first draft proposal, and then receives feedback from reviewers who want to help them to improve and refine their ideas. When everyone has had a chance to act on this feedback, the review committee will select the proposals that will be put on the programme for the conference.&lt;br /&gt;&lt;br /&gt;More information, dates and benefits of speaking are listed on the &lt;a href="http://xp2012.org/cfp/call-for-proposals"&gt;conference website&lt;/a&gt;. My next two posts contain more information about a couple of the session types we're looking for: &lt;a href="http://emilybache.blogspot.com/2011/11/tech-demos-at-xp2012.html"&gt;Tech Demos&lt;/a&gt;&lt;br /&gt;and the &lt;a href="http://emilybache.blogspot.com/2011/11/xp2012-team-challenge.html"&gt;Team Challenge&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;*Academic papers have a separate review track, and proceed much as they have done previously. The demands of academic rigour and peer review mean we won’t change a formula that clearly works for this kind of submission. See the &lt;a href="http://xp2012.org/cfp/research"&gt;call for research papers&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-6572688054861657659?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/6572688054861657659/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=6572688054861657659' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/6572688054861657659'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/6572688054861657659'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2011/11/presenting-session-at-xp2012.html' title='Presenting a session at XP2012'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-3735973407497466372</id><published>2011-11-10T07:05:00.000+01:00</published><updated>2011-11-10T07:06:27.388+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='geek points'/><category scheme='http://www.blogger.com/atom/ns#' term='feminism'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>Öredev experiences on my first day here</title><content type='html'>I've never been to Öredev before, and it really is a very impressive conference. Gathered in Malmö right now, is over a thousand developers, with a collection of speakers representing the elite of the global software development industry. The sessions are overflowing with a plethora of great advice, news and inspiration. That's primarily why I'm here, although I could also praise the excellent conference organization, food, live music, sponsor giveaways and other entertainments.&lt;br /&gt;&lt;br /&gt;I'd like to talk about my first impressions of the conference. As with other software conferences I've been too, women are rather unusual here, both among delegates and speakers. I've &lt;a href="http://emilybache.blogspot.com/2010/05/programmer-conferences-are-like-games.html"&gt;blogged about this before&lt;/a&gt;, and it's not untypical. The sad fact is that the proportion of women is low, and, unlike in other industries, &lt;a href="http://archive.cra.org/info/taulbee/women.html"&gt;actually falling&lt;/a&gt; in software development. &lt;br /&gt;&lt;br /&gt;I'd just like to relate two experiences I had yesterday.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Women speakers&lt;/b&gt;&lt;br /&gt;I'm here as an ordinary delegate at this conference, but at most conferences I go to, I'm a speaker. I was really happy to be greeted yesterday by Dan North, Gojko Adzic, Pat Kua, Corey Haines and others, since they're people who I really respect. I've mostly got to know them when we've spoken at the same conferences in the past. Of course they all asked me which day I was speaking on at Öredev. Well, the easy answer is that I was not asked to speak here. I looked on the Öredev conference website and there was no call for submissions, unlike other conferences I have spoken at like XP, Agile Testing Days, ScanDev, Agile, JFokus etc. I assumed that it was invitation only, and the track chairs would mail me if they were interested in having me speak. Now I realize that &lt;i&gt;I&lt;/i&gt; should have mailed &lt;i&gt;them&lt;/i&gt; to &lt;b&gt;point out&lt;/b&gt; I wanted to speak here.&lt;br /&gt;&lt;br /&gt;I think I just fell into this trap that women apparently often fall into, described in this article I read this week: "&lt;a href="http://www.linkedin.com/news?actionBar=&amp;amp;articleID=853663629&amp;amp;ids=3cVdP4NdzwRe2MTc3sTdPkOdjwIej8ScPoScPkU&amp;amp;aag=true&amp;amp;freq=weekly&amp;amp;trk=eml-tod-b-ttle-68&amp;amp;ut=3eUMeMiggbC4Y1"&gt;Four Ways Women Stunt Their Careers Unintentionally&lt;/a&gt;". Apparently we tend to be "overly modest" and "women fail to get promoted because they fail to step up and apply". So I didn't apply, and I didn't get a job to speak at Öredev. #kickingmyself&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Neal Ford's keynote&lt;/b&gt;&lt;br /&gt;I listened to a keynote by Neal Ford yesterday. I've heard him speak before, and he is always very entertaining and yet makes some interesting points about software. It's just a small thing he said that really bothered me. A keynote speech is supposed to set the tone for a whole conference - you have the everybody gathered, and you're supposed to say something inspirational and thought provoking.&lt;br /&gt;&lt;br /&gt;One of Neal's jokes was about some obscure Star Trek reference that I didn't get (although from the audience reaction I'm guessing most others did), that he followed up with a slide showing the top Google image results when you searched for this thing. He made some comment about google knowing that when you search for this, you're really asking for porn. He had helpfully airbrushed out the image results so you could only vaguely see the outline of naked women.&lt;br /&gt;&lt;br /&gt;Neal, you really didn't need to do that. Your talk had enough fun stuff in it without alienating me with science fiction references and disguised porn.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Looking forward&lt;/b&gt;&lt;br /&gt;There are two more days of the main conference, and plenty more good stuff on the programme. I've spotted a session called "geek feminism" in the "extra" track. I've never thought of myself as a geek feminist, but maybe I am. Having had the experiences described above, I think I'll go along and find out.&amp;nbsp;&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-3735973407497466372?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/3735973407497466372/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=3735973407497466372' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/3735973407497466372'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/3735973407497466372'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2011/11/oredev-experiences-on-my-first-day-here.html' title='Öredev experiences on my first day here'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-3552960703319303477</id><published>2011-11-09T08:03:00.000+01:00</published><updated>2011-11-09T08:03:43.249+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='clean code'/><category scheme='http://www.blogger.com/atom/ns#' term='ATDD'/><category scheme='http://www.blogger.com/atom/ns#' term='TextTest'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>What is Text-Based Testing?</title><content type='html'>Programmers have a vested interest in making sure the software they create does what they think it does. When I'm coding I prefer to work in the context of feedback from automated tests, that help me to keep track of what works and how far I've got. I've written &lt;a href="http://emilybache.blogspot.com/2011/05/tdd-in-terms-of-states-and-moves.html"&gt;before about Test Driven Development, (TDD)&lt;/a&gt;. In this article I'd like to explain some of the main features of Text-Based Testing. It's a variant on TDD, perhaps more suited to the functional level than unit tests, and which I've found powerful and productive to use. &lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;The basic idea&lt;/b&gt;&lt;br /&gt;You get your program to produce a plain text file that documents all the important things that it does. A log, if you will. You run the program and store this text as a "golden copy" of the output. You create from this a Text-Based Test with a descriptive name, any inputs you gave to the program, and the golden copy of the textual output.&lt;br /&gt;&lt;br /&gt;You make some changes to your program, and you run it again, gathering the new text produced. You compare the text with the golden copy, and if they are identical, the test passes. If the there is a difference, the test fails. If you look at the diff, and you like the new text better than the old text, you update your golden copy, and the test is passing once again. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Tool Support&lt;/b&gt;&lt;br /&gt;Text-Based Testing is a simple idea, and in fact many people do it already in their unit tests. AssertEquals(String expected, String actual) is actually a form of it. You often create the "expected" string based on the actual output of the program, (although purists will write the whole assert before they execute the test).&lt;br /&gt;&lt;br /&gt;Most unit test tools these days give you a nice diff even on multi-line strings. For example:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;img alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAADXCAIAAAAvPftMAAAJ4GlDQ1BJQ0MgUHJvZmlsZQAAeAG1lmdUFFcbx+/M9kbbZemw9N47SO9NinRRWZZe1mXpiA0RIxBBRERAETBUBaNSJBZEFAtBQAEVNIsEASUGC6Ki8g7wniQfkvdT3jln7vzmef73ee7cc8+ZPwCkTiaHEw8LAJDATub6ONkyAoOCGbhxgAVkQAdEgGaykjg2Xl7u4B+vD6MAWk0+0Fyt9Y+yv08IhEcksQCA7JF0GIvDTUa4AeHBtGQOwnA6wjQusiiEC1Y5ap1PrXLYOl9c0/j62CGa2wDgyUwmNwoA4kMkzkhlRSF1iO8R1mGHx7ABICkgbMmKZoYjjNxAIyFh+yoXIawS9pc6UX9hJjPsj5pMZtQfvL5+ZCbS2D4miRPPzFh7+TeH5Ih05BsAsNvOyeDGREUnM2yQnY7QYLiwWVoaDD0dXd1/s93/vdbqGVtv8s577exA9P4/Y8luAFj8BgBq8M9YcBIAZ5A9ENH/M6YiCoDwSQA61Vgp3NT1eujVBwY5t/yABsSANJAHKkAT6AEjYA6sgQNwBZ7AFwSBrYAFokEC4II0kAX2glyQD4rAUVAOqkAtaABnwXnQAS6D6+AWuAcGwQgYBzwwDV6BBfABLEMQhIMoEBUSg2QgRUgd0oNMIEvIAXKHfKAgKBSKgthQCpQF7YPyoWKoHKqGGqEfoUvQdegONAQ9hiahOegt9BlGwWSYBkvBSrA2bALbwG6wL7wFjoIT4Uw4Bz4El8E18Bm4Hb4O34NHYB78Cl5EARQJRUfJojRRJig7lCcqGBWJ4qJ2ofJQpagaVAuqC9WHeoDioeZRn9BYNBXNQGuizdHOaD80C52I3oUuQJejG9Dt6F70A/QkegH9DUPBSGLUMWYYF0wgJgqThsnFlGLqMG2Ym5gRzDTmAxaLpWOVscZYZ2wQNha7A1uAPYFtxXZjh7BT2EUcDieGU8dZ4DxxTFwyLhd3HHcGdw03jJvGfcST8DJ4PbwjPhjPxmfjS/FN+Kv4YfwMfpkgQFAkmBE8CeGEDEIh4TShi3CfME1YJgoSlYkWRF9iLHEvsYzYQrxJnCC+I5FIciRTkjcphrSHVEY6R7pNmiR9IguR1ch25BByCvkQuZ7cTX5MfkehUJQo1pRgSjLlEKWRcoPyjPKRj8qnxefCF863m6+Cr51vmO81P4Ffkd+Gfyt/Jn8p/wX++/zzAgQBJQE7AabALoEKgUsCYwKLglRBXUFPwQTBAsEmwTuCs0I4ISUhB6FwoRyhWqEbQlNUFFWeakdlUfdRT1NvUqdpWJoyzYUWS8unnaUN0BaEhYQNhP2F04UrhK8I8+gouhLdhR5PL6Sfp4/SP4tIidiIRIgcFGkRGRZZEpUQtRaNEM0TbRUdEf0sxhBzEIsTOyzWIfZUHC2uJu4tniZ+Uvym+LwETcJcgiWRJ3Fe4okkLKkm6SO5Q7JWsl9yUUpaykmKI3Vc6obUvDRd2lo6VrpE+qr0nAxVxlImRqZE5prMS4Yww4YRzyhj9DIWZCVlnWVTZKtlB2SX5ZTl/OSy5VrlnsoT5U3kI+VL5HvkFxRkFDwUshSaFZ4oEhRNFKMVjyn2KS4pKSsFKB1Q6lCaVRZVdlHOVG5WnlChqFipJKrUqDxUxaqaqMapnlAdVIPVDNWi1SrU7qvD6kbqMeon1Ic0MBqmGmyNGo0xTbKmjWaqZrPmpBZdy10rW6tD67W2gnaw9mHtPu1vOoY68TqndcZ1hXRddbN1u3Tf6qnpsfQq9B7qU/Qd9Xfrd+q/MVA3iDA4afDIkGroYXjAsMfwq5GxEdeoxWjOWME41LjSeMyEZuJlUmBy2xRjamu62/Sy6SczI7Nks/Nmv5trmseZN5nPblDeELHh9IYpCzkLpkW1Bc+SYRlqecqSZyVrxbSqsXpuLW8dbl1nPWOjahNrc8bmta2OLde2zXbJzsxup123PcreyT7PfsBByMHPodzhmaOcY5Rjs+OCk6HTDqduZ4yzm/Nh5zEXKReWS6PLgqux607XXjey2ya3crfn7mruXPcuD9jD1eOIx8RGxY3sjR2ewNPF84jnUy9lr0Svn7yx3l7eFd4vfHR9snz6NlE3bdvUtOmDr61voe+4n4pfil+PP79/iH+j/1KAfUBxAC9QO3Bn4L0g8aCYoM5gXLB/cF3w4maHzUc3T4cYhuSGjG5R3pK+5c5W8a3xW69s49/G3HYhFBMaENoU+oXpyaxhLoa5hFWGLbDsWMdYr8Ktw0vC5yIsIoojZiItIosjZ6Msoo5EzUVbRZdGz8fYxZTHvIl1jq2KXYrzjKuPW4kPiG9NwCeEJlxiC7Hj2L3bpbenbx/iqHNyObxEs8SjiQtcN25dEpS0JakzmYb82PtTVFL2p0ymWqZWpH5M80+7kC6Yzk7vz1DLOJgxk+mY+cMO9A7Wjp4s2ay9WZM7bXZW74J2he3q2S2/O2f39B6nPQ17iXvj9v6crZNdnP1+X8C+rhypnD05U/ud9jfn8uVyc8cOmB+o+g79Xcx3Awf1Dx4/+C0vPO9uvk5+af6XAlbB3e91vy/7fuVQ5KGBQqPCk0XYInbR6GGrww3FgsWZxVNHPI60lzBK8kreH9129E6pQWnVMeKxlGO8MveyzuMKx4uOfymPLh+psK1orZSsPFi5dCL8xPBJ65MtVVJV+VWfT8WcelTtVN1eo1RTWoutTa19cdr/dN8PJj801onX5dd9rWfX8xp8GnobjRsbmySbCpvh5pTmuTMhZwbP2p/tbNFsqW6lt+afA+dSzr38MfTH0fNu53sumFxouah4sbKN2pbXDrVntC90RHfwOoM6hy65XurpMu9q+0nrp/rLspcrrghfKbxKvJpzdeVa5rXFbk73/PWo61M923rGbwTeeNjr3Ttw0+3m7VuOt2702fRdu21x+/IdszuX7prc7bhndK+937C/7WfDn9sGjAba7xvf7xw0Hewa2jB0ddhq+PoD+we3Hro8vDeycWRo1G/00VjIGO9R+KPZx/GP3zxJfbI8vmcCM5H3VOBp6TPJZzW/qP7SyjPiXZm0n+x/vun5+BRr6tWvSb9+mc55QXlROiMz0zirN3t5znFu8OXml9OvOK+W53N/E/yt8rXK64u/W//evxC4MP2G+2blbcE7sXf17w3e9yx6LT77kPBheSnvo9jHhk8mn/o+B3yeWU77gvtS9lX1a9c3t28TKwkrKxwml7nmBVDICEdGAvC2HgBKEADUQcQHdq/7wTUFBGB9/f8Sov17XveMayojAKqdAQggAuC2H4DySQCUW5C67QB4UQDwNV33Moh2zQ+vzQFJkfp66z3Itog1ebay8k4JANwRAL4Wraws16ysfK1FvM4EAN3sdR+6Pu9/jf8BVkKvjQWGId8AAAAJcEhZcwAACxMAAAsTAQCanBgAACAASURBVHgB7Z0PWBTX2ejP9i7JYoFoFDSSfJhYEzBlSaWtqcqtu20i5I9LLH6JEUxMblka8wS4PmqxSu+H+WIhzaPwWMuaa6H+i7dQmyWJEFPBatJi+y33uvSTTZUEqrtFCGB20R3d+cp9z8z+md2dXZb/sPOeB3bPnDnnvO/5nXlnzpmdd47s2rVrBAMSQAKTR+ArkycaJSMBJEAJoBHicYAEJpkAGuEkdwCKRwJohHgMIIFJJoBGOMkdgOKRgBwRIIFJIdDc3NzX1zcpoqeaUDTCqdYjUtGHWmB1tVRaG7SdOBwNigd3IoHxJ4BGOP6MUQISCEpg/I2Q7frw+HtXbwXVYmJ2sgzDTowklIIEhkHAMyeMX/Xv/uXMH/7EP5Ewxk0Jj9W6dix//aMTP1S6tpzfN1r3PfB98um1V2feMm/I/x8nn752750+WSZuk+36uOSVnbpPLhaf/HRT6syJE4ySkEAIBDxGCJmfVKV+5b9F2Kw90TGx//wvxwdNhkA1DBCy9Z3zm749E64tckWUf7avPpB15gxLd8jvWEaW+WeYyBSWjVz+6k7yyToSMZFiURYSCImA13AULPDEm+uiombCJ8SDVGAjJPa+eYqomRCiFHL2auMm1VwurDl0vgsK3ur+4+6Df/YehA6c2LTmUBvYLyFM2xbVFiNEmUvFa7a8//7bUPYXxuuEvXpoC1eRqtjwBTd2HLj0C2fVm2h+Qtp+veGZt1tpLOSguDd1lXrZ1xaHXAAzIoEJJOBlhHANfGbzod+9tQE+IR5EjWhC3q05fOLE8ePHP+xiCSu/Z8P+C+CQcfJ1suXHp8BY2IHeDw/3+tTQe/ETm4OfljnaL7Y7YDdr7/zk0Mtv9XxkuPDCg1GNJalbIn9svnbtjLbzic11DCFdfz5cUvuYwXyt89N/e0BB64td9srmFff41BzCJut9RgihBGZBAhNCwGs4OjyJYCK3ye3btJBiXtJDjOHEofc+v0LILAJ2FhFixXICF9Xf1mxXzgGD7DijI2T578veMDCfNpCGb4OEmfc9QsiPcvLv3PnqC+okKmvOokdX0G8MSCBMCHhdCWEqyF8G4RPiQZoIlpO5LmfNc89t2LBqnpy0Hd/00NIK8tCKx5Z/k/TfCmKAdxB+p6PfU/vySO4SR4jDTkh6RsbaZ57K2vzRmY9/AFNKxaI1nRfOaB/4bN3Kh9/48Kqn0PBjk3djaPi6YgkpEfAyQrgZs2bLOwMD1+ET4sE53HLAhYoPA3/R1RLtC2uWLnJc+xSS6IiTH3U6M3i+Pr54hWWuvq194iKJ9p10yu/P0JKGj69GL1JCuC+W3ta5fvXSF1FJz20ufXM5+egy9T++0XXpUtcNT40hxWDEzMBwlLGDzgE0C6kezIQExp6AlxHC7dD3ft985s/t8Bnk1ihoAXPCOz0jzij1zq1Et27u3PhfXU5YfHFH/qE2esHjRo98Zk7xqMc25zfkr4xPSL2yohjukvBWDlW5gly93fBm1JaUeHqLZ+FLJ8Bi/vHx3tSFdGvLJ1m7fvAw5PysdsWKoyZXkZC+B9qOzY1/eMdFUrY6Ze7cfKP77BFSacyEBMaXgGysXm/BMgMMiYpSwC2ZAVYBd0zF9eayBd7NFWKgBiKndfGBloEqowJUKS4IU6c4gZMnT+Kzo3wfjdmBDb8W8j8XgvUEqdSdLcgh4qrJlSWUMq68+I0Eph0Br+HotNMeFUYCYUAAjTAMOnFaNmHRokXTUu9xUHrM5oTjoBtWGc4EZsyYEeWcwYRzM0NpW5DpWyjFMQ8SGCGBm1wYYeHwKobD0fDqT2zNNCSARjgNOw1VDi8CaITh1Z/YmmlIAI1wGnYaqhxeBNAIw6s/sTXTkAAa4TTsNFQ5vAigEYZXf2JrpiEBNMJp2GmocngRQCMMr/7E1kxDAmiE07DTUOXwIoBGGF79ia2ZhgTQCKdhp6HK4UUAjTC8+hNbMw0JoBFOw05DlcOLwFfoqz4wIAEkMHkEZIODg93d3ZOnAEpGAlIngMNRqR8B2P5JJxDMs/6hze8Nqd+nbz09ZB7MgASQQBACwYxw1SP/QmSDUHiQftAg47/4GCR6tt07MIIEkMDwCASbE5pvDG1k8V91Gejw5Apyw1K+tX95+JmnJ3EVUYE2GEUCE00gmBGOXJdhLeV7wzD3gSdOfnYt9asjF0jIwPEXFuY3+NSw/GT7iVT+ncQ+e3ATCUwZAsGGo6OZE8IShRO7lG9U5i8+TYe358sHfv10KrPr/KZH6CrC+E69KXOkoSIBCQS7OwpzwlXfuA/+Hn/E+bfqkfucf5AO8W/cF6hiWDttgpbydWngXDY4aiasMKOImcNvyr1XAr7a+AvngsKqLedhcVMaYF3Ft+gCNBBeOA7nDqbrvHOx4C3Hv3BVjt9IYPwIBLsSblsDC3QOGcTnhGAJsJRvVGL07duzVmatmskt5fuLpHmGt9c88eNTa5o2yOhSvoT83Kt+WMr3tthSvrr+fFjK94E5sJTvQ1siD5mvrbp0/IWVm+s6f73GtWqMpx5uRV7X+mfcSsCu4jMHIr65/0J70jzm7TUPl5566cSGpK7GN574ka78pCHz4ZnXv2AU5GpJyurIQ+evrZp5/IWHNp9I/fUafFG0hy3GxoNAMCMc7U0XWIFs/Jfy9TdCL0zClYAJiUpKZQynD733d1hQmNyCpdmYC/U6suFgVuq9AGLevVHs1fe5xYJ/9YZBQRcLVlq9asMNJDAOBIIZ4WjmhM6lfJOcNgJL+a7MH/hl3Y8fm9tTdm7US/mumGN3PLVuR1xo91zcKwFfh4tbPtlat2P13J7Ff+UW+ubWSPSstMhyV9AMTdaKGOJ46qkdcQ+MA3OsEgl4EQhmhKP8nZBbypc3Qn4p33dgKV/DIVjKNxYO9QjXgNFLHUJgKd+ND0ZX0aV800WX8l338dXSjepFcjJwHWZwwwnMP+obiPad9UsXkUOfXuz/Nhig4puwOPC6n73/UupTSTO/6Lo+c8Ej+aBDm33jD5fKCXsdFkrEgATGmUAwIxzlnNB3Kd916+bqSJZWyy3lu2L/t8SX8t3x8sr4fKJ9vXhxw5/Fl/LdnJoSv4ViWf5m+4kN/hdDWJueu8g5yXlWAlbc/8LW9HXrUnRksVabdbHkiUPq9g3q7b8t3vyDlXQNYL7C/2n47c7U1fE7uITXPzrxQ6WzIvxCAuNDYHx+JxTTdRyX8hUTFygNlgHmFhQmAwMD7tV/ubWABWsD0+WGGQKLkwZacDhQ7ZiOBIZPYOKMcPi6YQkkIAkCwX4nlAQAbCQSmGwCaIST3QMoX/IE0AglfwgggMkmgEY42T2A8iVPAI1Q8ocAAphsAl6/E17iwmSrhPKRgLQIeP1EERcXJ9r6c3+9krvn/aR/mXPip2tFM2AiEkACIyaAw9ERo8OCSGBsCIzECM2f/aHpYBL8QWRstMBakICECYzECP/WlKda/SP4g8h0Qccy/T2Wnp5+G7jbh3NgLXXVtX8HJ7LwC1zTOoffNMYmUkaQyLY2HNPpdLXnLTwzW38PBJEyvkjZsTqYRmKEvsqM3batpUwmK+sfToW0RElz0BL9DWU5EZF3x8XHxd0dExkh07WCo9UEhRDUG0ITW2u1TBAqWkTwDLi5MX/XbFxrCcsTjf0KNK2Lf6h/CGb8buacrjBFJotccUCAzD/R3rRtfV5LJy3Dmgplspi74d5IXKQss67dfZwwOnVOi5sq26nTZspkEZoKQ0iKDJVpJEb4z/8aJMwN+KORMQ2Ri541GJ/1+D2EUPmD2W3GFx+CjKwJDtbMVt8zGNu4a2XGNnONsRveNe6wWy8bzi6b7esjFYKcEWZxqzfC8rQYvCpAWd/RZ+2jIVc5y7+qqAezjcbnKDf5HSvJSv8MUzeFNcHhrPPrNhGFI2eoiEok3SfJ1mPpd5rLHfesKj2aC/uFvwGIJpa/Wpy1dD4hMWvOGq1woAz2VWXrNfs+gbKWxl1qbUlLr1FXrFUX1lFpLEl4Mq+qADzhxuZAGsII4b5o/i9P1Z5rA9H3xd1FNQAd2H8O3vgS/iDCp7g/Leer1fxpW114zkINgjEdy8ypqNVpZTL1eRthOhu1cHaCjczMlJRCn2sSa/6kZN8ndlqqWp1TzZ+ITNXaHF2rqypdY+0uToLzRNX1R92+xqtggpuSNhKiV0bKtNU0szMwxteLjUX1R7KSYyFFroheuCQteT54OTLnq7e7NK3mBzmmY4Xairpj22kLUgqPmVrr+LaUNbTT2hhToVpbW6fj1JdtP0bPjGxnQw6/LVPrznHjGT5bbQVUUtbS71SPEJupzpkz09ku1nKeEwUZ1dXnuDMxLVtY13gMjktavI6TS2XfHx8/K3oWDeDX4S+U6TqzY9/HXucfplWbom3hCHpgeusGFen4zkgpPN9DD9yB1kqZqtLXTdMv2/mKHFlmRSd3qLceAzm1IJqjV1tNrz1wMtzVwlXIWM45JWire2hDAJnl2Ha+fbJM3Z9qNyXpCclTRqZoj4Gy/vndKeqs7CYSwx/1rZUaVXkLX5/nk7E06AplMXFHPocjCIJi6er0lckPE6MnS4BEwji4IvL5aWnJ3DVg1qMrVORCJ6gUt+zVnz9GDhiNB658p6rkca7ihPTV6an3q3q9iAulDDMOVn/NFegpwDucbf37M//rN4kv7X9t/4fuPe/vWfjP//sq/EHEnUgj5noQXnr6smPQerZcQ0hBx+Cg1VgJicqimo7uPvtgB5w+VKWnrQ7H5fpSiDZzpx13JVZDOSHlkOaOwC5DuUpZaoAIXxXRlF/uNtfACa6kme7dm5zM7e04XQJy9G3dVrvDXaHdWAVSDN5SYK+5nipyusPqsHeUw+k1Vw9ljJWgMyk4aui+XM+dcrNPX+42VGWDSn1UvIHuVpUYzN1tVHlSc9luNxvPGs2wsxlqUVZSOXw2ZZGhw2y1u9VzUIEF9SClr7uP06+jCCoDFIOOjrPQaqLvAGycCELlGmkLS0Eu3+qiyqqjVVVVegOU9RdqM+wlZK8NpNsNcCX8E8TsBrhu8Hg9ML1041XiGl6lIZqjdhgpXDPWn27j1IO6+CCSbdBxGZQnRfXmtqPwXW+mJXh6JTWG7u62UsCXXePgurtAf5leWKiENpBAOZCCsx19dmu3Gfqqox78NYvq2/oAlkh+M6VUftbusLfpoX+dLbrWdva08ZpLw0GHtUNfCriIqqDSaPbqbKvReUS5M0PEO9FariSlBtrDnmA+zWlFexZQVmmUVc3NRXB0cS3ls7kPS35zNJ/CCzW0wjekff0++PNJfTCt6ILpECRCRLir8z9+B8fND9ULodK03GJVfuon7bufpqOpkt+/kQVXIqa9fi9RNv9IHS0n0d/PUJEGYXEad1/e3RFBGjcwKzK/+xqMG24+rFIyfKbZfCVzY+FHztn3LoiN5r35uVQHle4f2P/43V5labM6Ac560bnl5fnKmsvlq8ktKyk6u+f5JXDdylSS9Kr96oXRzM1vQXmKKYJYQXn9ziVQaH52Edn22Zd2xcLkr9vPH9PVtn8OwmGcwmcjp3//xhJ66YXAqydf8K1csj5j491VW/OeS6aX0L/s5lGABmkbK5X5NZ9cXr0GRBC9+bB6PmFuUj9jd/fYb5Hbd8I/FaGY7ys0QoCLE+r94d5Lm+DSjW3/ECxX9UHx9mb7RT3RL4Nrway45HS1d1m20z+bQr7wjb6zF+/+7/G7Sclpc/p8Ts1bVkC6MwvokY1bC7ZlWPpf/wsnYd/25kgqIfVLaDbUlltTkJYwC7LNB5JM3P3wdp84uNArgIlPftbyN0ppYxpc/xOfyFSRJl65uMQ0l5o9tdt/uHa3Hs6dZruODnFGHWym2piktblHjW+kw4EGQfHiuxfo9yD3SWNjHNy9PIx6F6W+XHMSTktk7XMvC4uxAzdBY2GNt/lptPIuHo48EvzgZzstjXX0Cgv7x5XgIk+DgxFkVM6DjqOJ3Kfww2lvsEPQE9ELHlGRvNq/WJbAce0JvKbuYxME2aAc/ClnOt9ADEkMZ1Pegma7Dndncmt1jnKj7ejZXU/e01Xc6H53juqrAh14sYnP68zJzxws26aM2wgXvcfZ24DCVRulYnPCUt3LtdBbrualV15MdpENINTTPFfMxc0Bwya3Qm7dHNBbmsxnNqjibjqyXvqZE6yrrPs7QDbWAfYMIW5mJJ+VKqyY4YnTaQvdynw2RzWTOLKyfjZvESFmEDrjDj4X9+mg5wU++Odn7TAgF1By5RR8z/ruhs3lvdb8vaUHU+blPaeOdTdUkCn0qM10LCZpfZWx78VkepoIEtxHT5A8Ie76Soj5fLKt3dkJfz6JCcthvJb/Xms/pJve1zWR7Ee/pqCHttGZUR73YDZpyi2qbmk9t+uJVCM/xIdbz5XltS0Wr9poqY8v9bOdjRWp24z382QFVXll5jYiZ8whpPc69xME291SWVbZAncJo1MKCsju72U762eZ9vMN5zvJck2uMZ+/S2p7f18eyc52vZLKWbHoBTSGNH1wygSHVn9r026w2HmyP+45Qgrynk9LcvzjIpTkjjp/1eieTpMpMjl959tHgJGpy6ZYuDSXNO050Qr7bKb38prIv6bBMUoDPZp9g/UmP82h6TYRof5laIqxraOfsTTmpG4jKucZzVOx/GvPFBB9Y2dM0hIIC+ZS02cHLK0m73urYtkI6dwe9734o0YYM+el/qCRm+1F3BljPPiuid4U6T9zdC8pePCehd+CkVLjX29wEpRzoyMIV9venbrWfjjF2Sw9NhJ5FzT7yxsw+SIKv/yK+GQNadKdaGXZ/sb9O91zwgGLyWThp67y2MS013SNVnPVXX96He5pasvquHsRtKGgCnMTTkAMHBTurhFNpLkhsO3FSetJkV6zSE5/pgAlAwSoj1Z864ag4gBZQ0mGsaxrSugZZAcf4F5tP9P4vxPhDyI+Odtq6BWSC6oaIzeTgkG5kk7z+GC9fLpAA+NtVXlNlXPSYjesJmTlXn7WV87PCQftbUWQC4KqqLRAqSp37XVVZXRNFI2/XMnPCWGiR+ehcHavNNqMv4TIXgOdJcH6izUl3A66EwIMPWH60acv4uZ9kKAq4jSFWY1z8gmzhkolKeemknT+wAu10wmbhipPQxGd6gx21Dvbm11QADtANEzGNK6pC2RwqWeFSZEzZJfD7A+Cta3GpQEpqjHSJEFZt1xuTqgRTmv9hdqMe0myc064mp8TDlr1VCMImtLyXKLi5quC+jlxHZXZTqX4DDYDzHXpRNQr2H2z1YNt5dYARNCYk1ICkyc6J1S66ChL2vjdHafpXI0LfCcO2i/z3QRpXIrjbCnfbVVwkNj98htdR5QqF3R1cqBq/tufvJTkNuzdbZW5mvJmvgVWbo7vlE67hgb/RDonLDdy6jrn5M4iTmhcMa8P7khwZSKV/P1UrxzD24AVl4ZthGB+g5//dPDzF2jEP8DvAFar9+Tekwn28Rt99B6Mhm87TXHQEn1n4Zjm7oJwSda+gPXQ/WLBLrwtI8jgsPbBWqh9fU7p/B5OU46+IGfAKHerw2CH2wBWehPBFWgl3CakC24JuXYLvsXEcZUFgiUo6xMNUShVbajKaW8J2+MjybU5ZDZ6o6IcDnQHQPaWSdvoowetTaCZHYKnjF9+OxwIAuIulcbomxqhqqj8NPcj1hjVObxqXPMMt12HEPnCAgN7GtwRftP5Cb8DCO+NeO1j338lZu0RAqdoGKIW1bQlu0bwNuP+mNR8yAsTYtdgXB49i58AelURfEMRQDTUFetXWTBNRcTAJLbX4SDy6GhhTbQSLjOkB6cpJs6nMhGpokkhCnWpJlqHMzFIbwmLDZ2N6TXeggNDPsu310Ta6FObQuE6DqhIv/yK6FnC/UK1xiAeuWJXFTF1d113HtVjUOUwqwjJi8KnTnhk9I9HN0DisvWH4h/4rs/eITbh+bH+PrvDEREdH+t10DI9lms3I+5O8LeVIWqcuN2MzTakpU2cNlNNEsvYWHm01425qabiFNVnJEY4RZuCaiGB6UlghHdHp2djUWskMBUJoBFOxV5BnSRFAI1QUt2NjZ2KBNAIp2KvoE6SIhDQCENxbWQhEzz14P9cAUufUfANoom+mXAbCUiOgJgRBnJtZFsy1TqXxTG1hbII8H+Mj4uJ9DjdsJbGQnWKLCKywtDvZima6N6LESQgcQJiRijm2ti4KzNnd621t76kMLOwlvq5PbTmrJl7NAKcfbZpDvKPfrKOr6q2llJvFcHzraKJEueOzUcCbgJiRijm2risYL/GfrHXqL+SWFT8VAI8bZucljaf+7V98aMrCLnYRR/BJYoE6kiZ6Hy+0ilFNNGtAUaQgMQJiBmhG4ml8dm8pqKtT8NjWYrIXv3uufsMNcY8vdXrqQjLm8/mkaI8pedRLoeYC4JoolsSRpCAdAkEfNrR17VRnnx4UAecLgxmeWjZTNtjknbnHu17Iz1gRZ7cGEMCSECEgLjthOTaCG8xiVHerDIMvrjEp2LOI9YnjYgm+mbCbSQgPQJiRujt2ggPtceKPMTO1hUpD5CiNs0ieE0jC8/Ox87i6gIvRwaGo7dugBcqjFD5+kUTpQcbW4wERAmA55OvU29Iro1ezpFub0vnu5ickrLB+w6CaOLwPK4wNxIIXwLoRSF6asJEJDBxBL7yna2miZOGkpAAEvAjEPQnCr/cmIAEkMCYE0AjHHOkWCESGB4BNMLh8cLcSGDMCaARjjlSrBAJDI8AGuHweGFuJDDmBNAIxxwpVogEhkcgoBGG4tQLby+El4WH5NQL7zwH919/T9/haYu5kUAYEhAzwpCceklrhTrybrqoKTj17mpwrksh6r/LdDaoI2Liwf03Qt0wgvWOwxA7NgkJeAiIGWFoTr0L1h2BBQchNJeqirc1cO6ERMx/1/LmgoxFR+lKAIaq+IwFFc7FIj06YAwJSJqAmBGG5NRLomPn8891R5Becj+suEODv/8uYzpVTFTaNcmwd0n2VhXZ9oHJ9YoMrgh+IAGJExAzQjeS4E69THtFoTZHLUvdNttw+HnBYgFe/rsOurVoBu9NYacLdgmX+XKLwggSkCwBMVcmDsbQTr2KeI321aWWx+aQtRuLaz/ek+XxrffFOUPwxhnffbiNBCROQNwIQ3LqhbFnYjL8pc6vjEjaf7Eka6nLCoX+uxERsHXhS7gvCqIiI2IIuTNCXKjEewKbL1kCYsNRb6feQOuV9lt6+LmdsaWFkBjXxU7ov0t/kVAkPl5Emg6foi9oM/1mn56UPJ3sMlbJUseGIwEhgUe3tI3MqRcW2nWHyrOwVCsNov679st61+vXVPUd47faI68CfiKBaUZgNE698ALufnjTtgKW3xxygMna4IoaUk63ZWMECUiDwGiMUBqEsJVIYJwJiM0Jx1kkVo8EkICQABqhkAbGkcAkEEAjnAToKBIJCAmgEQppYBwJTAIBNMJJgI4ikYCQABqhkAbGkcAkEAhqhL5r67LUh7eHd1oCXZnztdU6XfV5SzCvCJbxdeW19dDlfSehrSgSCUxJAuJG6O+by7TXymQR1Ic3LkaWWeb0Rrp9JS9v4x+6YNkJGlorcspaPAZpadRxi/ZqDB6LYxp2qWPi6PK+6l2Nnqx8efxEApIkEMAI/Rbclcc8dNbIPZvWZ8jWb9OdgZV5FUufL6rkH0izNGSqte/8p7nhcEmmens79xoLR0TC1tIqIdWexpKM4kVGKzzeZogv/t6b59C/V4gH4xIlIP68GfXNTWD+oSRfurDIY5PTYrmNWYtXqMj/6ewiZD4hdud6oHEr95f3ZWc3Nxl7m80/S+BqTUhLT2BbVeSQqw7mo4rdynIj9/z2kp9UqpLe+mhLmtAR0ZURv5GAlAiIXwk5Al6+uW4mlsY385rI1qddj2TzO+QKq6E+vnCfvqD5uNHqsWyWevG6gsNmJco5TtfCm2C+n3/hHMi6cuA3EpAgAY+9hNJ4U+32pLW7jxr70uf7Fkx88fBhWsWF1UErmnEH+vcGBYQ7pUfA15aEBIS+uZBuOqZNWk8MfYNLZglzDSN+ZwxpttzkC8yA2mfHBBM/jIoxKxKYxgQCDUd9fXPZzrqk9QeK9IWL5PR3CurCNGSAOuw3INdthiE0e/TjeQXG/Hfa4a6orXVPXlPRjsfRvXdIipgh/AmA/6OvU6+Yb663ty5RlRs4x0k73B0thYujWDBWajz4NFVwT3Rw0K4vck4mVSX16N4rhg3TJEdgNP6EbGvDweyMvPWGvq3DGaHCu70ZooidhVdBzzkKY1ImMJpJGXu969bL5ZXfmB05LILR4Ik/rAKYGQmENYHRXAnDGgw2DglMFIFAN2YmSj7KQQKSJ4BGKPlDAAFMNgE0wsnuAZQveQJohJI/BBDAZBNAI5zsHkD5kicwUiNkLXXVtdNiwU9/r2LodGEi29NyDJyTdXUWz1NArC2ER4IYkTWKJX9AIYDhExipEdqvaDau7RL6SAxf9niXEPMqJv6J9isfr9+4v/vWbdoatlOnzQT3ZU2FQaiet78yc05XmCKTRa440C/MhHEkMCICokbIwvsnhqgtIkJFVBEheESwpmqZLLN14rzobRaL05Pf36sYGiWSCK1QvrLltSzqBsmShCfzqgrAY9nVNjF/5TvuWVV6NBdqG82zDkMQxt2SISBqhPYTGXGylMKGVnCfDxZMp3RwQYCw/VgLHcoxrdoUbQtnAoypWp1TbWNNm5I2EqJXRsq01a3uuiyNu1JyjnEZLRWZKdtr6ZpNLD3cK3rYzrIcvlaZVneOGyHaGspyODkyXSstNNBaKVNVDrirc0aY1gadWhaTUXuJTwCv4vTvpwrWraHJoonEeMt5UVckpK9OT71f1es+a1B/5e82N/c27e0tOrKF81dWLF2dvjL5YWJ0CsYvJDAaozevhQAACnZJREFUAqJGGK29YDeWJpYp42UybW1Lp2euJBAVQ5rW7+2uMne31ZfuXp/6LnWOcFwyXuKPZsdNa9MRK5Enbj9dAhcafVv3z59LcpeOS0wxHim9CCU6z+TrjbuPUGNre69M/+jXY0nEd3KPwNPefc3lB/LeMkIeS1PGtiP1ZsegvW/NAvqInGLu8vqdKwVrA9ta6spSZJHKMtNWo/nCa0vcgoiXV7ErWTTRtRO+nQbJpwTwV/bKIyiLUSQwXAKBxlOK5HRt46DW0nIsI3XBWqI5anj7+SX8+y2cIsBLvlm/cwk8Bjo/u4hs++xLO4kXSHeN5ubGxoHj4L0LYqMFRiOf/50SYjx1oeeu/1evzC0gB063MU/W5zVVGvVEHv2dr9tPVus6uj+H6hxwsN/9IIz8MjI2VpVufS49GRLlccnpaqeslmO7UtcXE1LQbLYvnS+QIdBllNEQ/ZVHKQWLS5aA6JXQSaPH1HhwT6mRqEprNj+22N+Td7ZrTii8KvQ6Czuc4zkH4V5DI8xCc8Q+Waoq/lXVnv3m0p9ueUV15FcHKreRgvTkaFurLuLur12IWvz495criZXmVSTq7Ob6wgf3ZCgjtzf4XJYXP7a2phzmcHv3HTxuci5bSguNJrhOIKOpA8sigVAJiBuhpaVOmyKLS3r9rrXgB9i4NSstVuF7zYTh6AenTGAS/a1Nu2HEOS+aG8YZ2zr6GUtjTuo2ogLneRI5Yw4hvdf97vgvXr2BHNh2gKQvnT9/2bOavfnFqvKcBEI6DPWEFL2clTbb0cvPudj+TtO16PQXdx4BB8Xdf4NJITtgaTU5f1BQxCZmvbZn0Gpef9eFpLjIFG1Fi/s9qL5exRwU0UQBLth/E04gt25ARJDsFYUdDM3EQLMCZvIqgRtIIDAB8KD0c+rtq8zWVJ5uC+Z0azeAx65G4/TQLdJf5jwxrfoCPkVTWp5LVJWcI6+5nHPu1VQavbw1HZfh+qWpoon2tqOg4NHLVKCjo56/laLMLsiGylRV3W2e9yaWn6avXbQZSgkpFXEltnefrszNLm/mBYl5FQ/6J1qN5URZ6Wws1y43rUr6ekb/YPVyV/Zpl392TEECQQmM3JWJZVm5XM7Y+h0Rs4TzPcZmI5HRPhdO+F1b7pvmPtT9IvBTup1EQ6WszcbydUHMHuFXrV/JkSTYWipiUt+tPLpjzb+qY32v9yOpEMsggWERGPlBBxYIkhTRs3xuhiii4V6Nb1AIzdR3p9+23FWHPNq1EDfERKr1KzmShMj7VlSVk+6rXc5XUI2kDiyDBEZOYORXwpHLxJJIAAkICIjfmBFkwCgSQALjSwCNcHz5Yu1IYEgCaIRDIsIMSGB8CaARji9frB0JDEkAjXBIRJgBCYwvgaBG6LtSr6gqYv6vogVFE0WrxEQkICUC4kbov1IvZcK2ZKp1zkdC6aaI/6toQdFEKUHGtiKBYAQCGKHfSr2NuzJzdtdae+tLCjMLOfc/Ef9XMEy/giBcNDGYUrgPCUiJgPgTM/4r9S4r2N+3+5VdRv2VV5ornoIHreFhGfB/TWjtUO3xXBwhzXeJXy6jSKKUIGNbkUAwAuJXQq6E10q9ishe/e65+ww1xjy9VfBgqK+LEi3pVdAlXDTRtRO/kYCECYhfCUWAyJMPD+og/cJglsheTEICSGCkBIJcCQl1BxwqiPq/ihYUTRyqetyPBMKfQCAjBGdVBlzib92ww42VQBjE/F9FC4omBqoV05GAxAiAt6GfU++g97q82QZR914x/1fRgqKJQb0ccScSkBABdGWS2EkXmzv1CAQajk49TVEjJBCmBNAIw7RjsVnThwAa4fTpK9Q0TAmgEYZpx2Kzpg8BNMLp01eoaZgSQCMM047FZk0fAmiE06evUNMwJRDUCENyww3NqZeFZQN7bAGfvQlTutgsJBACAXEjFHfDHalTL9PZoI6IiY+Pi4lQN0yLJbZDAIdZkMBYEQhghH6+uaNw6rW8uSBj0VG65oShKj5jQcVQiwCPVdOwHiQwPQiIGyH1zU1fmehc7oW2BJx6NfaLveDUm1hU7HHq9V7Uljr6+hZkTKeKiUq7hq4ruCR7q4ps+8Ak8AKeHpRQSyQwjgTEjZAT6OWGO2KnXgetZtEM3m/RTn2ArTfBMwMDEkACTgIT49Q7Q9TtEDsBCSABIBDkSjg2Tr0REeDNe+FL/r5oZEQMIXdGhGz52EVIQAIEAhlhSG64oTj1KhIfLyJNh0+1A0zTb/bpScnTyeO1yJkE+gubGI4E4KbleDv12i/rXbd4VPUdog7CEvLgxKYiAR8CE+XUy9p6+hnFrFjXop/heD7DNiGBERGYqOmZPDo2FkehI+oiLBTuBALNCcO93dg+JDBlCKARTpmuQEWkSgCNUKo9j+2eMgTQCKdMV6AiUiWARijVnsd2TxkCaIRTpitQEakSCGqEYk69LON2zWXO11brdNXnLcG8IgT5nYxtPT3g3ytV4NhuJOBLQNwIRZ16LY06dYosIlJjcFvQ7St5eRv/0OX0imityClr8RikSH7CNOxSx8TFgX+velejJ6uvVriNBCREIIAR+jn1AhJHRMLW0ioBG8XS54sq+QfSLA2Zau07/2luOFySqd7ezj2u7Zef9DSWZBQvMloHB62G+OLvvXkO/XsFODEqVQLiT8yILribkJaewLaqyCEBKzs4C9IQt3J/eV92dnOTsbfZ/LMErla//MxHFbuV5Ubu+e0lP6lUJb310Za05xV8DfiJBKRKQPxKyNHwcup18mHFVuaFfXKF1VAfX7hPX9B83Gj1WLZXfofNSpRznK6FN8F8P/8C3XuleuBhuz0EPPbiSRtRLPHFw4dpwQurgxafcQf69wYFhDulRyDIlTAkp95hEbszhjRbbvJFZoCv7+yYMTsHDEsPzIwEphKBQEYo5tQLafYboPxthgm8eq+gcb75ox/PKzDmv9MOd0VtrXvymop2PI6OFQJeGJUqAfAvDNGp11ip8UDSVME9zsFBO9wdLTX0+Tgp8pui+fVFTv9eVUk9uveKcsNEqREYjVMv29pwMDsjb72hb+uSWR77HCpm6+9hiCJ2Fl4FhyKF+6VBYDSTMvZ6162Xyyu/MTtyWKyiwb9+WAUwMxIIawKjuRKGNRhsHBKYKAKBbsxMlHyUgwQkTwCNUPKHAAKYbAJohJPdAyhf8gTQCCV/CCCAySaARjjZPYDyJU8AjVDyhwACmGwCaIST3QMoX/IERI2QhfdPSJ4MAkACE0RA1AjtJzLiZCmFDa2WCdICxSABCRMQNcJo7QW7sTSxTBkvk2lrWzr5xQUlTAmbjgTGkYCoEYI8RXK6tnFw0Gz47q7UBRGyzGMtOEAdx27AqqVMIJARUiY9psaDe0qNRFVas/mxxcPwk5AyUGw7EhguAXEjtLTUaVNkcUmv37UW/AYbt2alxSpG428xXK0wPxKQEAFR0+p/b8+vluxps6sT8VVoEjoWsKmTRABdmSYJPIpFAi4C4sNR1178RgJIYNwJoBGOO2IUgASCE0AjDM4H9yKBcSeARjjuiFEAEghOAI0wOB/ciwTGncD/Bxq+coJQ6WaGAAAAAElFTkSuQmCC" /&gt;&lt;br /&gt;&lt;img alt="" src="data:image/png;base64,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" /&gt;&lt;br /&gt;&amp;nbsp; &lt;br /&gt;Which is a failing text-based test using JUnit.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Once your strings get very long, to the scale of whole log files, even multi-line diffs aren't really enough. You get datestamps, process ids and other stuff that changes every run, hashmaps with indeterminate order, etc. It gets tedious to deal with all this on a test-by-test basis.&lt;br /&gt;&lt;br /&gt;My husband, Geoff Bache, has created a tool called "&lt;a href="http://texttest.org/"&gt;TextTest&lt;/a&gt;" to support Text-Based testing. Amongst other things, it helps you organize and run your text-based tests, and filter the text before you compare it. It's free, open source, and of course used to test itself. (Eats own dog food!) TextTest is used extensively within &lt;a href="http://www.jeppesen.com/"&gt;Jeppesen Systems&lt;/a&gt;, (Geoff works for them, and they support development), and I've used it too on various projects in other organizations.&lt;br /&gt;&lt;br /&gt;In the rest of this article I'll look at some of the main implications of using a Text-Based Testing approach, and some of my experiences.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Little code per test&lt;/b&gt;&lt;br /&gt;The biggest advantage of the approach, is that you tend to write very little unique code for each test. You generally access the application through a public interface as a user would, often a command line interface or (web)service call. You then create many tests by for example varying the command line options or request contents. This reduces test maintenance work, since you have less test code to worry about, and the public API of your program should change relatively infrequently.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Legacy code&lt;/b&gt;&lt;br /&gt;Text-Based Testing is obviously a regression testing technique. You're checking the code still does what it did before, by checking the log is the same. So these tests are perfect for refactoring. As you move around the code, the log statements move too, and your tests stay green, (so long as you don't make any mistakes!) In most systems, it's cheap and risk-free to add log statements, no matter how horribly gnarly the design is. So text-based testing is an easy way to get some initial tests in place to lean on while refactoring. I've used it this way fairly successfully to get legacy code under control, particularly if the code already produces a meaningful log or textual output.&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;No help with your design&lt;/b&gt;&lt;br /&gt;I just told you how good Text-Based Testing is with Legacy code. But actually these tests give you very little help with the internal design of your program. With normal TDD, the activity of creating unit tests at least forces you to decompose your design into units, and if you do it well, you'll find these tests giving you all sorts of feedback about your design. Text-Based tests don't. Log statements don't care if they're in the middle of a long horrible method or if they're spread around several smaller ones. So you have to get feedback on your design some other way.&lt;br /&gt;&lt;br /&gt;I usually work with TDD at the unit level in combination with Text-Based tests at the functional level. I think it gives me the best of both worlds.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Log statements and readability&lt;/b&gt;&lt;br /&gt;Some people complain that log statements reduce the readability of their code and don't like to add any at all. They seem to be out of fashion, just like comments. The idea is that all the important ideas should be expressed in the class and method names, and logs and comments just clutter up the important stuff. I agree to an extent, you can definitely over-use logs and comments. I think a few well placed ones can make all the difference though. For Text-Based Testing purposes, you don't want a log that is megabytes and megabytes of junk, listing every time you enter and leave every method, and the values of every variable. That's going to seriously hinder your refactoring, apart from being a nightmare to store and update.&lt;br /&gt;&lt;br /&gt;What we're talking about here is targeted log statements at the points when something important happens, that we want to make sure should continue happening. You can think about it like the asserts you make in unit tests. You don't assert everything, just what's important. In my experience less than two percent of the lines of code end up being log statements, and if anything, they increase readability.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Text-Based tests are completed after the code&lt;/b&gt;&lt;br /&gt;In normal TDD you write the test first, and thereby set up a mini pull system for the functionality you need. It's lean, it forces you to focus on the problem you're trying to solve before you solve it, and starts giving you feedback before you commit to an implementation. With Text-Based Testing, you often find it's too much work the specify the log up front. It's much easier to wait until you've implemented the feature, run the test, and save the log afterwards.&lt;br /&gt;&lt;br /&gt;So your tests usually aren't completed until after the code they test, unlike in normal TDD. Having said that, I would argue that you can still do a form of TDD with Text-Based Tests. I'd normally create the half the test before the code. I name the test, and find suitable inputs that should provoke the behaviour I need to implement in the system. The test will fail the first time I run it. In this way I think I get many of the benefits of TDD, but only actually pin down the exact assertion once the functionality is working.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;"Expert Reads Output" Antipattern&lt;/b&gt;&lt;br /&gt;If you're relying on a diff in the logs to tell you when your program is broken, you had better have good logs! But who decides what to log? Who checks the "golden copy"? Usually it is the person creating the test, who should look through the log and check everything is in order the first time. Of course, after a test is created, every time it fails you have to make a decision whether to update the golden copy of the log. You might make a mistake. There's a well known antipattern called "Expert Reads Output" which basically says that you shouldn't rely on having someone check the results of your tests by eye.&lt;br /&gt;&lt;br /&gt;This is actually a problem with any automated testing approach - someone has to make a judgement about what to do when a test fails - whether the test is wrong or there's a bug in the application. With Text-Based Testing you might have a larger quantity of text to read through compared with other approaches, or maybe not. If you have human-readable, concise, targeted log statements and good tools for working with them, it goes a long way. You need a good diff tool, version control, and some way of grouping similar changes. It's also useful to have some sanity checks. For example TextTest can easily search for regular expressions in the log and warn you if you try to save a golden copy containing a stack trace for example.&lt;br /&gt;&lt;br /&gt;In my experience, you do need to update the golden copy quite often. I think this is one of the key skills with a Text-Based Testing approach. You have to learn to write good logs, and to be disciplined about either doing refactoring or adding functionality, not both at the same time. If you're refactoring and the logs change, you need to be able to quickly recognize if it's ok, or if you made a mistake. Similarly, if you add new functionality and no logs change, that could be a problem.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Agile Tests Manage Behaviour&lt;/b&gt;&lt;br /&gt;When you create a unit test, you end with an Assert statement. This is supposed to be some kind of universal truth that should always be valid, or else there is a big problem.&lt;b&gt; &lt;/b&gt;Particularly for functional level tests, it can be hard to find these kinds of invariants. What is correct today might be updated next week when the market moves or the product owner changes their mind.&lt;b&gt; &lt;/b&gt;With Text-Based Testing you have an opportunity to quickly and easily update the golden copy every time the test "fails". This makes your tests much more about keeping control of what your app does over time, and less about rewriting assert statements.&lt;br /&gt;&lt;br /&gt;Text-Based Testing grew up in the domain of optimizing logistics planning. In this domain there is no "correct" answer you can predict in advance and assert. Planning problems that are interesting to solve are far too complex for a complete mathematical analysis, and the code relies on heuristics and fancy algorithms to come up with better and better solutions. So Text-Based Testing makes it easy to spot when the test produces a different plan from before, and use it as the new baseline if it's an improvement.&lt;br /&gt;&lt;br /&gt;I think generally it leads to more "agile" tests. They can easily respond to changes in the business requirements.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Conclusions&lt;/b&gt;&lt;br /&gt;There is undoubtedly a lot more to be said about Text-Based Testing. I havn't mentioned text-based mocking, data-driven vs workflow testing, or how to handle databases and GUIs - all relevant topics. I hope this article has given you a flavour of how it's different from ordinary TDD, though. I've found that good tool support is pretty essential to making Text-Based Testing work well, and that it's a particularly good technique for handling legacy code, although not exclusively. I like the approach because it minimizes the amount of code per test, and makes it easy to keep the tests in sync with the current behaviour of the system. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-3552960703319303477?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/3552960703319303477/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=3552960703319303477' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/3552960703319303477'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/3552960703319303477'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2011/11/what-is-text-based-testing.html' title='What is Text-Based Testing?'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-6960256928582387078</id><published>2011-10-14T11:43:00.000+02:00</published><updated>2011-10-14T19:52:53.271+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='clean code'/><category scheme='http://www.blogger.com/atom/ns#' term='Code Kata'/><category scheme='http://www.blogger.com/atom/ns#' term='teaching programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Coding Dojo'/><title type='text'>The Clean Coder &amp; Apprenticeship Patterns</title><content type='html'>I'm speaking next week at &lt;a href="http://www.scandevtour.se/2011-tour/"&gt;ScanDev on Tour&lt;/a&gt; in Stockholm on the subject of "Software Development Craftsmanship", and as part of my research I read both "The Clean Coder" by Robert C. Martin and "Apprenticeship Patterns" by Dave Hoover &amp;amp; Adewale Oshineye. These are very different books, but both aimed at less experienced software developers who want to learn about what it means to be a professional in the field. In this article I'd like to review them side by side. First some text from each preface on what the authors think the books are about:&lt;br /&gt;&lt;br /&gt;Apprenticeship Patterns&lt;br /&gt;&lt;br /&gt;"This book should help you through the tough decisions you face as a newcomer to the field of professional software development. "&lt;i&gt; (preface xi)&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;The Clean Coder&lt;br /&gt;&lt;br /&gt;"This book is about software professionalism. It contains a lot of pragmatic advice" &lt;i&gt;(preface xxii)&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The Content&lt;/b&gt;&lt;br /&gt;Both books contain a lot of personal stories and anecdotes from the authors' careers, and begin with a short autobiography. Some of the advice is also similar. Both advise you to practice with "Kata" exercises, to read widely and to find suitable mentors. I think that's mostly where the similarities end though.&lt;br /&gt;&amp;nbsp; &lt;br /&gt;Dave and Ade don't say much about how to handle unreasonable managers imposing impossible deadlines. Bob Martin devotes a several chapters to this kind of issue, handling pressure, time management, estimation, making committments etc. &lt;br /&gt;&lt;br /&gt;Dave and Ade talk more about how to get yourself into situations optimized for learning and progress in your career. They advise you to "Be the worst", "Find mentors", seek "Kindred Spirits". In other words, join a team where you're the least skilled but you'll be taught, look for mentors in many places, and get involved in the community.&lt;br /&gt;&lt;br /&gt;Bob talks about a lot of specific practices and has detailed advice. He mentions "... pairing is the most efficient way to solve a problem" &lt;i&gt;(p164)&lt;/i&gt; Later in the chapter he suggests the optimal composition of job roles in a gelled team. &lt;i&gt;(p169)&lt;/i&gt; He also has some advice about how to successfully argue with your boss and go over their head when necessary &lt;i&gt;(p35)&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The Advice&lt;/b&gt;&lt;br /&gt;Those few example perhaps illustrate that these two books are miles apart when it comes to writing style, approach and world view. Dave&amp;amp;Ade have clearly spent a lot of time talking with other professionals about their material, acting on feedback and testing their ideas for validity in real situations. The book is highly collaborative and while full of advice, is not prescriptive.&lt;br /&gt;&lt;br /&gt;Bob Martin on the other hand loves to be specific, provocative and extreme in his advice. "QA should find nothing."(p114) "You should plan on working 60 hours per week." &lt;i&gt;(p16) &lt;/i&gt;"Avoid the Zone." &lt;i&gt;(p62)&lt;/i&gt; "The jury is in! ... TDD works" &lt;i&gt;(p79)&lt;/i&gt; These are some of his more suprising pieces of advice, which I think are actually fairly doubtful propositions when taken to extremes like this. Mixed in are more reasonable statements. "You do not have to attend every meeting to which you are invited" &lt;i&gt;(p123)&lt;/i&gt; "The professional developer is calm and decisive under pressure". &lt;i&gt;(p150)&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;The way everything is presented as black-and-white, do-or-do-not-there-is-no-try is actually pretty wearing after a while. He does it to try to make you think, as a rhetorical device, to promote healthy discussion. I think it all too easily leads the reader to throw the baby out with the bathwater. I can't accept one of his recommendations, so I throw them all out.&lt;br /&gt;&lt;br /&gt;Some of Dave&amp;amp;Ade's advice is actually just as hard to put into practice. Each of their patterns is followed by a call to action. Things like re-implementing a program you've written in an imperative language in a functional language &lt;i&gt;(p21)&lt;/i&gt;. Join or start a user group &lt;i&gt;(p65)&lt;/i&gt;. Solve the same coding exercise once a week for the next four weeks &lt;i&gt;(p79)&lt;/i&gt;. None of these things is particularly easy to do, but they seem to me to be interesting and useful challenges.&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Collaboration&lt;/b&gt;&lt;br /&gt;Bob has also clearly not collaborated very widely when preparing his material. One part that particularly sticks out for me is a footnote on page 75:&lt;br /&gt;&lt;br /&gt;"I had a wonderful conversation with @desi (Desi McAdam, founder of DevChix) about what motivates women programmers. I told her that when I got a program working, it was like slaying the great beast. She told me that for her and other women she had spoken to, the act of writing code was an act of nurturing creation." &lt;i&gt;(footnote, p75)&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Has he ever actually run his "programming is slaying a great beast" thing past any other male programmers? Let me qualify that - non-fantasy-role-playing male programmers? Thought not. This is in enormous contrast to Dave&amp;amp;Ade, whose book is full of stories from other people backing up their claims.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Stories&lt;/b&gt;&lt;br /&gt;Bob's book is full of stories from his own career, and he is very honest and open about his failures. This is a very brave thing to do, and I have a great deal of respect for him for doing so. It's also really interesting to hear about the history of what life was like when computers filled a room and people used punch cards to program them. Dave&amp;amp;Ades stories are less compelling and not always as well written.&lt;br /&gt;&amp;nbsp; &lt;br /&gt;Bob's book is not just about his professional life, he shares his likes and dislikes. He reccommends cycling or walking to recharge your energy, or "focus-manna" as he calls it, &lt;i&gt;(p127)&lt;/i&gt;. Reading science fiction as a cure for writer's block. &lt;i&gt;(p66)&lt;/i&gt; Listening to "The Wall" while coding could be bad for your design. &lt;i&gt;(p63)&lt;/i&gt; When describing "Master" programmers he likens them to &lt;i&gt;Scotty&lt;/i&gt; from Star Trek. &lt;i&gt;(p182)&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;All this is very cute and gives you a more rounded picture of what software professionalism is about. Maybe. Actually it really puts me off the idea. I know a lot of software developers like science fiction and fantasy role playing, but it really isn't mandatory. He usually says that you may have other preferences, and you don't have to do like he does, but I just don't think it helps all that much. The rest of the book is highly dogmatic about what you should and shouldn't do, and it kind of rubs off.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Conclusions&lt;/b&gt;&lt;br /&gt;The bottom line is, I wouldn't reccommend "The Clean Coder" to any young inexperienced software developer, particularly not if she were a woman. There is too much of it written from a foreign culture, in a demanding tone, propounding overly extreme behaviour. The interesting stories and good pieces of advice are drowned out.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;On the other hand, I would recommend "Apprenticeship Patterns". I think it is humbly written and anchored in real experience from a range of people. I agree with them when they say you need to read it twice to understand it. The first time to get an overview, the second time to understand how the patterns connect. It's not as easy to read as it might be. But still, I think the content is interesting, and it gives a good introduction to what being a professional software craftsman is about, and how to get there.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-6960256928582387078?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/6960256928582387078/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=6960256928582387078' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/6960256928582387078'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/6960256928582387078'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2011/10/clean-coder-apprenticeship-patterns.html' title='The Clean Coder &amp; Apprenticeship Patterns'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-3800796706180111618</id><published>2011-09-21T10:47:00.000+02:00</published><updated>2011-09-21T10:47:00.060+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='code retreat'/><category scheme='http://www.blogger.com/atom/ns#' term='clean code'/><category scheme='http://www.blogger.com/atom/ns#' term='Coding Dojo'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Code Retreat Stockholm</title><content type='html'>This weekend I was in Stockholm to facilitate a &lt;a href="http://coderetreat.com/"&gt;Code Retreat&lt;/a&gt;, organized by &lt;a href="http://twitter.com/#%21/peter_lind"&gt;Peter Lind&lt;/a&gt; and sponsored by &lt;a href="http://www.valtech.se/"&gt;Valtech&lt;/a&gt;. We were about 40 coders gathered in the warm autumn sunshine early on a Saturday morning at Valtech's offices. (Do take a look at &lt;a href="http://www.valtechlabs.se/code-retreat-pa-valtech"&gt;Peter's blog post&lt;/a&gt; about it, he has a photo too).&lt;br /&gt;&lt;br /&gt;It's actually the first time I've even attended a code retreat, let alone facilitated, but I think it went pretty well. Corey Haines has written extensively about what should happen, and &lt;a href="http://coderetreat.com/facilitation.html"&gt;what the facilitator should do&lt;/a&gt;. I think he's given a great gift to the community, not just by inventing the format, but also by documenting it thorougly.&amp;nbsp; I've previously led various coding dojos and "&lt;a href="http://bacheconsulting.com/clean-code-days"&gt;clean code day&lt;/a&gt;" events, but code retreat is somewhat different in format, if not in aim.&lt;br /&gt;&lt;br /&gt;The reason for going to a code retreat is to practice your coding  skills. By repeating the same exercise over and over, with different  pairing partners, you have a chance to work on your coding habits. Do  you pay attention to what your tests are telling you about your design?  Do you remember to refactor regularly? Can you take really small steps  when you need to?&lt;br /&gt;&lt;br /&gt;For the day in Stockholm, we followed the tried and tested formula for a code retreat that &lt;a href="http://coderetreat.com/"&gt;Corey has laid out&lt;/a&gt;. I spent about 20 minutes introducing the day, the aims and the coding problem (&lt;a href="http://en.wikipedia.org/wiki/Conway%27s_Game_of_Life"&gt;Conway's Game of Life&lt;/a&gt;). Then we did 6 coding sessions, each with a short retrospective, and a longer retrospective at the end of the day. Each session comprised 45 minutes coding in pairs, 10 minutes retrospective in groups of 6-8, and 5 minutes to swap partners. I also began each coding session by reminding everyone of what we were supposed to be practicing, and highlighted a different "challenge" to add some variety. The challenges were things like:&lt;br /&gt;&lt;br /&gt;- concentrate on writing really beautiful code so the language looks like it was made for the problem. *&lt;br /&gt;- partition code at different levels of abstraction. **&lt;br /&gt;- Think about &lt;a href="http://emilybache.blogspot.com/2011/05/tdd-in-terms-of-states-and-moves.html"&gt;TDD in terms of states and moves&lt;/a&gt;.&lt;br /&gt;- do &lt;a href="http://cumulative-hypotheses.org/2011/08/30/tdd-as-if-you-meant-it/"&gt;TDD as if you meant it&lt;/a&gt;&lt;br /&gt;- concentrate on refactoring in very small steps&lt;br /&gt;&lt;br /&gt;Each pairing session is just 45 minutes, and in that time you don't actually have time to really solve the whole kata, and that's actually quite difficult to cope with. Most coders are very motivated by writing code that does something useful, and like to show off their finished designs at the end. To try to prevent that, Corey emphasizes that you should keep in mind the end result isn't important, and be sure to delete the code at the end of the session. I found that even with that rule, there was quite a lot of discussion of how the designs ended up, and some people even saved their code.&lt;br /&gt;&lt;br /&gt;One of the things I encouraged people to try was working in an unfamiliar programming language, and although I specified "for 1 or 2 sessions", I was surprised to find how popular it was to do this. After the first session when most people used Java, C#, Ruby or Python, there were more and more people coding in Clojure, Javascript, Erlang and even Vim script. I think it got a bit out of hand actually. It's hard to practice your coding habits and TDD skills when you're struggling with the language syntax and how to get the tests to run. Next time I facilitate I'll try to be clearer about using a familiar environment for most of the sessions.&lt;br /&gt;&lt;br /&gt;One of the things I offered in the last session was using the &lt;a href="http://www.cyber-dojo.com/"&gt;cyberdojo&lt;/a&gt;, and three pairs agreed to try it. I had them working in Java and Ruby, switching pairs every 5 minutes, coding in a browser window. They complained about the browser experience compared with their IDEs, but they liked the feedback cyberdojo gives you. It shows how long you spend between running the tests, and whether the tests pass, fail or give a compiler error.&lt;br /&gt;&lt;br /&gt;I'm not sure if it was a good idea to bring in the cyberdojo at the code retreat. One of the main things we discussed in the retrospective for that session was the resistance they all felt to changing the first test that was written at one of the three pairing stations. This test was too big and focussed on a boring part of the problem. Yet each person who "inherited" the code tried their best to make it pass, no-one started over with a better test. It's that kind of collaboration problem that the cyberdojo is good at highlighting. It's not so much a tool for improving your coding skills as improving your collaboration skills. This is good, but not really the purpose of the code retreat.&lt;br /&gt;&lt;br /&gt;Thinking back over the day, I've also become a little uncertain about the "delete your code" rule. I understand why it's there, but it didn't seem to prevent people from trying to solve the whole problem in 45 minutes. By deleting the code, you also lose the opportunity to use analysis tools like those in the cyberdojo to give you some more feedback on how you're doing.&lt;br /&gt;&lt;br /&gt;Outside of this code retreat, I've been trying out the &lt;a href="http://content.codersdojo.org/codersdojo_client/"&gt;codersdojo client&lt;/a&gt; quite a bit recently, to see if it gives a useful analysis of a coding session. Unlike cyberdojo, it lets you use your normal coding tools/IDE. So far it's still in beta testing and seems too buggy for me to recommend, but if you're lucky enough to successfully upload your coding session, you do get quite a good visualization of some of your coding habits. It will clearly show if you spend a long time between test runs, or if you spend a lot of time with failing tests.&lt;br /&gt;&lt;br /&gt;So after my first code retreat, I'm feeling very encouraged that this is a good format for becoming a better coder, and I'd be happy to run one again. I'd like to try using coding visualization tools as part of the retrospective for each session. I'd also like to try setting the challenges before people have chosen a pairing partner, so they can find someone who also wants to work on my challenge rather than just try a new language. Or maybe I just need to emphasize more that trying a new language isn't the focus of the day.&lt;br /&gt;&lt;br /&gt;In any case, I hope this blog post shows that I learnt a lot from facilitating this code retreat, even if I didn't write a single line of code myself :-)&lt;br /&gt;&lt;br /&gt;* "You can call it beautiful code when the code also makes it look like the language was made for the problem" -- Ward Cunningham quoted in "Clean Code" by Bob Martin.&lt;br /&gt;** G6: Code at Wrong Level of Abstraction - advice from "Clean Code" by Bob Martin.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-3800796706180111618?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/3800796706180111618/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=3800796706180111618' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/3800796706180111618'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/3800796706180111618'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2011/09/code-retreat-stockholm.html' title='Code Retreat Stockholm'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-54536224162832737</id><published>2011-08-25T15:18:00.000+02:00</published><updated>2011-08-25T15:18:37.076+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='clean code'/><category scheme='http://www.blogger.com/atom/ns#' term='Code Kata'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Refactoring Kata fun</title><content type='html'>I've been working on a kata called "Tennis"*, which I find interesting, because it is quite quick to code, yet is a big enough problem to be worth doing. It's also possible to enumerate pretty much all the allowed scores, and get very comprehensive test coverage.&lt;br /&gt;&lt;br /&gt;What I've found is that when I'm using TDD to solve the Kata, I tend to only enumerate actually a very small number of the test cases. I generally end up with something like:&lt;br /&gt;&lt;br /&gt;Love-All&lt;br /&gt;Fifteen-All &lt;br /&gt;Fifteen-Love&lt;br /&gt;Thirty-Forty&lt;br /&gt;Deuce&lt;br /&gt;Advantage Player1&lt;br /&gt;Win for Player1 &lt;br /&gt;Advantage Player2&lt;br /&gt;&lt;br /&gt;I think that's enough to test drive a complete implementation, built up in stages. I thought it would be enough tests to also support refactoring the code, but I actually found it wasn't. After I'd finished my implementation and mercilessly refactored it for total readability, I went back and implemented exhaustive tests. To my horror I found three (of 33) that failed! I'd made a mistake in one of my refactorings, and none of my original tests found it. The bug only showed up with scores like Fifteen-Forty, Love-Thirty and Love-Forty, where my code instead reported a win for Player 2. (I leave it as an exercise for the reader to identify my logic error :-)&lt;br /&gt;&lt;br /&gt;So what's the point of TDD? Is it to help you make your design good, or to protect you from introducing bugs when refactoring? Of course it should help with both, but I think doing this practice exercise showed me (again!) that it really is worth being disciplined and careful about refactorings. I also think I need to develop a better sense for which refactorings might not be well covered by the tests I have, and when I should add more.&lt;br /&gt;&lt;br /&gt;This is something that my friend &lt;a href="http://www.dalkescientific.com/writings/diary/"&gt;Andrew Dalke&lt;/a&gt; brings up &lt;a href="http://www.dalkescientific.com/writings/diary/archive/2009/12/29/problems_with_tdd.html"&gt;when he criticises TDD&lt;/a&gt;. The red-green-refactor iterative, incremental rhythm can lull you into a false sense of security, and means you forget to stop and look at the big picture, and analyze if the tests you have are sufficient. You don't get reminded to add tests that should pass straight away, but might be needed if you refactor the code.&lt;br /&gt;&lt;br /&gt;So in any case, I figured I needed to practice my refactoring skills. I've created comprehensive tests and three different "defactored" solutions to this kata, in Java and Python. You can get the starting code &lt;a href="https://github.com/emilybache/Refactoring-Katas"&gt;here&lt;/a&gt;. You can use this to practice refactoring with a full safety net, or if you feeling brave, without. Try commenting out a good percentage of the tests, and do some major refactoring. When you bring all the tests back, will they still all pass?&lt;br /&gt;&lt;br /&gt;I'm planning to try this exercise with my local python user group, &lt;a href="http://meetup.com/GothPy"&gt;GothPy&lt;/a&gt;, in a few weeks time. I think it's going to be fun! &lt;br /&gt;&lt;br /&gt;* Tennis Kata: write a program that if you tell it how many points each player has won in a single game of tennis, it will tell you the score.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-54536224162832737?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/54536224162832737/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=54536224162832737' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/54536224162832737'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/54536224162832737'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2011/08/refactoring-kata-fun.html' title='Refactoring Kata fun'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-5819782726735257013</id><published>2011-08-09T11:00:00.001+02:00</published><updated>2011-08-09T20:16:56.821+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='teaching programming'/><category scheme='http://www.blogger.com/atom/ns#' term='feature tests'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Books on automated testing</title><content type='html'>As I mentioned in my &lt;a href="http://emilybache.blogspot.com/2011/06/teaching-diverse-bunch-of-testers.html"&gt;last post&lt;/a&gt; I've recently taught a course in automated testing to a bunch of students at KYH. Before the course I spent some time looking for good course books for them. I looked at a few options and eventually decided on "The art of Unit Testing with examples in .Net" by Roy Osherove, and "The RSpec Book" by Chelimsky et al.&lt;br /&gt;&lt;br /&gt;I chose the unit testing book because Roy does a good job of describing the basics of test driven development, including simple mocks and stubs. The book is very practical and is full of insight from experience and code examples.&lt;br /&gt;&lt;br /&gt;I also looked at "Pragmatic Unit Testing in C# with NUnit" by Andrew  Hunt and David Thomas. I'm a big fan of their book "The Pragmatic  Programmer", so I had high hopes for this one. Unfortunately I was  rather disappointed with it. It talks about what good unit tests should look like,  but not much about how you use Test Driven Development to  create them.&lt;br /&gt;&lt;br /&gt;I chose the RSpec Book because it has quite a bit of material about Cucumber and how it fits in to a Behaviour Driven Development process. I think the published literature on automated testing focuses too much on unit level tools, and there is not enough written about feature level tests and how to use them as part of the whole agile process.&lt;br /&gt;&lt;br /&gt;I also looked at "Bridging the Communication Gap" by Gojko Adzic, which I think is an excellent introduction to how to use feature level tests as part of the agile process, but it is largely tool agnostic. There is a short chapter introducing some tools, including JBehave, a forerunner to Cucumber, Selenium and TextTest too. It's a little out of date now though, and for this course I wanted something with more detail.&lt;br /&gt;&lt;br /&gt;I hope these short book reviews are useful.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-5819782726735257013?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/5819782726735257013/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=5819782726735257013' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/5819782726735257013'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/5819782726735257013'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2011/08/books-on-automated-testing.html' title='Books on automated testing'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-7973766288705020936</id><published>2011-06-22T20:42:00.001+02:00</published><updated>2011-06-22T20:43:35.080+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='teaching programming'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Teaching a diverse bunch of Testers</title><content type='html'>I've just spent 3 weeks teaching a class of 11 students about automated testing, as part of a one year course in software testing. The course is organized by the local "Kvalificerade Yrkes Högskolan", &lt;a href="http://www.kyh.se/"&gt;KYH&lt;/a&gt;. (loosely translated: Skilled Trade University). The students come from all kinds of job backgrounds, from sitting in a supermarket checkout to driving trams to gardening, and most of them had never written a computer program before the course started.&lt;br /&gt;&lt;br /&gt;The KYH tries to design their courses so that students will be competent enough to get a job by the end of them, so they work closely with local employers to set the curriculum and find teachers for the courses.&lt;br /&gt;&lt;br /&gt;I was pleased to be asked to do this teaching job, since automated testing is one of my main areas of expertise, but at the same time I was quite daunted by the prospect. I've never taught non-programmers before, and I've certainly never had to set an exam or hand out grades. Before I agreed to do it, I spent some time talking to a friend of mine who has previously taught a different KYH course, and his story actually wasn't all that encouraging. It's hard work preparing the teaching materials, and some of the students will find it very difficult and need a lot of help and coaching. I decided it could be worth doing, anyway. I had some teaching materials prepared already, and I wanted the chance to invent more, try out some new ideas, and broaden my horizons.&lt;br /&gt;&lt;br /&gt;Now that I've done the course I can attest that it really is hard work preparing lessons and exercises, and some of the students do need a lot of help. It is very rewarding though when they start to understand. I got a real kick out of going round the classroom seeing them all starting to write tests with &lt;a href="http://seleniumhq.org/"&gt;Selenium&lt;/a&gt; and &lt;a href="http://cukes.info/"&gt;Cucumber&lt;/a&gt;, and answering their questions about Ruby and Page Objects and how to name tests and what to assert, and where to put the code and which parts to write tests for...&lt;br /&gt;&lt;br /&gt;I think by teaching this course I've learnt a lot myself about things like how to communicate ideas, give feedback and encouragement, and to set boundaries and manage expectations. I found marking their work much more interesting than I expected, too. What kinds of mistakes do inexperienced programmers make when doing TDD? Do they find it easier to write good tests with Selenium or Cucumber? Is there any correlation between testing skill and programming skill? (short answers - they don't refactor enough, Cucumber is &lt;i&gt;way&lt;/i&gt; easier, and no, the correlation seems pretty weak)&lt;br /&gt;&lt;br /&gt;So do I recommend getting involved? Absolutely! I think the IT industry in general needs more people in it from diverse backgrounds, and this is the kind of course that brings them in. If my experience is anything to go by, you'll work hard but you'll learn a lot from the students too. Networking with the other employers in the course Industry Reference Group is useful, and if I was looking to hire a junior tester I'd now know exactly who to ask first. Actually, who knows, in a few years some of my students might even be in a position to give &lt;i&gt;me&lt;/i&gt; a job.&lt;br /&gt;&lt;br /&gt;Don't just complain that it's hard to hire qualified people and/or people from diverse backgrounds. Get down to your local KYH equivalent and help them set up a course! I think that being a good software developer or tester is not restricted to only those with a degree in Computer Science. A course at a trade school where local employers get involved is good value for everyone.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-7973766288705020936?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/7973766288705020936/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=7973766288705020936' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/7973766288705020936'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/7973766288705020936'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2011/06/teaching-diverse-bunch-of-testers.html' title='Teaching a diverse bunch of Testers'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-7377553649725430864</id><published>2011-06-21T12:03:00.001+02:00</published><updated>2011-06-21T12:04:28.888+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>Nordic Ruby and Diversity</title><content type='html'>This is the second time I've attended &lt;a href="http://nordicruby.org/"&gt;Nordic Ruby&lt;/a&gt;, you can read about what I thought last year&lt;a href="http://emilybache.blogspot.com/2010/05/programmer-conferences-are-like-games.html"&gt; here&lt;/a&gt;. This year I enjoyed the conference more, for several reasons. There were some small changes in the way it was organized, (on a Friday and Saturday instead of taking up a whole weekend), a better choice of speakers and topics, (less technical, more inspirational), and I knew more of the people there.&lt;br /&gt;&lt;br /&gt;One of the themes of the conference was diversity, which I was very, very happy to see. There was an inspiring talk by &lt;a href="http://blogs.thewehners.net/josh"&gt;Joshua Wehner&lt;/a&gt; about this topic, taking up some depressing statistics about the IT industry in general and open source software in particular. What struck me most was that he said the statistics for women involvement are improving in many formerly male-dominated disciplines, like maths, physics and law, but in computing, the situation was actually better 20 years ago than it is now. The curves are pointing the wrong way in our industry.&lt;br /&gt;&lt;br /&gt;Having said that, there were slightly more women at the conference this year than last, I think I counted 4 of 150, compared with 2 of 90 last year. There were also far fewer references to science fiction movies from the speakers this year ;-)&lt;br /&gt;&lt;br /&gt;Joshua did take up several things that we could do practically to reduce bias and positively encourage diversity. He's written about some of them in &lt;a href="http://blogs.thewehners.net/josh/posts/425--and-the-wisdom-to-know-the-difference"&gt;this blog post&lt;/a&gt;. Another one he mentioned that I liked was the "no asshole rule". If people engage in arrogant one-upmanship, talk down to others, and emphasize their superior programming abilities, they should be regarded as not just annoying, but actually incompetent. Developing software is a multi-faceted skill, and it takes a lot more than just writing good code to be a good software developer.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://twitter.com/#%21/objo"&gt;Joe O'Brien&lt;/a&gt; continued the diversity theme in his talk "Taking back education" by basically arguing that having a degree in computer science correlates very badly with being a good software developer, and that we should be finding ways to bring people into our industry who have non-traditional backgrounds. He advocated companies to start apprenticeship programmes, while conceding that this model of education doesn't scale very well. He talked about getting a group of companies together to set up a "code school". He said "forget universities when it comes to education [of software developers]. We're better at it"&lt;br /&gt;&lt;br /&gt;I applaud his efforts to bring a more diverse range of people into the industry, and I think my recent experiences teaching a group like this are relevant. I think I'll write a separate blog post about that experience, but basically I think the idea of a "code school" is a good one, and similar institutions probably already exist, and could add a course in software development to their programme of courses in practical skills. For this to happen it's up to companies to put in time and energy setting them up, rather than just complaining that when they put out a job advert, all they get are white male applicants between the ages of 25-35, so it's not their fault.&lt;br /&gt;&lt;br /&gt;Another talk that deserves a mention is the one by &lt;a href="http://www.josephwilk.net/"&gt;Joseph Wilk&lt;/a&gt;. He spoke about "The Limited Red Society" which is an idea that &lt;a href="http://twitter.com/#%21/JoshuaKerievsky"&gt;Joshua Kerievsky&lt;/a&gt; came up with. I heard Joshua speak about it at XP2009, and I thought Joseph did a very good job of explaining what it is, and why it's important.&lt;br /&gt;&lt;br /&gt;Basically the idea is that although you need your tests to go red during TDD, if they stay red for any length of time, it can get you into trouble. While they are red, you can't check in, ship your code, or change to working on a different task. This is one motivation for trying to measure, and limit, how much of the time your tests are red. It's also about more generally improving the feedback we get for ourselves while we work. Professional sports stars spend time analysing and visualizing their performances (where balls land on a tennis court, footballers rates of passing etc). We programmers could benefit from that kind of thing too.&lt;br /&gt;&lt;br /&gt;Joseph has invented a tool that helps him to track his state when doing TDD. It's a simple monitoring program that makes a note every time he runs his tests. It's not as elaborate as the &lt;a href="https://elearning.industriallogic.com/gh/submit?Action=PageAction&amp;amp;album=blog2009&amp;amp;path=blog2009/2010/sessions&amp;amp;devLanguage=Java"&gt;commercial tool&lt;/a&gt; offered by Joshua Kerievsky's company, but it does work with Ruby and Cucumber. Joseph also has his tool connected to his CI server so that it runs tests that have failed recently in his and others' checkouts first in the CI test run. He also gathers statistics about individual tests, how often they fail, and whether they are fixed without the production code needing to be changed - a way of spotting fragile tests.&lt;br /&gt;&lt;br /&gt;I think this kind of statistics gathering is really interesting and I think Joseph will just have more insights to share as he gathers more data and does more analysis. I've been experimenting with the tool provided by &lt;a href="http://codersdojo.org/"&gt;codersdojo.org&lt;/a&gt; for measuring my performance at code katas, but Joseph seems to be taking this all to the next level.&lt;br /&gt;&lt;br /&gt;Overall I thoroughly enjoyed Nordic Ruby. (I still think it would be improved by some actual open space sessions though). I talked to loads of really interesting people, enjoyed good food and drink in comfortable surroundings, and listened to some people give excellent talks. Thanks for organizing a great conference, &lt;a href="http://elabs.se/"&gt;Elabs&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-7377553649725430864?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/7377553649725430864/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=7377553649725430864' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/7377553649725430864'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/7377553649725430864'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2011/06/diversity-and-ruby-community.html' title='Nordic Ruby and Diversity'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-3249462692435575919</id><published>2011-05-10T16:25:00.000+02:00</published><updated>2011-05-10T16:25:51.410+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Coding Dojo'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>TDD in terms of states and moves</title><content type='html'>The classic description of TDD that most people know is the &lt;a href="http://butunclebob.com/ArticleS.UncleBob.TheThreeRulesOfTdd"&gt;3 rules by Bob Martin&lt;/a&gt;. I think his rules are a very succinct description, and for a long time I've just relied on them, together with a picture of "red-green-refactor" to describe TDD to newcomers. More recently I've found value in expanding this description in terms of states and moves.&lt;br /&gt;&lt;br /&gt;When I'm doing TDD in a coding dojo using the Randori form, I get  people stepping up to take the keyboard who've never done it before, and  I find it helps them to understand what's going on if I explain which  state we're in and what the legal moves are for that state. The picture I've used is like this:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-o4EntaV8oSg/Tck-yrMEdrI/AAAAAAAAAF0/RM186m7uFZQ/s1600/intro+coding+dojo+xp2011.015.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://1.bp.blogspot.com/-o4EntaV8oSg/Tck-yrMEdrI/AAAAAAAAAF0/RM186m7uFZQ/s320/intro+coding+dojo+xp2011.015.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;I'd like to go through each state and some of the moves you can make in each.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-wQuGc4DW9pY/Tck-2BPlt6I/AAAAAAAAAF4/HO5ppYCXwr4/s1600/intro+coding+dojo+xp2011.016.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://1.bp.blogspot.com/-wQuGc4DW9pY/Tck-2BPlt6I/AAAAAAAAAF4/HO5ppYCXwr4/s320/intro+coding+dojo+xp2011.016.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;I think before we start on a TDD coding session there is value in  doing a small amount of analysis and planning. In the dojo, I'll spend around 15 minutes in this starting state before we start coding. We'll talk about the chosen kata so everyone hopefully understands the problem we're going to solve. We'll write a list of potential test cases on a whiteboard, and identify some kind of "guiding test". This is an overarching test that will probably take us a couple of hours to get to pass. It helps us to define the API we want to write, and the goal for our session. We may also talk a little about how we'll implement the solution, perhaps discuss a possible data structure or algorithm. &lt;br /&gt;&lt;br /&gt;I know the group is ready to move on when we have sketched a guiding test or goal for the session, and have chosen the first test we'll try to make pass.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-XetlTcLaQXo/Tck-5vN5yTI/AAAAAAAAAF8/tggFAA39uSU/s1600/intro+coding+dojo+xp2011.017.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://2.bp.blogspot.com/-XetlTcLaQXo/Tck-5vN5yTI/AAAAAAAAAF8/tggFAA39uSU/s320/intro+coding+dojo+xp2011.017.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;When we're getting to red, we're trying to set up a small achievable goal. We'll choose a simple test from our list, one that will help us towards our session goal (guiding test). This test should force us to address a weakness in our production code.&lt;br /&gt;&lt;br /&gt;Starting with naming the test then writing the assert statement helps us to focus on what the missing functionality is. Then we can fill in the "act" and "arrange" parts of the test. I'm not sure who invented the "Arrange, Act, Assert" moniker for structuring tests, but the idea is that a test has three parts. In the "Arrange" part you set up the objects the system under test will interact with, in the "Act" part, you call the production code to do whatever it is, and in the "Assert" step, you check it did what you expected.&lt;br /&gt;&lt;br /&gt;In a compiled language it helps to fill in a bit of production code while we're writing the test, but only just enough to keep the compiler quiet. Once the test executes, and is red, you can move on. &lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-sHAiB1_djOE/Tck-86AvMsI/AAAAAAAAAGA/pydv_AvYPqw/s1600/intro+coding+dojo+xp2011.018.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://1.bp.blogspot.com/-sHAiB1_djOE/Tck-86AvMsI/AAAAAAAAAGA/pydv_AvYPqw/s320/intro+coding+dojo+xp2011.018.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&amp;nbsp;This is where we flip over to the production code (I've seen newbies presented with a failing test trying to edit the test to make it green!).&lt;br /&gt;&lt;br /&gt;If we can easily see what the implementation should be, we might just write it, but often it helps to return some kind of fake value, until we work out what the code should be. Sometimes in this state we find the test we wrote is too hard, and we need to get back to green by removing or commenting out the failing test. This is a sign we understand the problem better than we did before, which is a good thing. In that case, we'll go back to "Getting to red" and write a better test. Otherwise, we get to green by making the new test pass.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-67bpR_GVCHg/Tck_AeQzUQI/AAAAAAAAAGE/UiMxBAjfeps/s1600/intro+coding+dojo+xp2011.019.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://2.bp.blogspot.com/-67bpR_GVCHg/Tck_AeQzUQI/AAAAAAAAAGE/UiMxBAjfeps/s320/intro+coding+dojo+xp2011.019.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;The refactoring move is where we want to remove fake implementations, refactor away code smells and improve code readability generally. Don't forget there may also be duplication and readability problems in the tests as well as the production code. The trick is to do a series of small refactorings that taken together lead to a better design. Try to stay only a few keystrokes away from a running system (green tests).&lt;br /&gt;&lt;br /&gt;While we're looking for refactorings, we'll probably spot weaknesses in the production code implementation - functionality that is missing or cases that are not handled. This is a cue to note new test cases, not to fix the code. If we find a hard coded return value, say, we should be able to think of a new test case that will force us to write a better implementation.&lt;br /&gt;&lt;br /&gt;We can move on when we're happy the design of the code is good (for the test cases so far).&lt;br /&gt;&lt;br /&gt;At some point hopefully we'll find we can get our guiding test to pass, and/or that we're out of time and the coding session is over. We'll look through the code a final time, (as we check it in, maybe), then take a few minutes to reflect on what we learnt during this coding session. In the coding dojo, we'll spend some time discussing what was good and bad about this dojo session, and what we might do differently next time based on what we've learnt.&lt;br /&gt;&lt;br /&gt;The cycle begins again with the next coding task or the next dojo session.&amp;nbsp;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-3249462692435575919?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/3249462692435575919/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=3249462692435575919' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/3249462692435575919'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/3249462692435575919'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2011/05/tdd-in-terms-of-states-and-moves.html' title='TDD in terms of states and moves'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-o4EntaV8oSg/Tck-yrMEdrI/AAAAAAAAAF0/RM186m7uFZQ/s72-c/intro+coding+dojo+xp2011.015.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-7230166151090097692</id><published>2011-02-28T21:53:00.000+01:00</published><updated>2011-02-28T21:53:34.799+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>DynCon, Scandinavian Developer Conference and XP2011</title><content type='html'>The &lt;a href="http://swdc-central.com/dyncon2011/schedule.html"&gt;programme for DynCon&lt;/a&gt;  has just been published, and the whole conference is about dynamically  typed languages. There are talks about all sorts of languages, old and  new, and I think it's going to be really interesting to get people  together from all these different communities. I'm giving a talk with title "A Test-Driven Introduction to Python" where I'm hoping to show off some of the best features of Python. I'll also be demoing a new testing tool called "CaptureMock" which my husband Geoff has invented. I'll be interested to hear what all the afficionadoes of other languages think of both it and python.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://www.scandevconf.se/2011/conference/detailed-program/"&gt;programme for Scandinavian Developer Conference&lt;/a&gt; has been up for a while now, and I'm very pleased with the way its looking. The conference will be held in Göteborg in April, and I'm responsible for a whole track called "Conversation Corner". I'm delighted so many people have agreed to take part, and I think we'll be discussing some really interesting topics. I'm hoping it will be a really interactive part of the conference, as a complement to the other 10 tracks which mostly comprise presentations.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://xp2011.org/program/"&gt;programme for XP2011&lt;/a&gt; also came out last week, although it is not yet complete. I'm Industry Chair for this conference, which will be held in Madrid in May, and I &lt;a href="http://emilybache.blogspot.com/2010/12/xp2011.html"&gt;blogged before&lt;/a&gt; about my long association with this series of conferences. For this year, I'm still talking to people about putting together panel debates and discussions, and we also have space for more demos and lightning talks. The programme of tutorials and workshops is pretty much complete though, and I think we've got a great lineup of people leading them.&lt;br /&gt;&lt;br /&gt;So I've got a very busy spring ahead of me with all these fantastic conferences coming up, and I'm thoroughly looking forward to all of them :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-7230166151090097692?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/7230166151090097692/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=7230166151090097692' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/7230166151090097692'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/7230166151090097692'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2011/02/dyncon-scandinavian-developer.html' title='DynCon, Scandinavian Developer Conference and XP2011'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-421889136669114240</id><published>2011-01-30T22:28:00.001+01:00</published><updated>2011-01-30T22:31:14.086+01:00</updated><title type='text'>Online resources for Coding Dojos</title><content type='html'>If you're running a coding dojo, or if you're an individual who likes to practice code kata, there are a number of websites which aim to help. In this post I want to review some of what's out there.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://codekata.pragprog.com/"&gt;http://codekata.pragprog.com/&lt;/a&gt;&lt;br /&gt;The idea of the code kata was originally presented by Dave Thomas in his blog. This is the list of Kata exercises he originally suggested. The dates on the site say 2007 but it must have been at least a couple of years before that*. Some of these katas don't actually involve writing any code, such as &lt;a href="http://codekata.pragprog.com/2007/01/kata_three_how_.html"&gt;kata three&lt;/a&gt;. The focus is on general programming skills rather than TDD in particular.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://codingdojo.org/"&gt;http://codingdojo.org&lt;/a&gt;&lt;br /&gt;The idea of practicing code kata in a group and calling it a Coder's Dojo was presented by Laurent Bossavit and Emmanual Gaillot at &lt;a href="http://www.springerlink.com/content/jeufb0lybyptdx9d/"&gt;XP2005&lt;/a&gt;. Codingdojo.org is their site for the community, and has some helpful information if you're looking to join or set up a dojo. There is also a catalogue of Kata descriptions. In the past I've personally contributed quite a bit of material to this site, but I've recently become frustrated with the amount of spam on it.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://web.cs.wpi.edu/%7Egpollice/Dojo.html"&gt;http://web.cs.wpi.edu/~gpollice/Dojo.html&lt;/a&gt;&lt;br /&gt;This is an article rather than a whole site, but it gives one of the best summaries of a coding dojo that I've seen on the web.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://katacasts.com/"&gt;http://katacasts.com&lt;/a&gt;&lt;br /&gt;Corey Haines set up this site in 2009 and his original intention seemed to be to publish a screencast of a kata performance each week. Unfortunately the most recent screencast on the site is from July 2010. There is a lot of good stuff on there to watch, though - notably versions of the StringCalculator kata in almost any programming language you can think of. I really like the idea of screencasts of katas, since for me katas are all about practicing the moves of TDD and becoming expert with your language and editor/IDE. I'm not half as interested in the code you end up with than the route you took to get there. I like that Corey and others comment on the various performances and people learn from watching each other. &lt;br /&gt;&lt;br /&gt;&lt;a href="http://cyber-dojo.com/"&gt;http://cyber-dojo.com&lt;/a&gt;&lt;br /&gt;As I understand it, Jon Jagger created this tool to help development teams improve their collaboration skills. He's been round several conferences using it as a kind of game for learning about practices such as pair programming, clean code, TDD, and all the people issues related to working in a team. It's a fun activity for a group of programmers to do together, but to get the most out of it I think you need a facilitator who will help you understand what was happening and what there is to learn from it.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://codingkata.org/"&gt;http://codingkata.org&lt;/a&gt;&lt;br /&gt;This site still claims to be in beta, but there is quite a bit of material already. The philosophy seems to be to try to get people to have fun by playing with code, and also to learn new languages. There's no particular emphasis on TDD. There is a catalogue of katas, and for each one it provides starter projects you can download into your IDE. When you think you're done, it will check your solution for correctness and let you upload the code for public viewing. There doesn't currently seem to be any support for uploading screencasts, or giving people comments and feedback on their solutions.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://codersdojo.org/"&gt;http://codersdojo.org/&lt;/a&gt;&lt;br /&gt;This site is also quite new, but seems very promising. The aim seems very much to encourage collaboration, feedback, and becoming better at TDD - key elements of a face-to-face coding dojo. It provides tools that analyse your performance of a kata, not at the level of 'does the code work by the end' but at the level of 'what were the moves you made to get there'. Each time you run the tests it records the code before and after, and whether the tests passed or failed. There are tools to let you go through a kata performance, look at the moves made and suggest improvements to the performer.&lt;br /&gt;&lt;br /&gt;At present the only language supported is Ruby, but that is a great language for practicing TDD in :-) There is also no catalogue of katas to try - it just points to codingdojo.org.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;What sites have I missed?&lt;/b&gt;&lt;br /&gt;There are a number groups holding regular coding dojos in various parts of the world, and many have their own websites. Several of these are also full of helpful information, but they're not quite what I'm after. I'm looking for sites that are addressed to the whole online community. Please write me a comment and point out sites I should know about!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;* Laurent and Emmanuel credited Dave Thomas with the idea in 2005 when they presented the coder's dojo, &lt;a href="http://www.codinghorror.com/blog/2008/06/the-ultimate-code-kata.html"&gt;Jeff Attwood&lt;/a&gt; credits him in and article dated 2008, and &lt;a href="http://en.wikipedia.org/wiki/Kata_%28programming%29"&gt;wikipedia&lt;/a&gt; says he published code katas before Jan 2006.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-421889136669114240?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/421889136669114240/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=421889136669114240' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/421889136669114240'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/421889136669114240'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2011/01/online-resources-for-coding-dojos.html' title='Online resources for Coding Dojos'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-764326854820331323</id><published>2011-01-19T13:23:00.000+01:00</published><updated>2011-01-19T13:23:21.048+01:00</updated><title type='text'>Launch of my company website</title><content type='html'>&lt;span style="font-family: inherit;"&gt;I’m very excited to announce the launch of my company website, at &lt;/span&gt;&lt;a href="http://bacheconsulting.com/" style="font-family: inherit;"&gt;http://bacheconsulting.com&lt;/a&gt;&lt;span style="font-family: inherit;"&gt;. The site has information about the coaching and training I offer, links to this blog, my videos on YouTube, and my twitter feed. My hope is that it gives an indication of my areas of expertise, and what you can expect if I come to work with your development team.&lt;/span&gt;&lt;br style="font-family: inherit;" /&gt;&lt;br style="font-family: inherit;" /&gt;&lt;span style="font-family: inherit;"&gt;The site was built for me by my friend &lt;/span&gt;&lt;a href="http://www.netnebulis.com/" style="font-family: inherit;"&gt;James Pink&lt;/a&gt;&lt;span style="font-family: inherit;"&gt;, who was very helpful with ideas for site layout and content. He also created my company logo from some sketches I did, and a rather dodgy photo of me hanging my head upside down with one ringlet of hair sticking out. Quite a tricky shot to take by yourself, even if your phone does have two cameras!&lt;/span&gt;&lt;br style="font-family: inherit;" /&gt;&lt;br style="font-family: inherit;" /&gt;&lt;span style="font-family: inherit;"&gt;The pictures on the site are mostly from conferences - happy memories of good sessions at Agile 2008, XP2009 and XP2010. I’m very grateful to all the photographers for giving me permission to use them. I enjoyed searching through all the conference pictures, these guys really know what they're doing with a camera, and seem to catch just the best moments. The profile shot I’ve been using for a couple of years now was taken by my friend Margaretha Schölin, when we were in China on a business trip together. More happy memories, thanks Maggan :-)&lt;/span&gt;&lt;br style="font-family: inherit;" /&gt;&lt;br style="font-family: inherit;" /&gt;&lt;span style="font-family: inherit;"&gt;I’d also like to thank the people who agreed to be quoted saying nice things about the work I’ve previously done with them. I’ll return the favour sometime soon, I’m sure.&lt;/span&gt;&lt;br style="font-family: inherit;" /&gt;&lt;br style="font-family: inherit;" /&gt;&lt;span style="font-family: inherit;"&gt;So now all that remains is to hope that some more companies (preferably those in or near to Göteborg) will notice my site and want to hire me to help them learn agile engineering practices!&lt;/span&gt;&lt;br style="font-family: inherit;" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-764326854820331323?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/764326854820331323/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=764326854820331323' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/764326854820331323'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/764326854820331323'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2011/01/launch-of-my-company-website.html' title='Launch of my company website'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-2092397727132518516</id><published>2011-01-17T15:18:00.006+01:00</published><updated>2011-01-17T15:33:57.070+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='teaching programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Coding Dojo'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>Agile Coach Camp Norway</title><content type='html'>I travelled to Oslo last weekend, to take part in &lt;a href="http://www.agilecoachcamp.no/"&gt;Agile Coach Camp Norway&lt;/a&gt;. This was an open space conference organized by some enthusiasts, not for profit. I became interested in going to the conference when I heard some other agile coaches tweeting about it. I’ve just started my career as a kind of agile coach, and I’ve always enjoyed the open space parts of other conferences I’ve attended. I hesitated though, since I have quite a technical focus. What clinched it was when &lt;a href="http://twitter.com/#%21/jhannes"&gt;Johannes Brodwall&lt;/a&gt; signed up - an excellent programmer who shares my interest in using Code Kata for teaching and learning Test Driven Development.&lt;br /&gt;&lt;br /&gt;I was surprised to see Bob Martin in the hotel reception when I arrived - he had come on a whim since he was in Oslo that day. He spent some time on the first evening telling the story of how the agile manifesto came about, and his involvement. He’s an impressive speaker, even when improvising. Bob didn’t stick around for the rest of the conference, and he missed out on some really good discussions.&lt;br /&gt;&lt;br /&gt;We began the main part of the conference with a “coaching dojo”, which &lt;a href="http://twitter.com/#%21/rachelcdavies"&gt;Rachel Davies&lt;/a&gt; invented by analogy with a coding dojo. It was fun practicing coaching one another, and getting feedback from people who are used to giving good feedback. It really set the tone for the whole weekend.&lt;br /&gt;&lt;br /&gt;After lunch, we had the open space opening session, and loads of sessions were proposed. I suggested 4, and ended up being very pleased I'd done them. I got some great feedback about a short coding dojo I ran - being coached in my facilitation skills was very valuable for me, and the participants seemed to appreciate learning more about the coding dojo format I use.&lt;br /&gt;&lt;br /&gt;It turned out that Johannes and I weren't the only technically-focused people there, and we shared lots of ideas about code katas and teaching TDD. Everyone agreed that success with agile needs developers to change the way they work, and most struggle with TDD. "Parachuting" a trainer in for a couple of days might help developers understand they could work differently, but getting them to actually make changes is much harder. I'm hoping for some success with repeated regular coding dojo sessions with a team. I'll have to report back when I have more experience of actually doing this.&lt;br /&gt;&lt;br /&gt;Another highlight was discussing using games for teaching agile, and in  particular teaching agile engineering practices. Jon Jagger has his  “&lt;a href="http://cyber-dojo.com/"&gt;cyber-dojo&lt;/a&gt;” collaborative programming game that he has released open  source, and a “&lt;a href="http://jonjagger.blogspot.com/2010/12/kanban-1s-game.html"&gt;Kanban 1’s game&lt;/a&gt;” which he uses for teaching teams about  limiting work in progress, and keeping work items small. We talked about  the fact that many games are released under the creative commons  attribution license, and coaches share them with each other. The games  in themselves may take time and effort to create, but Jon and many of  the other coaches there felt they don’t lose by sharing them, quite the  opposite. They get feedback from others and help to improve the games. I  wondered if they were worried about losing business to cheaper rivals  who just took their materials, but people seemed confident that the  skill of the facilitator is so crucial in the success of a game in  achieving learning goals for the participants, that they would not lose  out.&lt;br /&gt;&lt;br /&gt;It was an intense weekend, with a couple of lovely walks in the snow, and good food together with interesting company. I learnt a lot about coaching and made new friends. I’ll be looking out for similar conferences in future :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-2092397727132518516?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/2092397727132518516/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=2092397727132518516' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/2092397727132518516'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/2092397727132518516'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2011/01/agile-coach-camp-norway.html' title='Agile Coach Camp Norway'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-6048920669124467202</id><published>2010-12-16T12:57:00.008+01:00</published><updated>2010-12-20T15:53:15.840+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='teaching programming'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>Teaching programming</title><content type='html'>The world need more and better programmers. Jason Gorman recently wrote &lt;a href="http://parlezuml.com/blog/?postid=977"&gt;this post&lt;/a&gt; encouraging people to start offering software apprenticeships, as an alternative to computer science degrees.&lt;br /&gt;&lt;br /&gt;He writes:&lt;br /&gt;&lt;br /&gt;"our computing education in [the UK] is preparing students for a  career in a version of computing most of us don't recognise. Students  devote the majority of their time learning theory and skills that they  almost certainly won't be applying when they get their first proper job.  Computing schools are hopelessly out of touch with the reality of  computing in the real world. While employers clamour for TDD or  refactoring skills, academics turn their noses up at them and focus on  things like formal specification and executable UML and compiler design,  along with outdated and thoroughly discredited "software engineering"  processes." -- Jason Gorman&lt;br /&gt;&lt;br /&gt;Jason ends his post with a call to arms - if you're a good software developer, get yourself an apprentice, and start training them. It's the same message I heard from Dave Hoover when he visited Göteborg recently. I think he also sees a multi-year apprenticeship as a better alternative for training programmers than a computer science degree.&lt;br /&gt;&lt;br /&gt;I also recently came across  &lt;a href="http://ubiquity.acm.org/article.cfm?id=1865908"&gt;this article,&lt;/a&gt; written by a computer science teacher in the US, with the following paragraph:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;"I no longer teach programming by  teaching the features of the language  and asking the students for  original compositions in the language.  Instead I give them programs  that work and ask them to change their  behavior. I give them programs  that do not work and ask them to repair  them. I give them programs and  ask them to decompose them. I give them  executables and ask them for  source, un-commented source and ask for the  comments, description, or  specification. I let them learn the language  the same way that they  learned their first language. All tools, tactics  and strategies are  legitimate. "&lt;/span&gt; -- &lt;b&gt;William Hugh Murray&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;So clearly some academics are teaching in creative ways. Rather than abandoning computer science degrees, might it not be better to improve their content?&lt;br /&gt;&lt;br /&gt;One of the things about the XP conference is that it brings together industry and academics, and lets them hear from one another. How to teach programming is a very important topic that is often discussed there. XP2005 for example was held at Sheffield university, where I remember chatting to one of the professors, and being impressed by the way they used eXtreme Programming as part of their undergraduate course.&lt;br /&gt;&lt;br /&gt;Another thing that happened at XP2005 was the first coding dojo I attended, and I believe the first one ever held outside of France. It was presented by Laurent Bossavit and Emmanuel Gaillot, founders of the Paris dojo. I was excited to discover a context in which I could improve my practical programming skills, in regular short bursts, alongside a continuing paid job.&lt;br /&gt;&lt;br /&gt;So one of the things I do in my new life as an agile testing consultant is to use the coding dojo format to teach people how to program better. We'll do code kata exercises and practice Test Driven Development, Refactoring, and discuss what Clean Code looks like. So far the reaction from professionals I've done this with has been very positive. Lots of people who have been coding for years appreciate the chance to learn new practical skills.&lt;br /&gt;&lt;br /&gt;I'm also getting involved in more formal education, this spring I'm teaching a three week course in automated testing, as part of a "Kvalificerad Yyrkesutbildning" in software testing. This is a one year full time course for students wanting to learn a practical skill, as an alternative to going to university and studying a more academic subject. In Sweden you can get a student loan while you're studying this course, and part of the time is spent working in a company gaining on-the-job experience.&lt;br /&gt;&lt;br /&gt;I'm starting to plan how I'm going to teach TDD, BDD, and how to use tools like Selenium, Fitnesse, TextTest and Cucumber. I think it's going to be very hands on and practical, but also go into the general principles behind tool choice and writing maintainable automated tests. I'm helping to write a formal syllabus and exam, with criteria for grades awarded.&lt;br /&gt;&lt;br /&gt;I guess what I'm trying to say is that I don't like this strand of thought in the Software Craftsmanship movement that wants to abandon formal education. There are lots of ways to train software developers, and apprenticeship isn't without its problems.&lt;br /&gt;&lt;br /&gt;I think this is just the sort of thing we'll be discussing at XP2011, where there will be a host of academics and experts from industry. &lt;a href="http://xp2011.org/node/6"&gt;Won't you join us&lt;/a&gt;?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-6048920669124467202?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/6048920669124467202/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=6048920669124467202' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/6048920669124467202'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/6048920669124467202'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2010/12/teaching-programming.html' title='Teaching programming'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-7393324487254115368</id><published>2010-12-09T10:27:00.007+01:00</published><updated>2010-12-09T21:43:08.542+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>XP2011</title><content type='html'>I've just been appointed to the role of Industry Programme Chair for  XP2011, which will be held in Madrid in May. I've been to 7  of the previous 11 XP conferences and I am&lt;span style="font-style: italic;"&gt; so &lt;/span&gt;pleased to be asked to contribute to the success of the conference this year by doing this role.&lt;br /&gt;&lt;br /&gt;Rachel Davies is the general chair, and I am really looking forward to working with her and the other organizers. Rachel is one of those people I have met repeatedly at conferences and always has something interesting to contribute. More recently, I read her excellent book on Agile Coaching. I can't remember exactly when I first met her, but I do remember meeting her former colleagues from Connextra, Tim MacKinnon and Steve Freeman. I can still picture them in the small minibus that picked us up from a tiny Italian airport in 2002. It was a hot summers day, and we were driven at high speed along small Sardinian roads to the lovely hotel Calabona by the sea and the historic walled city of Alghero. I remember being so impressed to meet some people who were actually doing eXtreme Programming &lt;span style="font-style: italic;"&gt;for real&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;There were &lt;span style="font-style: italic;"&gt;so&lt;/span&gt; many inspirational people at that conference, it was really a turning point in my career. I just found the old conference programme &lt;a href="http://www.xp2002.org/prog_full.html"&gt;online here&lt;/a&gt;, and it brings back so many memories!&lt;br /&gt;&lt;br /&gt;I remember sitting by the pool discussing subjects like how to test drive refactoring with Frank Westphal and Steve Freeman. There was a firey keynote from Ken Schwaber encouraging us to start a revolution in software development world. I remember Joshua Kerievsky asking Jutta Eckstein to explain all about how she was doing XP with a team of over 100 people. Following David Parnas' keynote about using a formal test specification language to define requirements I remember Martin Fowler opining about its usefulness or lack of it, (do read &lt;a href="http://martinfowler.com/articles/xp2002.html"&gt;his blog post about it&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;The colourful personality of Scott Ambler demonstrated his ability to break a plank of wood in two with his bare hands, as some kind of lesson to do with dedication and focus. The conference dinner at Poco Loco really was a little crazy, with a bunch of uncoordinated geeks going for it on the dancefloor while the local band played very loudly. The morning after everyone was rather subdued when listening to Enrico Zaninotto reading his keynote in halting English, relating XP to the history of manufacturing and modern lean ideals. Half the audience was having trouble staying awake which in no way reflected the quality of what he was saying. It was truly inspiring, and Mary and Tom Poppendieck in particular were listening in rapt attention.&lt;br /&gt;&lt;br /&gt;Michael Feathers wore a T-shirt saying "Save the LSF", and Geoff and I asked him why he was so interested in platform computing's Load Sharing Facility. It turned out Alan Francis had recently become unemployed and Mike was helping in the campaign to "Save the Lightly Scottish Fellow"!&lt;br /&gt;&lt;br /&gt;Laurent Bossavit was going round trying to attract people to his Birds Of a Feather session on the writings of Gerald Weinberger. Erik Lundh was taking about his team in Sweden who had done a complete XP iteration in 2 days when faced with an unexpected deadline. Steven Fraser seemed to be videoing everything and anything, including someone demonstrating the correct way to twirl Italian Spaghetti on a fork. Mike Hill was (as ever) being loud but friendly. Charlie Poole seemed to be full of insightful analogies and comments. Dave Hussman was really friendly too.&lt;br /&gt;&lt;br /&gt;It was just fantastic the way the XP community welcomed us in, and particularly Kent Beck's attitude was instrumental in that. My husband Geoff and I presented a poster at the conference with title "One suite of automated tests" based mainly on Geoff's experiences with the tool that was to become &lt;a href="http://texttest.org/"&gt;TextTest.&lt;/a&gt; We turned up on the first day for a workshop about "testing in XP", and Geoff was immediately controversial by saying that he didn't do any unit testing, only this weird text-based testing thing using log comparison. He said he found it so successful that he used it instead of both the XP practices of functional and unit testing. I remember several people being quite dismissive of his ideas.&lt;br /&gt;&lt;br /&gt;Later in the conference, Kent Beck made a particular effort to talk to us and we took our picture standing by our poster. Apparently he had been asking people to try to be inclusive and friendly to us after the somewhat negative reaction to our ideas. I think he wanted the newly-forming XP community to be welcoming and to embrace diversity of opinion.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_AkG8Hw7A2Pw/TQC2fW-FyeI/AAAAAAAAAFg/QxiO2uEbdTA/s1600/kentWithPoster.jpg"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_AkG8Hw7A2Pw/TQC2fW-FyeI/AAAAAAAAAFg/QxiO2uEbdTA/s320/kentWithPoster.jpg" alt="" id="BLOGGER_PHOTO_ID_5548635390778657250" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;So now I should turn this around and look instead to the future. I'd love it if even half the people I've mentioned in this post found time in their diaries to come to Madrid in May for XP2011. I wouldn't want them to come alone though, there are so many fantastic and inspirational people who have joined the ever-expanding agile community since 2002.&lt;br /&gt;&lt;br /&gt;I am every bit as keen now as Kent was then to see that the agile community embraces newcomers, and that the XP conference should provide a space where researchers and practitioners can freely discuss the state of the art. I hope we'll make new friends and business contacts, learn loads, and have fun. &lt;a href="http://www.xp2011.org/node/6"&gt;Would you like to join us there?&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-7393324487254115368?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/7393324487254115368/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=7393324487254115368' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/7393324487254115368'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/7393324487254115368'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2010/12/xp2011.html' title='XP2011'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_AkG8Hw7A2Pw/TQC2fW-FyeI/AAAAAAAAAFg/QxiO2uEbdTA/s72-c/kentWithPoster.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-2066653556547779102</id><published>2010-12-03T09:18:00.004+01:00</published><updated>2010-12-03T11:21:48.017+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Code Kata'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Django</title><content type='html'>Last night at &lt;a href="http://www.meetup.com/GothPy/calendar/15534820/"&gt;GothPy&lt;/a&gt; we had a play with &lt;a href="http://www.djangoproject.com/"&gt;Django&lt;/a&gt;, a web application framework for Python. I'm fairly familiar with &lt;a href="http://rubyonrails.org/"&gt;Rails&lt;/a&gt;, so it was interesting to see a different take on solving the same kinds of problems.&lt;br /&gt;&lt;br /&gt;I downloaded Django for the first time when preparing for the meeting, and spent about a day going through the &lt;a href="http://docs.djangoproject.com/en/dev/intro/tutorial01/"&gt;tutorial&lt;/a&gt; and trying stuff out. At the meeting were a few people who have used Django before, notably Mikko Hellsing, who has worked with it daily for several years.&lt;br /&gt;&lt;br /&gt;It was so much easier learning the tool from people who knew it than by reading the documentation. Constant code review and real time answering of questions is just brilliant for learning.&lt;br /&gt;&lt;br /&gt;At the meeting we decided to implement a very very simple web application, similar to the one that Johannes Brodwall performed as a Kata at XP2010 together with Ivar Nilsen. He calls it "&lt;em&gt;Java EE Spike Kata&lt;/em&gt;" since he does it in Java with no particular web frameworks, just what comes with Java. (There is a video of him doing it on his &lt;a href="http://johannesbrodwall.com/2010/09/30/java-ee-spike-kata/"&gt;blog&lt;/a&gt;, and sample solution &lt;a href="https://github.com/jhannes/java-ee-spike-kata.git"&gt;here on github&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;I thought we should be able to implement the same little application in any web framework, and it might be interesting to see differences, so I though we should try doing it in Django. It just involves two pages. One page "Add User" which lets you create a new user and save it to the database, and another page "Search User" which lets you search for users, and presents results. So the scenario is to create a user, search for them, and see they are returned.&lt;br /&gt;&lt;br /&gt;When I work on a problem in Rails I usually start with a &lt;a href="http://cukes.info/"&gt;Cucumber&lt;/a&gt;  scenario for the feature, and I discovered there is a python version of  Cucumber called &lt;a href="https://github.com/gabrielfalcao/lettuce"&gt;Lettuce&lt;/a&gt;. We could have course have just used Cucumber with python, but given the big "WARNING - Experimental" notice Aslak wrote on &lt;a href="https://github.com/aslakhellesoy/cucumber/tree/master/examples/python"&gt;this page&lt;/a&gt;,  I thought we could give Lettuce a try.&lt;br /&gt;&lt;br /&gt;So at the meeting we all worked together with one laptop and a projector, (me at the keyboard), and we started with a Lettuce  scenario. We implemented step definitions using &lt;a href="http://docs.djangoproject.com/en/dev/topics/testing/#module-django.test.client"&gt;Django's test Client&lt;/a&gt;, which is a kind of headless browser that understands how to instrument a Django application. Then we spent a couple of hours writing Django code together until the scenario was all green.&lt;br /&gt;&lt;br /&gt;The code we ended up with isn't much to write home about, but I've put it up on github &lt;a href="https://github.com/emilybache/gothpy-katas/tree/master/LearnDjango/"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;What we learned from this exercise&lt;/span&gt;&lt;br /&gt;Of course since I know Rails much better, I found it interesting to compare the two web frameworks. Django seems similar in many ways. It was dead easy to get up and running, it gives you a basic structure for your code, and separates the model from the presentation layer.&lt;br /&gt;&lt;br /&gt;The O-R mapping looks quite similar to ActiveRecord in the way you declare model classes backed by tables in the db. The presentation layer seems to have a different philosophy from Rails though. The html view part is rather loosely coupled to your application, and doesn't allow you to embed real python code in it, just basic control structures.&lt;br /&gt;&lt;br /&gt;You hook up the html to the controller code using url regular expression matching. I was a little confused about exactly how was supposed to work, since what I considered controller code was put in a file called "views.py". Most of the code we wrote ended up in here, and I feel a bit unhappy with it. It seems to be a mixture of stuff at all levels of abstraction. The Django Form objects we used seemed quite powerful though, and reduced the amount of code we had to write.&lt;br /&gt;&lt;br /&gt;The biggest difference I noticed compared with Rails was how explicit Python is about where stuff comes from. You always have to declaratively import or pass stuff before you can use it, so I found it straightforward to follow the connections and work out which code was executed and where it came from. I think that is because of Python's philosophy of strict namespaces, which Ruby doesn't have so much of.&lt;br /&gt;&lt;br /&gt;I also liked the way Django encourages you to structure a larger web application into a lot of independent smaller ones, and lets you include and re-use other people's small apps. Rails has plugins too of course, but I thought Django's way made it seem very natural to contribute and re-use code.&lt;br /&gt;&lt;br /&gt;Comparing Lettuce to Cucumber, they look almost the same, (by design). One small difference I found was that Cucumber step definitions don't care if you write "Given", "When" or "Then" in front of them, whereas Lettuce did. So I had steps like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Then I should see "results found"&lt;br /&gt;And I should see "Name"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;where the first step passed and the second step was reported as unimplemented by Lettuce. So Lettuce need a little more work to be really usable.&lt;br /&gt;&lt;br /&gt;I was also pretty disappointed by the &lt;a href="http://docs.djangoproject.com/en/dev/topics/testing/#module-django.test.client"&gt;Django test client&lt;/a&gt; for implementing test steps. It seemed to interact with pages at an abstraction layer lower than I am used to - at the level of making post and get requests and parsing html as a dom. I missed &lt;a href="https://github.com/jnicklas/capybara"&gt;Capybara&lt;/a&gt; and its DSL for interacting with web pages. I couldn't find any equivalent. I probably should have turned to &lt;a href="http://seleniumhq.org/"&gt;Selenium&lt;/a&gt; directly, but since we had no client side javascript it seemed overkill. (Francisco Souza has written about using Lettuce with Selenium compared with the Django test client &lt;a href="http://www.franciscosouza.com/2010/07/seleniumless-django-applications-using-the-test-client/"&gt;here&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;When it comes to unit-level testing, Django provides &lt;a href="http://docs.djangoproject.com/en/dev/topics/testing/#testcase"&gt;an extension to the normal unittest tool&lt;/a&gt; that comes with python (unittest was originally based on JUnit). We didn't do much with it at the session, and it seemed to work fine. It's nothing like &lt;a href="http://rspec.info/"&gt;RSpec&lt;/a&gt; though, and I miss that expressiveness and structure for my tests whenever I work in Python.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Overall&lt;/span&gt;&lt;br /&gt;All in all it was fun to look at Django with a group and to get some really helpful comments and insights from people who know it far better than I do. The Kata we chose seemed to work ok, but I should really do it again in Rails since I spent the whole time comparing Django with Rails in my head, not Django with Johannes' Java code :-)&lt;br /&gt;&lt;br /&gt;My conclusions are basically that Django looks like a good alternative to Rails. It would take time to learn, and surely has strengths and weaknesses I can't really evaluate from one short session looking at it. However, I'd fairly sure I'd have to do some work improving the testing tools if I was going to be happy working with it for real.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-2066653556547779102?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/2066653556547779102/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=2066653556547779102' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/2066653556547779102'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/2066653556547779102'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2010/12/django.html' title='Django'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-6135513313569053694</id><published>2010-11-01T11:04:00.006+01:00</published><updated>2010-11-10T11:10:42.207+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Code Kata'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>KataMontyHall</title><content type='html'>I was at the local &lt;a href="http://www.meetup.com/got-rb/"&gt;Ruby User Group&lt;/a&gt; last night, and I coded up KataMontyHall (see below) as a prepared Kata in front of the group. I got some great comments and feedback while I was coding, and I think the solution I ended up with was better than any I had created by myself during my practice sessions. I also got some new ideas about different approaches which I plan to try out and see if they improve the code even more.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://redsquirrel.com/dave/"&gt;Dave Hoover&lt;/a&gt; was visiting from the US, on his way to a speaking engagement at &lt;a href="http://oredev.org/2010"&gt;Öredev&lt;/a&gt;. He and I were both surprised to discover a common interest in the Monty Hall Dilemma. Dave has previously worked on it, and he showed us some code that he wrote 5 or 6 years ago when he was still learning Ruby. He even wrote an &lt;a href="http://redsquirrel.com/dave/play/montyOnAjax.html"&gt;online version of the game&lt;/a&gt; when he was first learning ajax, that you can play yourself!&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The Monty Hall Dilemma&lt;/span&gt;&lt;br /&gt;There is a gameshow hosted by Monty Hall where contestants try to win a big prize, which is behind one of three doors. The contestant begins by choosing a door, but not opening it. Then Monty steps forward and opens one of the &lt;span style="font-style: italic;"&gt;other&lt;/span&gt; doors. He reveals a goat (!). Then the contestant has the choice of either sticking with the door they have already chosen, or switching to the other unopened door. Whichever door the contestant decides on will be opened, and if they find the prize, they get to keep it. (I'm not sure what happens if they get the second goat!) So what's the best strategy? Stick or switch?&lt;br /&gt;&lt;br /&gt;People are biased towards sticking with what they've chosen, and the vast majority of people stick with the door they choose originally. Intuitively there should be an equal chance of the prize being behind any of the three doors, so it shouldn't matter if you stick or switch. However, in this case, your intuition is wrong. You are twice as likely to win the prize if you switch to the other unopened door.&lt;br /&gt;&lt;br /&gt;I am not the only one to think this result is incorrect, apparently famous mathematicians have also refused to accept it. What finally convinced them, was a computer simulation. Hmm I thought, that sounds like an interesting piece of code :-)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Pigeons are smarter than Humans&lt;/span&gt;&lt;br /&gt;I heard about the Monty Hall Dilemma listening to the quirks and quarks &lt;a href="http://www.cbc.ca/quirks/episode/2010/06/26/australopithecine-big-man-pigeons-make-a-deal-confused-parasitic-ducks-bringing-up-baby-keeping-the/"&gt;podcast&lt;/a&gt;.  Apparently humans are strange, because they don't learn to switch  doors. Some researchers set up the same problem for pigeons, with birdseed behind one of the doors, and found the birds quickly learnt to switch doors. You can read the &lt;a href="http://www.ncbi.nlm.nih.gov/pubmed/20175592"&gt;research&lt;/a&gt; for yourself!&lt;br /&gt;&lt;br /&gt;So if you, like me, are keen to prove yourself more intelligent than a pigeon, why don't you spend some time writing a little program that simulates the game? If you get it right, your version of KataMontyHall should clearly show that switching doors is the best strategy :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-6135513313569053694?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/6135513313569053694/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=6135513313569053694' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/6135513313569053694'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/6135513313569053694'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2010/11/katamontyhall.html' title='KataMontyHall'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-6882797965328419036</id><published>2010-10-07T07:54:00.008+02:00</published><updated>2010-11-01T11:03:33.094+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>Agile Testing Days - day 2</title><content type='html'>On the wednesday of Agile Testing Days it was my turn to speak, and together with Fredrik Wendt we presented "The Coding Dojo as a forum for teaching Test Driven Development". The talk was mostly aimed at developers, and the basic idea is to encourage them to learn TDD, and that going to a coding dojo might be a good way of doing that.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Michael Bolton&lt;/span&gt;&lt;br /&gt;The first keynote of the day was by Michael Bolton, someone I've never met before. His talk really made me think. He presented himself as an "agile skeptic", and had some criticisms of agile practices like automated unit and functional testing. He talked about testing as something that humans do - it is a "sapient activity" requiring an engaged brain. He said "Automated acceptance tests do not answer questions about value" - that is whether the software will be valuable to the people who are going to use it. He preferred to call them "rejection checks" - that is they check whether the software will be rejected, but do not test whether it will be accepted. Only a human can do that. Michael went on to question the large level of investment that agile teams make in these kinds of tests. He thought that effort could perhaps be better invested, when studies show only 6-15% of problems are regression issues.&lt;br /&gt;&lt;br /&gt;Michael emphasized the role of testers in projects as "skilled investigators" who provide a service giving you information about a software product. He drew on an analogy with a film critic - they don't tell you if the film has passed or failed, they tell you about the attributes of the film that will appeal more or less to certain audiences.&lt;br /&gt;&lt;br /&gt;I liked the way Michael talked about testing as an investigative activity, and the role of testers as intelligent humans. I think he undervalues the feedback developers get from automated functional tests though. Agile teams do a lot more refactoring than other kinds of teams, and I think without automated tests they would have a lot more than 6-15% regression issues. I do think it is useful to evaluate investment in automated tests against other investments though. Some of the tools we have, particularly for functional/system level testing are not very cost effective to use.&lt;br /&gt;&lt;br /&gt;I also think that testers can only start doing a "film critic" kind of role when the software is largely free of basic defects. These should be caught before a skilled tester gets their hands on the software, by developers properly checking their work, and automating those checks.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-6882797965328419036?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/6882797965328419036/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=6882797965328419036' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/6882797965328419036'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/6882797965328419036'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2010/10/agile-testing-days-day-2.html' title='Agile Testing Days - day 2'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-8239117432478891742</id><published>2010-10-06T09:14:00.004+02:00</published><updated>2010-10-14T09:44:32.405+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ATDD'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>Agile Testing Days - first conference day</title><content type='html'>&lt;p style="margin: 0px; font: 14px Helvetica;"&gt;Yesterday, Geoff gave his talk about agile GUI testing. For anyone who missed it, &lt;a href="http://europythonvideos.blip.tv/file/3980793/"&gt;here is a video&lt;/a&gt; of him giving roughly the same talk earlier this year at Europython. Gojko Adzic has also &lt;a href="http://gojko.net/2010/10/05/rethinking-user-interface-test-automation/#more-2013"&gt;blogged about what he said&lt;/a&gt;, which is exactly the kind of feedback we came to this conference for. In his post Gojko explains Geoff’s testing approach, and seems quietly positive about it, at least compared to the “sine of death” you get with other UI test automation tools. His conclusion that it looked more suitable for legacy code than greenfield development is a little uncomfortable though. We think it works there too :-)&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica; min-height: 17px;"&gt;&lt;span style="letter-spacing: 0px;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica;"&gt;&lt;span style="letter-spacing: 0px;"&gt;Today I’m giving my talk about teaching Test Driven Development via Coding Dojos. I’m looking forward to some feedback from the community about that. In the meantime I’ve written a bit about the three keynote talks we listened to yesterday.&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica; min-height: 17px;"&gt;&lt;span style="letter-spacing: 0px;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica;"&gt;&lt;span style="letter-spacing: 0px;"&gt;&lt;b&gt;Lisa Crispin&lt;/b&gt;&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica;"&gt;&lt;span style="letter-spacing: 0px;"&gt;The day started with a keynote from Lisa Crispin titled “Agile Defect Management”.  The overall message was to “lower the bar!” and aim to reduce defect count as far as possible, even to the point where a defect tracking software becomes superfluous. There was a lot of talk about whether such a tool was needed, and in what situations, and she gave a good overview of the state of the art of thinking in this area. &lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica; min-height: 17px;"&gt;&lt;span style="letter-spacing: 0px;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica;"&gt;&lt;span style="letter-spacing: 0px;"&gt;This was a good talk, with audience involvement, by someone who knows what they are talking about. The thing is I have higher expectations from a keynote. I expect to come away inspired and challenged, with some new insight to take back to my daily life. For me, this talk didn’t really deliver that. Lisa concentrated too much on the specific question of whether to use an electronic defect tracking tool or not, and didn’t sufficiently put that question in to the wider context given in the title of the talk “agile defect management”. I was disappointed to find nothing really original or surprising in what Lisa said.&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica; min-height: 17px;"&gt;&lt;span style="letter-spacing: 0px;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica;"&gt;&lt;span style="letter-spacing: 0px;"&gt;&lt;b&gt;Linda Rising&lt;/b&gt;&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica;"&gt;&lt;span style="letter-spacing: 0px;"&gt;This was a good talk to hold straight after lunch when everyone is a bit sleepy. Linda spoke very amusingly on the subject “Deception and Estimation: How we Fool Ourselves”. She began by inviting us to see this as “the weird talk” of the conference, and that she was going to go through some of the latest scientific research in the area of cognition and psychology and hoped to relate that to why we have such trouble making good estimates in the context of a software project.&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica; min-height: 17px;"&gt;&lt;span style="letter-spacing: 0px;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica;"&gt;&lt;span style="letter-spacing: 0px;"&gt;A self-confessed scientific amateur, she stated up front that she wouldn’t provide references to the research she mentioned, although she could give them to you if you emailed her and asked. Linda then proceeded to relate a series of amusing anecdotes designed to illustrate how irrational and over-optimistic people can be. (Markus Gärtner &lt;a href="http://www.shino.de/2010/10/05/agile-testing-days-deception-and-estimation-how-we-fool-ourselves/"&gt;has blogged about&lt;/a&gt; what they all were). Towards the end of the talk, Linda began to relate all this to the subject of estimation, and told a story about some conference where she met people who were trying to apply scientific methods, statistics and data mining to the problem of improving estimates in software projects. In my mind, a seemingly a rational response to the problem of irrational, over-optimistic people. &lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica; min-height: 17px;"&gt;&lt;span style="letter-spacing: 0px;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica;"&gt;&lt;span style="letter-spacing: 0px;"&gt;Linda then did what I saw as a complete about-turn in her argument. She quoted one proponent of this “scientific” approach as saying, “well we can’t just make up a number, can we?”. Well no, we can’t, Linda just spent the last half hour convincing us humans are over-optimistic and irrational, and you can’t trust them to make up numbers. Yet that seemed to be exactly what Linda then proposed we do in agile. The points about the way agile overcomes this natural human over-optimism by for example breaking down problems into thin slices, using the wisdom of the crowd and enforcing tight feedback cycles, all kind of got crammed in at the end with little or no explaination.&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica; min-height: 17px;"&gt;&lt;span style="letter-spacing: 0px;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica;"&gt;&lt;span style="letter-spacing: 0px;"&gt;Quite apart from those specific criticisms of her argument, as someone with a scientific training I didn’t like the way Linda protrayed science and scientists. They initially appeared in Linda’s talk as white-coated oracles who make pronouncements of the truth. “80% of drivers think they are above average”. “You eat more at an all-you-eat buffet”. “Online daters lie about their age and weight”. She then attempted to shatter this illusion of scientific infalliability by quoting Planck, who pointed out that the scientific process doesn’t always proceed in an orderly manner, and sometimes new and better theories only really catch on when the older generation who invented the previous ones atually die off.&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica; min-height: 17px;"&gt;&lt;span style="letter-spacing: 0px;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica;"&gt;&lt;span style="letter-spacing: 0px;"&gt;Yes, scientists are human too, and you do them a disservice when you only present their results as received truths, without references, and without explaining either the methods they used to reach the conclusions, or what they themselves think of the wider applicability of the results.&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica; min-height: 17px;"&gt;&lt;span style="letter-spacing: 0px;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica;"&gt;&lt;span style="letter-spacing: 0px;"&gt;This could have been a far more interesting talk about actual recent research studies - what’s coming out of the latest brain imaging techniques, for exaple. Linda could also have spent more time explaining how agile works with human nature to provide better estimates and plans. For all that it made me laugh, all this talk left me with was a bunch of amusing anecdotes and an uneasy feeling that agile was anti-science.&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica; min-height: 17px;"&gt;&lt;span style="letter-spacing: 0px;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica;"&gt;&lt;span style="letter-spacing: 0px;"&gt;&lt;b&gt;Elisabeth Hendrickson&lt;/b&gt;&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica;"&gt;&lt;span style="letter-spacing: 0px;"&gt;The last session of the day saw Elisabeth Hendrickson presenting  “Lessons Learned from 100+ Simulated Agile Transitions”. With a huge amount of energy and panache, Elisabeth strode around the stage, explaining what happens in an exercise which she usually does with a group of 8-20 people over the course of a whole day. Within the framework of this simulation, she drew out stories and anecdotes to illustrate such diverse subjects as the Satir change model, how physical layout affects communication, the difference between status meetings and communication meetings, and tests as alignment tools.&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica; min-height: 17px;"&gt;&lt;span style="letter-spacing: 0px;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica;"&gt;&lt;span style="letter-spacing: 0px;"&gt;This talk was definitely the highlight of my day. Elisabeth took some things I kind of knew about, and made me think about them in a different light, from a different angle, and in a new context. I was challenged to go back to my standup meetings and make sure they really are about communication, and that my task board really does make status visible. I have a additional way of explaining ATDD to people - in terms of aligning developers and other stakeholders and getting them moving in the same direction.&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica; min-height: 17px;"&gt;&lt;span style="letter-spacing: 0px;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica;"&gt;&lt;span style="letter-spacing: 0px;"&gt;Having said all that, I do have a criticism (are you surprised?!). Elisabeth released her slides under the creative commons license, but she does not release the details of her simulation. This would effectively prevent anyone else from running it. I think this is rather like a tool vendor who presents a new testing approach, which by the way, you can’t use without either buying their tool, or spending a large amount of time and money developing your own version. Those kinds of talks don’t tend to get accepted at this kind of conference.&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica; min-height: 17px;"&gt;&lt;span style="letter-spacing: 0px;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica;"&gt;&lt;span style="letter-spacing: 0px;"&gt;I was disappointed that Elisabeth didn’t release her simulation materials, and I’m not sure why she doesn’t want to. She is obviously a fantastic agile coach and facilitator, and has more invitations to speak than she has time or inclination to accept. It would surely only enhance her reputation to make the agile transition simulation game materials available.&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px; font: 14px Helvetica;"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin: 0px; font: 14px Helvetica;"&gt;&lt;span style="letter-spacing: 0px;"&gt;&lt;span style="font-weight: bold;"&gt;Update&lt;/span&gt;: &lt;/span&gt;I talked to Elisabeth afterwards about her materials, and she related a  story about another independent consultant she knows, who arrived at a  client site ready to do a simulation exercise that he had designed, only  to discover the participants had done the exact same exercise the week  before with a different consultant! The other consultant had just taken  the material without permission or acknowledgement. Elisabeth doesn't  want to end up in the same situation, and I can understand that. She did  say she could release more information about the simulation though,  enough that you could understand how it is designed, and perhaps build  your own similar one. I think that would be a reasonable compromise. I just felt slightly cheated after her keynote - I wanted to look at this simulation, poke at it, see how it works and understand why she could use it to generate so many great insights into agile transitions.&lt;br /&gt;&lt;/p&gt; &lt;p style="margin: 0px; font: 14px Helvetica; min-height: 17px;"&gt;&lt;span style="letter-spacing: 0px;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-8239117432478891742?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/8239117432478891742/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=8239117432478891742' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8239117432478891742'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8239117432478891742'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2010/10/agile-testing-days-first-conference-day.html' title='Agile Testing Days - first conference day'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-5381219586533068557</id><published>2010-10-05T08:03:00.004+02:00</published><updated>2010-10-05T08:20:34.340+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pyUseCase'/><category scheme='http://www.blogger.com/atom/ns#' term='ATDD'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>Tutorial with Lisa Crispin at Agile Testing Days</title><content type='html'>I’m at Agile Testing Days this week, and yesterday I attended a tutorial with Lisa Crispin. I’ve never actually met her before, although I have read many of her articles, and the book she wrote together with Janet Gregory, “Agile Testing”. It’s an important book, covering in some detail the role of testers in agile teams, with lots of practical advice and anecdotes from real life.&lt;br /&gt;&lt;br /&gt;So I was very interested to meet Lisa and hear what she had to say. She had lots of general advice and war stories about what kinds of tools are useful in an agile setting. From all the new insights and thoughts I gathered from the tutorial, there were two stories that I’d like to share with you here.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The Whole team decides&lt;/span&gt;&lt;br /&gt;Lisa’s main message was that automated testing tool choice is a whole team decision, since everyone on an agile team will be affected. She told a story about when she joined a team of Java programmers and persuaded them to try Watir for web testing - a tool that lets you write tests in Ruby. Although the developers agreed to this and were initially keen to learn Ruby, it became clear after a while that they just weren’t comfortable with it, and Lisa found she just didn’t get the help she needed when extending and maintaining the tests. They switched to a tool where the tests were written in Java and things worked much better.&lt;br /&gt;&lt;br /&gt;That depressed me a little, I have to say. I’d personally much rather be writing Ruby than Java! Someone else chipped in with another story though. On his team they were also developing a system in Java, with the difference that the developers were very keen to learn Groovy. They had started writing tests using it, and it was working very well. It made writing tests more fun, since they got to learn a language they were interested in. The test automation work was less effort than expected, since they felt much more productive in Groovy than Java. I guess the difference is that the developers were motivated to learn the new language because they had chosen it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;You can do ATDD with GUI testing tools&lt;/span&gt;&lt;br /&gt;Lisa told an interesting story about GUI testing. She said she was working on some new features and realized that the only way to test them was was via a GUI testing tool. She was at first very skeptical that they would be able to do Acceptance Test Driven Development with a GUI tool - the GUI hadn’t been written yet, so how could they use this tool to write tests?&lt;br /&gt;&lt;br /&gt;In the end she said it turned out really well. They worked from GUI mockups of the new features, and wrote tests with placeholders. When the test scripts needed to interact with GUI elements that didn’t exist yet, she just wrote them in terms of what she’d like there to be there, based on the mockups. When the programmers came to implement the GUI, they could fill in the placeholders and quickly get the new tests running.&lt;br /&gt;&lt;br /&gt;This was encouraging since it’s basically the way you work with &lt;a href="http://www.texttest.org/index.php?page=ui_testing"&gt;PyUseCase&lt;/a&gt; too. A criticism we get sometimes is that since PyUseCase is a capture-replay tool, you can’t use it to define the tests before the GUI exists - a problem if you’re trying to do Acceptance Test Driven Development. Our experience matches Lisa’s though - you &lt;span style="font-style: italic;"&gt;can&lt;/span&gt; define the test in general terms, with placeholders, and parts that won’t execute at all at first. Some parts of the test of course can be recorded from the existing GUI. As the GUI is extended for the new feature, gradually you replace the placeholders with executable statements until the whole test passes.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;And now for the rest of the conference...&lt;/span&gt;&lt;br /&gt;Geoff is giving a talk this morning about PyUseCase and &lt;a href="http://texttest.org"&gt;TextTest&lt;/a&gt; as part of the main Agile Testing Days conference. We’d really like to get some feedback from experienced testers. It’s a different approach to capture-replay that most people here, like Lisa, will not have seen before. There are lots of other interesting talks and things going on too, and I hope to find time to blog a little more about the conference later in the week.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-5381219586533068557?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/5381219586533068557/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=5381219586533068557' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/5381219586533068557'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/5381219586533068557'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2010/10/tutorial-with-lisa-crispin-at-agile.html' title='Tutorial with Lisa Crispin at Agile Testing Days'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-8577467798776934966</id><published>2010-09-24T12:27:00.017+02:00</published><updated>2010-09-24T13:50:12.375+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Code Kata'/><category scheme='http://www.blogger.com/atom/ns#' term='Coding Dojo'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Coding Dojo Survey Results</title><content type='html'>A little while ago, &lt;a href="http://wendt.se/blog/"&gt;Fredrik Wendt&lt;/a&gt; and I put together a little survey and sent it to all the people we know who have attended coding dojo meetings here in Göteborg. There are several groups in the city which run these kinds of meetings from time to time. We wanted to know what kinds of things people are learning from practicing code katas in a group, and get some feedback and comments to help us to develop the groups we run.&lt;br /&gt;&lt;br /&gt;The survey got 29 responses - thankyou to everyone who participated! I was very encouraged to see that the overwhelming majority - 90% - said they would recommend the dojo to other people who wanted to improve their programming skills. There were lots of comments too - I won't include them all - but I particularly liked:&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center; font-weight: bold; font-style: italic;"&gt;"Dojos make me relive the joy of red-green-refactor” &lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: center; font-weight: bold; font-style: italic;"&gt;“you learn a lot from each other at these meetings”&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: center; font-weight: bold; font-style: italic;"&gt;“... planting seeds that have improved me as a programmer and a problem solver”&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: center; font-weight: bold; font-style: italic;"&gt;“I have started to think in terms of TDD”&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;The first question asked people which dojo(s) they had been to.&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_AkG8Hw7A2Pw/TJyAN46ePuI/AAAAAAAAAEI/hTYWXrJMx2w/s1600/chart.png"&gt;&lt;img style="float: left; margin: 0pt 10px 10px 0pt; cursor: pointer; width: 320px; height: 250px;" src="http://4.bp.blogspot.com/_AkG8Hw7A2Pw/TJyAN46ePuI/AAAAAAAAAEI/hTYWXrJMx2w/s320/chart.png" alt="Which dojo(s) have you been to?" id="BLOGGER_PHOTO_ID_5520428219353677538" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Fredrik and I set up &lt;a href="http://www.meetup.com/JDojo-Gbg/"&gt;JDojo@Gbg&lt;/a&gt; about a year ago, as an free coding dojo for Java programmers, sponsored by &lt;a href="http://iptor.com/"&gt;Iptor&lt;/a&gt;. We advertized it as a taught course - 5 sessions, once a month, come and learn TDD. We ran it twice together, and now Fredrik is continuing it together with &lt;a href="http://jsolutions.se/"&gt;Ola Berg&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The second sort of coding dojo going on in the town is various language user groups. It must be four years since I pestered Niclas Nilsson and CJ that we should do code Katas at &lt;a href="http://www.meetup.com/got-rb/"&gt;Got.rb&lt;/a&gt; (Göteborg Ruby User Group). Inspired by the success of that group, and together with Andrew Dalke and Johan Lindberg, I set up &lt;a href="http://www.meetup.com/GothPy"&gt;GothPy&lt;/a&gt; (Gothenburg Python User Group) about two years ago. More recently, Jonas Nicklas set up &lt;a href="http://groups.google.com/group/gotjs"&gt;Got.js&lt;/a&gt; (Göteborg javascript user group) and Jörgen Lundberg set up &lt;a href="http://www.meetup.com/Scala-Geats/"&gt;Scala Geats&lt;/a&gt; (Göteborg Scalaenthusiaster). So there are several small, language specific groups that meet and do dojo evenings occasionally, interspersed with other activities.&lt;br /&gt;&lt;br /&gt;The third kind of coding dojo meetings going on is where people run them internally at their employer, which lots of people do from time to time. In addition, Fredrik and I are both facilitating these kinds of groups at clients, as part of our work coaching teams and encouraging them to be more agile.&lt;br /&gt;&lt;br /&gt;I was pleased that people from all these sorts of groups filled in the survey, and that many people had been to more than one kind.&lt;br /&gt;&lt;br /&gt;Most of the survey respondents had been to 4 or 5 dojo meetings:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_AkG8Hw7A2Pw/TJyKwL4ys8I/AAAAAAAAAFI/UE_N5Z3KZpQ/s1600/how+many.jpg"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 223px;" src="http://1.bp.blogspot.com/_AkG8Hw7A2Pw/TJyKwL4ys8I/AAAAAAAAAFI/UE_N5Z3KZpQ/s320/how+many.jpg" alt="Roughly how many dojo meetings have you been to?" id="BLOGGER_PHOTO_ID_5520439803678733250" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;We asked several questions about perceived skill level before and after participation in dojo meetings. We wanted to know what people thought they were learning, basically.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_AkG8Hw7A2Pw/TJyElnCt7qI/AAAAAAAAAEY/D186_ihOTtM/s1600/improvements.002.jpg"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://2.bp.blogspot.com/_AkG8Hw7A2Pw/TJyElnCt7qI/AAAAAAAAAEY/D186_ihOTtM/s320/improvements.002.jpg" alt="" id="BLOGGER_PHOTO_ID_5520433024919793314" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;As you can see, people were fairly good at the programming language in question before the dojo(s), and only reported marginal improvements, 0.3 on average, on a five point scale.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_AkG8Hw7A2Pw/TJyFfPDDpcI/AAAAAAAAAEg/CgCmtAV5PSQ/s1600/improvements.003.jpg"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://2.bp.blogspot.com/_AkG8Hw7A2Pw/TJyFfPDDpcI/AAAAAAAAAEg/CgCmtAV5PSQ/s320/improvements.003.jpg" alt="" id="BLOGGER_PHOTO_ID_5520434014911178178" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;When it comes to the IDE used in the dojo, again, we are looking at a modest improvement, also 0.3 on a five point scale.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_AkG8Hw7A2Pw/TJyF7yg6uLI/AAAAAAAAAEo/DGB4PkMD4zE/s1600/improvements.004.jpg"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://4.bp.blogspot.com/_AkG8Hw7A2Pw/TJyF7yg6uLI/AAAAAAAAAEo/DGB4PkMD4zE/s320/improvements.004.jpg" alt="" id="BLOGGER_PHOTO_ID_5520434505468000434" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Using Mock Objects is a topic that doesn't always come up in dojo meetings, I personally have certainly had more of a focus on classic TDD. The feedback shows that people didn't feel they were that good at it before the meetings, and not that much better afterwards - an average 0.5 increase on a 5 point scale. From some of the comments, I think this is an area to focus on more in future. To that end, we're having a &lt;a href="http://www.meetup.com/GothPy/calendar/14701071/"&gt;GothPy meeting&lt;/a&gt; next week looking at Mockist TDD :-)&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_AkG8Hw7A2Pw/TJyGpgxiCPI/AAAAAAAAAEw/OWa0jCws1wg/s1600/improvements.005.jpg"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_AkG8Hw7A2Pw/TJyGpgxiCPI/AAAAAAAAAEw/OWa0jCws1wg/s320/improvements.005.jpg" alt="" id="BLOGGER_PHOTO_ID_5520435290979830002" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Refactoring is an essential part of Test Driven Development, and in fact any modern programmer's toolbox. I was pleased to see that people thought the dojo had helped them to improve this skill too - 0.5 on a five point scale.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_AkG8Hw7A2Pw/TJyH3yQ6_fI/AAAAAAAAAFA/iNxj6lfT3H0/s1600/improvements.006.jpg"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://4.bp.blogspot.com/_AkG8Hw7A2Pw/TJyH3yQ6_fI/AAAAAAAAAFA/iNxj6lfT3H0/s320/improvements.006.jpg" alt="" id="BLOGGER_PHOTO_ID_5520436635704688114" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;So it looks like going to a dojo encourages you to write unit tests more often - 0.6 (on a five point scale) more often on average.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_AkG8Hw7A2Pw/TJyHeD8yBSI/AAAAAAAAAE4/tz-A0OiIc2U/s1600/improvements.007.jpg"&gt;&lt;img style="display: block; margin: 0px auto 10px; text-align: center; cursor: pointer; width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_AkG8Hw7A2Pw/TJyHeD8yBSI/AAAAAAAAAE4/tz-A0OiIc2U/s320/improvements.007.jpg" alt="" id="BLOGGER_PHOTO_ID_5520436193775453474" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;This result is the most pleasing to me, since I think TDD is such an important skill, and it can be so difficult to get going with. People are moving from a low level of skill up to a medium level of skill - a whole 1 point (on a five point scale) on average! No-one is claiming to be a TDD expert yet though, I will have to repeat the survey in a few years and see if anyone is brave enough to claim that by then ;-)&lt;br /&gt;&lt;br /&gt;Fredrik and I are off to &lt;a href="http://www.agiletestingdays.com/"&gt;Agile Testing Days&lt;/a&gt;  in a week or so, where we'll be presenting a bit about what we've  been doing at these various groups, and what we recommend for others starting their own coding dojos. We've learnt a lot by running these meetings, and had fun too. Hopefully these survey results might encourage you to find a coding dojo and improve your programming skills!&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_AkG8Hw7A2Pw/TJyBASF6WhI/AAAAAAAAAEQ/z5tyrZD-Wrw/s1600/logo_atd.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; cursor: pointer; width: 206px; height: 64px;" src="http://2.bp.blogspot.com/_AkG8Hw7A2Pw/TJyBASF6WhI/AAAAAAAAAEQ/z5tyrZD-Wrw/s320/logo_atd.png" alt="Roughly how many dojo meetings have you been to?" id="BLOGGER_PHOTO_ID_5520429085106002450" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-8577467798776934966?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/8577467798776934966/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=8577467798776934966' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8577467798776934966'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8577467798776934966'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2010/09/coding-dojo-survey-results.html' title='Coding Dojo Survey Results'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/TJyAN46ePuI/AAAAAAAAAEI/hTYWXrJMx2w/s72-c/chart.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-8839472713392762004</id><published>2010-06-19T21:33:00.010+02:00</published><updated>2010-08-25T09:24:48.834+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pyUseCase'/><category scheme='http://www.blogger.com/atom/ns#' term='Bache Consulting'/><category scheme='http://www.blogger.com/atom/ns#' term='Coding Dojo'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>What to do next</title><content type='html'>I had fun for a few months programming Ruby at &lt;a href="http://elabs.se/"&gt;eLabs&lt;/a&gt;, but now I'm moving on*. What exactly I'll be doing next is not entirely clear. My plan, at least initially, is to work as an independent consultant specializing in automated testing and agile coaching. I'd also like to do some contract Ruby or Python programming. Hopefully I will find customers who are willing to hire me to do those things on a part-time basis, or with short term contracts, so I can do a mixture.&lt;br /&gt;&lt;br /&gt;I have a long term dream to build some kind of product around &lt;a href="http://sourceforge.net/projects/pyusecase/"&gt;PyUseCase&lt;/a&gt; and &lt;a href="http://texttest.org"&gt;TextTest&lt;/a&gt;. I really believe in the approach Geoff has built for testing rich client python GUIs, and I'd like to see if it could be adapted for testing web applications. I have some ideas I'd like to try out, but I'll need to find real customers with real applications and problems to try them out on. I'm hoping that will be possible through the agile testing consulting that I'll be doing.&lt;br /&gt;&lt;br /&gt;I'd also like to develop the idea of the coding dojo as a forum for teaching Test Driven Development and related agile engineering practices. I'm certain there is more that could be done to help people to get going with these skills. I'm looking into what courses are currently offered by local training providers, and hoping to both teach and develop those courses. I'm also working on my own formal training course based around the &lt;a href="http://www.meetup.com/JDojo-Gbg/"&gt;JDojo@Gbg&lt;/a&gt; meetings I led last year.&lt;br /&gt;&lt;br /&gt;As you may have noticed from &lt;a href="http://emilybache.blogspot.com/2010/05/programmer-conferences-are-like-games.html"&gt;previous posts&lt;/a&gt;, I really enjoy going to conferences, and often speak at them. I don't expect that to change much :-) Geoff and I are both scheduled to speak at &lt;a href="http://www.agiletestingdays.com/"&gt;Agile Testing Days&lt;/a&gt; in Berlin in October, which I am really looking forward to. It'll be a chance for us to learn from some of the best in our industry, and share some of our ideas. Geoff's testing tools are developing all the time, and I'll be talking about what we've learnt from the many dojo meetings going on in Göteborg. I'll be speaking together with my friend and former colleague &lt;a href="http://wendt.se/blog/"&gt;Fredrik Wendt&lt;/a&gt;, a stalwart member of &lt;a href="http://www.meetup.com/GothPy"&gt;GothPy&lt;/a&gt; and assistant leader of &lt;a href="http://www.meetup.com/JDojo-Gbg"&gt;JDojo@Gbg&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;So it's an exciting time for me, and I have several activities lined up to get me going with my new business. I'm also hoping to find a bit more time to spend writing articles for this blog. We'll see if I succeed!&lt;br /&gt;&lt;br /&gt;* eLabs is a very young company with only about 8 employees, and after I agreed to  join CJ and his team back in January the company strategy changed a  little. After I started in March, my role didn't work out the way I'd anticipated. CJ and I  had a good talk about it, and I think it's with no hard feelings on  either side that I left the company at the end of June.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-8839472713392762004?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/8839472713392762004/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=8839472713392762004' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8839472713392762004'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8839472713392762004'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2010/06/what-to-do-next.html' title='What to do next'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-3771677421524015141</id><published>2010-05-25T10:53:00.010+02:00</published><updated>2010-05-25T22:52:39.299+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='geek points'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>Programmer Conferences are like Games</title><content type='html'>Why are there so few women programmers? That's a big question. How about a related one that's slightly smaller: Why do so few women go to programmer conferences?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Nordic Ruby on Twitter&lt;/span&gt;&lt;br /&gt;&lt;a href="http://nordicruby.org/"&gt;Nordic Ruby&lt;/a&gt; was clearly appreciated by many of its attendees. See &lt;a href="http://twitter.com/#search?q=nordicruby"&gt;tweets like this&lt;/a&gt;:&lt;br /&gt;&lt;span class="status-body"&gt;&lt;span class="status-content"&gt;&lt;strong&gt;&lt;br /&gt;&lt;a href="http://twitter.com/ronge" class="tweet-url screen-name"&gt;ronge&lt;/a&gt;&lt;/strong&gt;:                              &lt;span class="actions"&gt;&lt;/span&gt;&lt;span class="entry-content"&gt;&lt;a href="http://twitter.com/search?q=%23nordicruby" title="#nordicruby" class="tweet-url hashtag" rel="nofollow"&gt;#nordicruby&lt;/a&gt; - best  conference ever, looking forward meeting you all next year ! Lots of  food for thoughts. Really sad it's over.&lt;/span&gt;      &lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="thumb vcard author"&gt;&lt;/span&gt;&lt;span class="status-body"&gt;&lt;span class="status-content"&gt;&lt;strong&gt;&lt;a href="http://twitter.com/skanev" class="tweet-url screen-name"&gt;skanev&lt;/a&gt;&lt;/strong&gt;:                              &lt;span class="actions"&gt;&lt;/span&gt;&lt;span class="entry-content"&gt;&lt;a href="http://twitter.com/search?q=%23nordicruby" title="#nordicruby" class="tweet-url hashtag" rel="nofollow"&gt;#nordicruby&lt;/a&gt; was just  awesome. Thank you guys&lt;/span&gt;           &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="thumb vcard author"&gt;&lt;/span&gt;&lt;span class="status-body"&gt;&lt;span class="status-content"&gt;&lt;strong&gt;&lt;a href="http://twitter.com/walming" class="tweet-url screen-name"&gt;walming&lt;/a&gt;&lt;/strong&gt;:                              &lt;span class="actions"&gt;&lt;/span&gt;&lt;span class="entry-content"&gt;Got so much inspiration. Big  thanks @&lt;a class="tweet-url username" href="http://twitter.com/elabs" rel="nofollow"&gt;elabs&lt;/a&gt; for &lt;a href="http://twitter.com/search?q=%23nordicruby" title="#nordicruby" class="tweet-url hashtag" rel="nofollow"&gt;#nordicruby&lt;/a&gt; conference.&lt;/span&gt;      &lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Very few Women&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;What I also noticed was, that of around 100 delegates, only 2 were women*.&lt;br /&gt;&lt;br /&gt;I have to say, I go to a lot of conferences, which gives me plenty to compare it to. In addition to Nordic Ruby, in the past year I have been to: &lt;a href="http://scottishrubyconference.com/"&gt;Scottish Ruby Conference&lt;/a&gt;, &lt;a href="http://www.scandevconf.se/"&gt;Scandinavian Developer Conference&lt;/a&gt;, &lt;a href="http://jfokus.se/"&gt;JFokus&lt;/a&gt;, &lt;a href="http://smidig2009.no/"&gt;Smidig&lt;/a&gt;, &lt;a href="http://europython.eu/"&gt;Europython&lt;/a&gt; and &lt;a href="http://www.xp2009.org/"&gt;XP2009&lt;/a&gt;. In general, I really enjoy conferences, and none of those I've mentioned had a huge proportion of females. Nordic Ruby was not exceptional in that respect. However, although I enjoyed Nordic Ruby, it does not feature in my all-time favourite list. I'll come to why in a minute. A lot of things about the conference were very good, of course. Some of the talks were excellent, and the venues, food and parties were absolutely top knotch.&lt;br /&gt;&lt;br /&gt;The format of of the conference was 30 minute talks (all on one track)  interspersed with 30-120 minute breaks. The last session of each day was  open and any attendee could give a short "lightning" talk, and many people did so. Every speaker, lightning or otherwise, had a large  audience, since there was nothing else on the programme.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Hampton Catlin's talk - the two kinds of Games&lt;/span&gt;&lt;br /&gt;My favourite talk was one by &lt;a href="http://nordicruby.org/speakers#talk_13"&gt;Hampton Catlin&lt;/a&gt;, talking about how to make applications attractive to their users. He talked a bit about the different kinds of games that people prefer.  Perhaps I can expand this idea to explain why I don't rate Nordic Ruby as highly as some of the other attendees clearly did.&lt;br /&gt;&lt;br /&gt;Hampton explained that computer games lie on a scale from Male-Oriented to Female-Oriented. They are called by those names because your physical gender is a good predictor of which sort you will prefer. (He stressed that you should keep in mind that people are complex, defy easy categorization, and a given individual could have preferences anywhere on the scale.)&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;br /&gt;The Male-Oriented game will let you score points and rank yourself against opponents. The Female-Oriented game will let you build supportive social networks with collaborators, and become admired by your peers. Hampton said that most computer games are Male-Oriented. He highlighted some  exceptions, including &lt;a href="http://www.facebook.com/FarmVille"&gt;Farmville&lt;/a&gt;, which is a popular game on Facebook. In fact, he said Facebook itself can be seen as a Female-Oriented game.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Programmer Conferences are like Games&lt;/span&gt;&lt;br /&gt;This got me thinking about the Nordic Ruby conference. If Facebook can be seen as a game, can you see a conference that way too? Do attendees play for "score" and "rank"? Is the programmer's conference game so Male-Oriented that most women just aren't interested in playing?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The Conference as a Male-Oriented Game&lt;/span&gt;&lt;br /&gt;If a programmer conference is a Male-Oriented Game, it will provide you with opportunities to improve your rank and score compared to other attendees. For example, giving a talk will let you show off the cool software project(s) you have created/contributed to. You can improve your rank by criticising other people's code, and contrasting it with the beauty of your own. You can also score "geek points" by making gratuitous references to obscure programming languages, advanced mathematics and classic sci-fi films.&lt;br /&gt;&lt;br /&gt;Your overall conference success is measured by how many people subsequently download your open source projects, and how many followers you gain on Twitter.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;The Conference as a Female-Oriented Game&lt;/span&gt;&lt;br /&gt;If a programmer conference is a Female-Oriented Game, it will provide you with opportunities to form supportive social networks and gain admiration. Lecture-style talks aren't so good for that, so the conference will schedule sessions for attendees to have conversations with each other, and collaborate. The conference programme will raise discussion topics that interest attendees, and encourage idea sharing. There may be organized group sessions where you share programming-related problems, pool your ideas and collectively come up with strategies to move forwards. You will gain admiration by being insightful, charming and subtly drawing people's attention to your open source projects, while also being admiring of others' projects.&lt;br /&gt;&lt;br /&gt;Your overall conference success is measured by how many people subsequently contribute to your open source projects, and how many friendly messages you get on Twitter.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Who Won Nordic Ruby?&lt;/span&gt;&lt;br /&gt;Ok, I'm stretching the analogy rather, (!) but I'd say the Nordic Ruby conference game was a little too Male-Oriented for my liking. The focus of the programme was on lecture-style talks, and, put it this way, the speakers made &lt;span style="font-style: italic;"&gt;way&lt;/span&gt; too many references to &lt;span style="font-style: italic;"&gt;Star Wars&lt;/span&gt;! There &lt;span style="font-style: italic;"&gt;were&lt;/span&gt; long breaks, which gave many opportunities for conversation, but there were no formal network-building activities. There was lots of time for chatting, but no mechanism to draw people together around, say, a discussion topic, or a collaborative coding exercise.&lt;br /&gt;&lt;br /&gt;The conferences I have enjoyed most have involved relatively few lecture-style talks, and largely comprised of workshops, coding dojos, tutorials, conversation corners and open space discussions. Next week I'm going to  &lt;a href="http://xp2010.org/"&gt;XP2010&lt;/a&gt; (which will be my seventh XP conference :-D), and it's the first ever &lt;a href="http://meetup.com/u/2QY"&gt;GothPyCon&lt;/a&gt; this Saturday. At both I am organizing coding dojo sessions - collaborative excercises in collective learning and mutual appreciation. Bring on the Female-Oriented conference games!&lt;br /&gt;&lt;br /&gt;* There was also two other females there, but neither are programmers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-3771677421524015141?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/3771677421524015141/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=3771677421524015141' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/3771677421524015141'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/3771677421524015141'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2010/05/programmer-conferences-are-like-games.html' title='Programmer Conferences are like Games'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-8338208117156398535</id><published>2010-04-30T21:33:00.003+02:00</published><updated>2010-04-30T22:48:36.994+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='clean code'/><category scheme='http://www.blogger.com/atom/ns#' term='Code Kata'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Python and Ruby and small methods</title><content type='html'>I've been working full time in Ruby now for about a month, and I think I'm beginning to get the hang of it. In many ways it's not so different from Python.&lt;br /&gt;&lt;br /&gt;I took some of the code I talked about struggling with in &lt;a href="http://emilybache.blogspot.com/2010/04/small-methods-tdd-and-defects.html"&gt;my last post&lt;/a&gt;, and set about translating it into Python. I wanted to see if the bugs were more obvious in a language I was more familiar with. Unfortunately before I was finished with the translation, my machine died and refused to restart, complaining about a disk error... so I may well have lost all my work. (ARRRGH!!) Anyway, before that happened, I was getting the feeling that the bugs weren't very obvious, even in a language I knew better.&lt;br /&gt;&lt;br /&gt;What I &lt;span style="font-style: italic;"&gt;did&lt;/span&gt; find though, was that it was quite hard to make the methods as short in Python as they were in Ruby. I &lt;span style="font-style: italic;"&gt;could&lt;/span&gt; make them as short, the language has the necessary features to do it, but when I did so, they just stopped looking like good Python to me.&lt;br /&gt;&lt;br /&gt;The other thing that I found was that RSpec lets you write really readable and well organized tests. Translating them into unittest made them just a travesty of their former selves.&lt;br /&gt;&lt;br /&gt;I've just listened to &lt;a href="http://blog.extracheese.org/2010/02/python-vs-ruby-a-battle-to-the-death.html"&gt;this talk&lt;/a&gt; by Gary Bernhardt, who is experienced in both Python and Ruby, and who has clearly thought quite hard about these kinds of issues and knows both languages very well. He has even tried to write a RSpec clone for Python, called &lt;a href="http://bitbucket.org/garybernhardt/mote"&gt;Mote&lt;/a&gt;. (He says himself that it isn't as good as RSpec, and that it is because Python lacks blocks, and won't let him monkeypatch core classes).&lt;br /&gt;&lt;br /&gt;Anyway, about half way through the talk, Gary shows this code example, first in Python:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;'\n'.join(obj.name&lt;br /&gt;    for obj in (&lt;br /&gt;        repository.retrieve(id)&lt;br /&gt;        for id in ids)&lt;br /&gt;   if obj)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Then the equivalent code in Ruby:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;ids.map do |id|&lt;br /&gt; repository.retrieve(id)&lt;br /&gt;end.compact.map do |obj|&lt;br /&gt; obj.name&lt;br /&gt;end.join('\n')&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Gary makes the point that the Ruby code is easier to read - you can follow it from top to bottom and see what it does. The thing is, I don't think many people would write code like that in Python. I might write it more like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;objs = [repository.retrieve(id) for id in ids]&lt;br /&gt;objs = filter(lambda x: x, objs)&lt;br /&gt;names = [obj.name for obj in objs]&lt;br /&gt;'\n'.join(names)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This code is four statements long, rather than one, and has two local variables ("objs" and "names") which the other two code snippets lack. In real code, you would probably be able to come up with rather more descriptive names, drawn from the problem domain. When I compare this code with the Ruby, I don't think it is any less readable. The filter(lambda x: x, objs) is not as nice as the Ruby call to "compact", but on the other hand, I think the two additional local variables make it clearer what is going on.&lt;br /&gt;&lt;br /&gt;I'm wondering whether the trouble I was having locating bugs in these small methods was because they were cramming so much into one statement, and almost completely lacking in local variables. That seems to be the Ruby way of doing things - maybe I will just get used to it and learn to read it just as well eventually? I guess I am going to find out!&lt;br /&gt;&lt;br /&gt;Anyway, I'm really hoping the friendly support technicians manage to save the contents of my hard disk, I want to use the code in an exercise at the upcoming Gothenburg Python Conference - &lt;a href="http://www.meetup.com/GothPy/calendar/13107391/"&gt;GothPyCon&lt;/a&gt;. I am hoping to run a workshop where half the room gets the buggy code with small methods, and the other half gets the same code refactored into longer methods. You get half an hour to find the bugs, then swap to the other codebase and find them again. Then I was hoping to have a discussion about which codebase was easier to debug, and/or split into pairs and re-implement the code from scratch, and see if we could come up with other designs that solved the problem more elegantly and transparently.&lt;br /&gt;&lt;br /&gt;If issues like this interest you - design, refactoring and testing -, I really hope you will come along!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-8338208117156398535?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/8338208117156398535/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=8338208117156398535' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8338208117156398535'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8338208117156398535'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2010/04/python-and-ruby-and-small-methods.html' title='Python and Ruby and small methods'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-3007081742502055493</id><published>2010-04-06T21:41:00.003+02:00</published><updated>2010-04-07T23:19:37.276+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='TextTest'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Small methods, TDD and defects</title><content type='html'>Last week at &lt;a href="http://scottishrubyconference.com/posts"&gt;Scottish Ruby Conference&lt;/a&gt; I chatted with &lt;a href="http://www.exampler.com/blog/"&gt;Brian Marick&lt;/a&gt; about software design. The week before that, he had been in Göteborg for &lt;a href="http://www.scandevconf.se/"&gt;Scandinavian Developer Conference&lt;/a&gt;, and had spent a morning pair programming with Geoff on &lt;a href="http://texttest.org/"&gt;TextTest&lt;/a&gt;. I took the chance to ask Brian what he thought about text-based testing now that he had seen it in action.&lt;br /&gt;&lt;br /&gt;Brian's view seems to be that text-based testing may be effective as a testing technique, but it just doesn't offer the design benefits you get with standard TDD. It doesn't give you guidance about small-scale design decisions, or intice you to structure your code into really small methods and classes. He thought the TextTest codebase wasn't bad, but that the methods were larger than he would prefer, some classes were doing too much, and some ideas were not expressed clearly.&lt;br /&gt;&lt;br /&gt;I've previously read about this design ethic of having really really small classes and methods in Bob Martin's book "Clean Code". Bob recommends one or two line methods. In contrast, I believe Steve McConnell's "Code Complete" advocates methods small enough to fit comfortably on one screen. Geoff's design for TextTest seems to land at about 5 or 6 lines for a typical method, which is somewhere in between.&lt;br /&gt;&lt;br /&gt;Brian said the main drawback of code structured largely into small classes and one and two line methods is that it is harder for people who are unfamiliar with the codebase to get to grips with it. You get lost in the trees, and can't easily get an overview of the forest. The big benefit is that people who are familiar with the code can potentially make sweeping improvements through very small, localized changes.&lt;br /&gt;&lt;br /&gt;I've had the opportunity to work on this kind of codebase recently, and my experience hasn't been entirely positive. Just as Brian predicted, I've found it hard to get into the code and grasp what it is doing. All the methods are one or two lines, and call each other. My pair and I ended up creating a temporary file where we pasted a whole call chain of about 6 methods so we could see them all at once, and read them in the order they called each other. There were 3 defects hidden in that 15 or so lines of code, and it took us a day or so to identify and fix them all. Yet, the code had been TDD'd, and the methods were well named. On the surface it looked very good. It actually took me some time to convince myself that we genuinely had found a defect, and that we hadn't just misunderstood what the code was supposed to do.&lt;br /&gt;&lt;br /&gt;The trouble seemed to stem from the fact that almost all the tests were for the "happy path" and there were several edge cases they never considered. Also, in one case the test had stubbed out the answer that one of the lower-level methods would return, and provided an answer the real code never gave. It took a long time for us to add missing tests for edge cases, and localize the defects to particular methods in the long call chain.&lt;br /&gt;&lt;br /&gt;I'm very interested in whether we would have found it easier to find the defects if the code had been structured as two or three 5 line methods instead of 6 one and two line methods. I'm also interested if we would have found the issues more easily if the code had been built with text-based testing, with fewer, more coarse grained tests, and a few log statements printing key intermediate values. I'm considering getting the original versions of the files out of git and refactoring them to see how else they could have looked.&lt;br /&gt;&lt;br /&gt;I don't want you to conclude that I am against building designs with really small methods, or TDD, or using stubs or anything like that. I think there is value in all these techniques, each can be done well or badly, and you make tradeoffs when you choose your approach. You still need design skills and testing skills, whether you're doing TDD or text-based testing. If Brian Marick had built TextTest the design might well have turned out differently. I don't know how much of that would have been because of his use of TDD, and how much because of his skill, and views on design.&lt;br /&gt;&lt;br /&gt;I'm actually relishing the prospect of working on more code with very small methods, and using TDD to build on it. I've got loads to learn about software design and testing :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-3007081742502055493?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/3007081742502055493/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=3007081742502055493' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/3007081742502055493'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/3007081742502055493'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2010/04/small-methods-tdd-and-defects.html' title='Small methods, TDD and defects'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-4939086396216750578</id><published>2010-03-17T21:10:00.004+01:00</published><updated>2010-03-17T22:17:39.895+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>Discussion on TDD at SDC2010</title><content type='html'>As I mentioned in my&lt;a href="http://emilybache.blogspot.com/2010/03/should-professional-developer-always.html"&gt; last post&lt;/a&gt; I chaired a fishbowl discussion at &lt;a href="http://scandevconf.se/"&gt;SDC2010 &lt;/a&gt;with title "Should a professional developer always use Test Driven Development?". I was delighted that the invited panelists &lt;a href="http://blog.objectmentor.com/articles"&gt;Michael Feathers&lt;/a&gt;, Geoff Bache and &lt;a href="http://www.dalkescientific.com/writings/diary/"&gt;Andrew Dalke&lt;/a&gt; all turned up, along with a few dozen other conference participants. As I predicted, we had a lively and interesting debate.&lt;br /&gt;&lt;br /&gt;Michael half-jokingly complained that Bob Martin goes around making these controvertial statements all the time, which Michael then gets to go around defending. Michael has a much more conciliatory attitude than Bob, and his take was that every truly professional developer must have at least given TDD a good try and learnt the technique, even if they then decide not to use it.&lt;br /&gt;&lt;br /&gt;Geoff's main point was that we need to widen the definition of TDD to include any process that involves checking in tests at the same time as the code, and not restrict it to just the classic Red-Green-Refactor style with tests in the same language as the code.&lt;br /&gt;&lt;br /&gt;Michael was largely receptive to this view, or at least that the soundbite description of "never write any code until you have a failing test" probably was a bit too brief description to encompass the whole of TDD. He did argue though, that the classic TDD style leads to code with good design characteristics of high cohesion, loose coupling, small classes and methods etc, and that he had not found other design techniques which led to better code than TDD. He was not keen to move to a TDD approach without unit tests, and lose these benefits, even if they result in good tests.&lt;br /&gt;&lt;br /&gt;Andrew argued that TDD is not sufficient by itself to produce a good suite of tests, and that there are other, better ways to produce these tests. Andrew pointed out that he had examined Fitnesse, a codebase that Bob Martin, (and some others), has created using TDD, and that he found several bugs, including security holes in it. Michael's counterargument was that with TDD, you get as good tests as you are capable of - if you are not skilled/aware of security issues, then you won't test for security holes, whatever process you use to create tests.&lt;br /&gt;&lt;br /&gt;Another argument of Andrew's was that he often likes to write tests that he expects to pass, to verify that his code works as expected, for example that he has implemented an algorithm correctly. In the narrow definition of TDD, you are only allowed to write tests you expect to fail. Michael's take was that this was indeed a too narrow definition of TDD. He said that he frequently writes tests as a way of asking questions of his code, and this often leads to tests that pass straight away.&lt;br /&gt;&lt;br /&gt;Some of the "audience" also stepped up to the microphones and joined in. &lt;a href="http://www.exampler.com/blog"&gt;Brian Marick&lt;/a&gt; pointed out that forcing yourself to write the test first was a very good way of ensuring you do actually write the test, instead of being lazy and just writing more code. The counter to that was along the lines of that there are other processes for arriving at a good test suite, which took different kinds of discipline. Andrew quoted the sqlite project, which boasts 100% branch coverage of their code by their test suite. Publishing your coverage figures and refusing to let them slip is a way of preventing developer laziness too.&lt;br /&gt;&lt;br /&gt;Brian Marick wrote &lt;a href="http://www.exampler.com/testing-com/writings/coverage.pdf"&gt;an article&lt;/a&gt; about coverage and tests over a decade ago, so he summarized it for us, which was interesting, but I think slightly beside the point. I think he was trying to argue that measuring coverage alone is not enough to guarantee you have a good test suite, but I don't think that was what Andrew was trying to claim. Simply doing TDD is not a guarantee that you will end up with a good test suite either.&lt;br /&gt;&lt;br /&gt;For me, the interesting outcome of the discussion was pointing out that the alternatives to TDD are not only "cowboy coding" or "test later, ie never", or "bad tests", but that there are other legitimate ways to come up with a good test suite, and professional developers may choose to use them instead of classic TDD. TDD is a discipline which all professional developers should perhaps have in their repertoire though. I think we agreed it is also a teaching aid for learning to write good tests.&lt;br /&gt;&lt;br /&gt;Happily, we definitely all agree that creating a good automated test suite alongside code is important. The precise method a professional developer should always use to produce it was not agreed upon though.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-4939086396216750578?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/4939086396216750578/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=4939086396216750578' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/4939086396216750578'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/4939086396216750578'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2010/03/discussion-on-tdd-at-sdc2010.html' title='Discussion on TDD at SDC2010'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-1900255253935352751</id><published>2010-03-04T20:53:00.003+01:00</published><updated>2010-03-04T21:35:09.822+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>Should a professional developer always use TDD?</title><content type='html'>I'm really looking forward to &lt;a href="http://www.scandevconf.se/2010/conference/detailed-program/"&gt;Scandinavian Developer Conference&lt;/a&gt;, and in particular the fishbowl discussion I'll be moderating on the Tuesday at 10:30am. Presenting their views will be Michael Feathers, Andrew Dalke, and Geoff Bache, and the topic under discussion is the same as the title of this post: Should a professional developer always use TDD?&lt;br /&gt;&lt;br /&gt;I've been enthusiastic about writing automated tests for my code since 2000 when I discovered eXtreme Programming, and started using JUnit. It's become a habit for me to write tests before code. Occasionly I decide not to, perhaps I am feeling lazy, or think a test would be too difficult to write. I find I usually regret it and end up writing a test afterwards anyway.&lt;br /&gt;&lt;br /&gt;One of the things Bob Martin, (a colleague of Michael Feathers), says about TDD in his book "clean code", is that it is a matter of professionalism. Developers should be like doctors. Would you trust a doctor who didn't wash her hands because she didn't belive in it? Well, you shouldn't trust a developer who doesn't use TDD because she doesn't believe in it.&lt;br /&gt;&lt;br /&gt;I've known Andrew Dalke since 2002, and we've worked together on and off since then. Recently he wrote &lt;a href="http://www.dalkescientific.com/writings/diary/archive/2009/12/29/problems_with_tdd.html"&gt;this article&lt;/a&gt; criticising TDD. Andrew does not believe TDD is necessary for good development work to happen. Is he unprofessional? Far from it.&lt;br /&gt;&lt;br /&gt;My experience of working with Andrew tells me that he is an excellent programmer, who produces high quality code and automated tests. However, the process by which he arrives at this code and tests is not TDD. Tests get written during development, but not in advance of the code they test. The tests do not in any way drive the design, in fact, he uses knowledge of the design of the code to inform what tests he writes.&lt;br /&gt;&lt;br /&gt;Andrew says in his article "Once I have a good sketch of how the code is going to be, I often continue by filling in the details. At this point unit tests starts to be useful" he likens what he does to an XP spike solution, except that he does not throw away the spike code and start over when he starts adding tests.&lt;br /&gt;&lt;br /&gt;The other person I know who has a complex relationship with TDD is my husband Geoff. Several years ago he was labelled a heretic and almost thrown out when he admitted to a room full of XP enthusiasts that he didn't write unit tests at all. Geoff does write tests - a lot of tests in fact - but they are not xUnit tests, and they don't drive the design of his code.&lt;br /&gt;&lt;br /&gt;Geoff uses an approach he calls "text-based testing" which involves driving the program from the command line, (or some kind of script), and having his code write a plain text log file of what it is doing. A tool called TextTest picks up the log output and compares it to the saved version from a previous run. Differences are flagged as test failure.&lt;br /&gt;&lt;br /&gt;It's a simple idea, but it is actually very effective and easy to use when you get the hang of it. The main advantage over ordinary TDD is that there is little or no code written per test, meaning less code to maintain overall. The fact that the tests are independent of the design of the code makes refactoring easier, and writing tests for legacy code relatively risk-free. &lt;br /&gt;&lt;br /&gt;TDD is a bit different with the text-based approach though. Geoff thinks of what he does as TDD, but actually, only half of the test is nailed down in advance of the code - only the part that tells the program which features to exercise. The part that asserts that it did the right thing is simply recorded after the code is written.&lt;br /&gt;&lt;br /&gt;So I expect a fascinating and lively discussion to ensue when I get these guys together! Perhaps you'll join us?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-1900255253935352751?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/1900255253935352751/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=1900255253935352751' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/1900255253935352751'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/1900255253935352751'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2010/03/should-professional-developer-always.html' title='Should a professional developer always use TDD?'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-1753301730046964539</id><published>2010-02-21T21:04:00.008+01:00</published><updated>2010-03-03T21:43:32.642+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='testing quadrants'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>developer-in-test role and tester role</title><content type='html'>In my current assignment, I'm taking the role of "developer-in-test". I'm working in a large distributed development project, which is building new functionality on a large existing codebase. In practice, I work closely with the developers in the project and build automated tests for subsystems that previously had only manual tests. The developers can use these tests to support their work, and add new tests as they build new features.&lt;br /&gt;&lt;br /&gt;My background is basically as a developer, so I have been reading up on testing. I found "Lessons Learned in Software Testing" by Kaner, Pettichord and Bach very helpful, and "Agile Testing" by Lisa Crispin and Janet Gregory helpful and also very thorough. I find it interesting that the authors of the first book started out as developers and now classify themselves as testers, while Lisa and Janet apparently always have called themselves testers, although they clearly write a fair amount of code as part of their work.&lt;br /&gt;&lt;br /&gt;Dave Nicolette recently made a blog post &lt;a href="http://dnicolet1.tripod.com/agile/index.blog?entry_id=1989736"&gt;"Merging the developer and tester roles"&lt;/a&gt; where he argues that Tester is just a specialization of Developer in the agile world, like DBA (DataBaseAdministrator) is a specialization of Developer. He argues that agile teams need to be staffed with generalizing specialists. That means anyone can turn their hand to any task that is currently needed, while still having some tasks they perform with more skill than others.&lt;br /&gt;&lt;br /&gt;I like Dave's viewpoint, it fits my experience. I can only write effective 2nd Quadrant tests, (business facing, support the team), if I understand what the developers need, and I do that best if I have done some development on that part of the system myself. To put it another way, I need to be just as competent at writing code as the other developers in the project I'm working in, but I also need additional skills to do with testing.&lt;br /&gt;&lt;br /&gt;I like the term "developer-in-test" to describe a role writing and enabling 2nd Qudrant tests.&lt;br /&gt;&lt;br /&gt;Having said all that, I'm not sure I agree with Dave that the Developer and Tester roles should always be merged. In my current assignment I'm also helping a group of testers, usability experts, technical writers and product owners to get going with exploratory testing. This testing falls into Q3 of the agile testing quadrants, and is quite different. You still need testing skills, but developer skills are mostly irrelevant. It's much more about understanding what the user is trying to achieve with the system, and how they view it.&lt;br /&gt;&lt;br /&gt;I think there is a role for non-coding testers in Q3 testing. However, I don't think you'll get far with Q3 unless you have the other quadrants well covered with automated tests. So I think the majority of work for a tester in an agile environment is still going to involve test automation. Only the biggest projects will be able to afford to have non-coding testers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-1753301730046964539?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/1753301730046964539/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=1753301730046964539' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/1753301730046964539'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/1753301730046964539'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2010/02/developer-in-test-role-and-tester-role.html' title='developer-in-test role and tester role'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-9184012949159131311</id><published>2010-02-14T20:27:00.003+01:00</published><updated>2010-02-14T20:39:00.974+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pyUseCase'/><category scheme='http://www.blogger.com/atom/ns#' term='Code Kata'/><category scheme='http://www.blogger.com/atom/ns#' term='Coding Dojo'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>XP2010 workshop and lightning talk</title><content type='html'>I've just heard that two of my proposals for &lt;a href="http://xp2010.org"&gt;XP2010&lt;/a&gt; have been accepted, which means I will definitely be off to Trondheim in early June. I've heard Trondheim is very beautiful, and the XP conference it usually excellent, so I'm really looking forward to it. It will actually be my 8th XP conference!&lt;br /&gt;&lt;br /&gt;I'm going to be running a half day workshop "Test Driven Development: Performing Art", which will be similar to the one I ran at XP2009, (which I blogged about &lt;a href="http://jsolutions.se/2009/06/03/tdd-workshop-at-xp2009/"&gt;here&lt;/a&gt;).  I've put up a &lt;a href="http://codingdojo.org/cgi-bin/wiki.pl?KataWorkshop"&gt;call for proposals&lt;/a&gt; on the codingdojo wiki, so do write to me if you're interested in taking part.&lt;br /&gt;&lt;br /&gt;The other thing I'll be doing is a lightning talk "Making GUI testing productive and agile". This will basically be a brief introduction to &lt;a href="http://texttest.carmen.se/index.php?page=ui_testing"&gt;PyUseCase&lt;/a&gt; with a little demo. Hopefully it will raise interest in this kind of approach.&lt;br /&gt;&lt;br /&gt;Perhaps I'll see you there?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-9184012949159131311?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/9184012949159131311/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=9184012949159131311' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/9184012949159131311'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/9184012949159131311'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2010/02/xp2010-workshop-and-lightning-talk.html' title='XP2010 workshop and lightning talk'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-8651063993346251382</id><published>2010-02-05T20:43:00.004+01:00</published><updated>2010-02-05T21:35:15.917+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pyUseCase'/><category scheme='http://www.blogger.com/atom/ns#' term='GothPy'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>code coverage and tests</title><content type='html'>At &lt;a href="http://www.meetup.com/GothPy/"&gt;GothPy&lt;/a&gt; yesterday, Geoff talked about code coverage and tests. Geoff has spent a lot of his evenings lately working on &lt;a href="http://texttest.carmen.se/index.php?page=ui_testing"&gt;PyUseCase&lt;/a&gt;, and getting the test coverage up to 100%, (statement coverage), a feat which he achieved last week. The evidence for this is available for all to see &lt;a href="http://texttest.carmen.se/index.php?page=nightjob"&gt;on the texttest site&lt;/a&gt;, (which is updated daily, btw, so if it is not green and 100% the day you read this post, then clearly Geoff had a bad day yesterday).&lt;br /&gt;&lt;br /&gt;I have limited experience of using coverage statistics to evaluate my tests, so it was interesting to hear Geoff summarize his findings. He thought it had been well worth the effort to get coverage to 100%, he'd found some bugs, some dead code, and improved his design along the way. Actually, saying he has 100% coverage is a statement that needs qualification. The tool he's been using - coverage.py - has a feature whereby you can mark lines of code as # pragma: no cover, ie I don't want this line counted for coverage purposes. So he's marked 37 of 3242 lines like this.&lt;br /&gt;&lt;br /&gt;The reason for excluding these lines is mostly practical - due to the nature of the tool you can't test it automatically when it is in "interactive" mode without physically pressing the buttons yourself - so automated tests for that part are impossible. Some excluded lines are for error cases which should never occur, but for which it would be useful to have a good error message if they ever did.&lt;br /&gt;&lt;br /&gt;Overall, Geoff thinks coverage is very useful to help you to identify&lt;br /&gt;&lt;ul&gt;&lt;li&gt;poorly tested areas of your code&lt;/li&gt;&lt;li&gt;mistakes in your tests&lt;/li&gt;&lt;li&gt;dead code&lt;/li&gt;&lt;li&gt;refactoring opportunities&lt;/li&gt;&lt;/ul&gt;The first one is obvious, but the others might take more explaination. Generally, each test is for a specific feature. If you think you have a test for a feature, but the code coverage shows the implementation of that feature not to be covered, then there is probably a mistake in your test.&lt;br /&gt;&lt;br /&gt;Similarly, if your tests cover all your features and some code is not covered, maybe it's not that important code at all, and could be safely removed. Geoff's tests are not unit tests, they are testing the whole of PyUseCase, and that maybe makes a difference with this particular point. If I just had unit tests, and a piece of code wasn't covered, I'm not sure I could as easily infer that it wasn't needed as a part of a larger feature.&lt;br /&gt;&lt;br /&gt;Refactoring opportunities can be identified from gaps in coverage too. The idea is that poorly tested code is a clue that it has other problems too. Perhaps you find two pieces of code are similar, and one copy has a gap in coverage. This could indicate they originate from copy-paste programming, and could be combined into one routine, with full test coverage.&lt;br /&gt;&lt;br /&gt;Geoff had some tips for people who wanted to use coverage statistics to improve their tests.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Don’t design your tests around coverage. Write appropriate tests, and then measure coverage.&lt;/li&gt;&lt;li&gt;This applies even when working with coverage results. See the coverage report as containing clues for new tests, not commands.&lt;/li&gt;&lt;li&gt;Use “#pragma : no cover” in your code to be explicit about code that you decide not to try and cover. Review these periodically.&lt;/li&gt;&lt;li&gt;Don’t be fanatical about absolute numbers. Commands like “Aim for at least 85% coverage” are counterproductive. (You get what you measure).&lt;br /&gt;&lt;/li&gt;&lt;li&gt;It’s always good to increase feasible coverage. It’s sometimes better to spend your limited time on other things. But if you don’t measure, you can’t make that decision effectively.&lt;/li&gt;&lt;/ul&gt;These last points are mostly also made in &lt;a href="http://www.exampler.com/testing-com/writings/coverage.pdf"&gt;an article by Brian Marick&lt;/a&gt; which is quite old (1997). Geoff found the article when he was researching the talk for GothPy, and thought it was very good, and fits his experience.&lt;br /&gt;&lt;br /&gt;Inspired by Geoff's talk, I spent some time today trying to get some coverage numbers for the code and tests I'm working on at present. Unfortunately it seemed to be a bit tricky to get the coverage tool to work. It's not python, of course, and that may have something to do with it. Hopefully I'll sort it out and be able to write a new blog post about my own experiences with coverage statistics sometime soon.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-8651063993346251382?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/8651063993346251382/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=8651063993346251382' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8651063993346251382'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8651063993346251382'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2010/02/code-coverage-and-tests.html' title='code coverage and tests'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-8994585738292051325</id><published>2010-01-27T21:00:00.005+01:00</published><updated>2010-02-01T22:12:44.468+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='selenium'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Domain Specific Languages for Selenium Tests</title><content type='html'>I gave this talk at &lt;a href="http://jfokus.se/"&gt;JFokus&lt;/a&gt; this week in Stockholm. I thought people might be interested in a summary of my main points.&lt;br /&gt;&lt;br /&gt;I've been using &lt;a href="http://seleniumhq.org/"&gt;Selenium&lt;/a&gt; for web application testing for over a year now, on a couple of different projects. This talk is based on my experiences.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;What is Selenium?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Selenium is actually an umbrella term for a suite of tools. The two tools in the suite I have been using are&lt;a href="http://seleniumhq.org/projects/remote-control/"&gt; Selenium Remote Control&lt;/a&gt; (RC) ,which allows you to test your webapp as it runs in a broswer, from Java code., and &lt;a href="http://seleniumhq.org/projects/ide/"&gt;Selenium IDE&lt;/a&gt;, which is a Firefox plugin that allows you to record tests.&lt;br /&gt;&lt;br /&gt;Selenium's killer feature is that it allows you to test your app while it is running in a browser, with a real browser javascript engine. This is particularly important for web applications with a lot of javascript and ajax. Selenium is also actively maintained, with version 2.0 having recently arrived at alpha release status.&lt;br /&gt;&lt;br /&gt;I showed a demo of how to write a test using Selenium IDE to record browser interaction, then pasting that into Java code. The test doesn't pass the first time you execute it, you have to tweak the code to replace xpaths with ids, and add a "wait" for the page to load at one point in the test. I find this is typical - Selenium IDE helps you to get started with your test, but there is still a lot of manual work to get it to pass.&lt;br /&gt;&lt;br /&gt;The code you end up with is rather widget-oriented and low level, this is what I end up with in my example:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;@Test&lt;br /&gt;public void createNewPublisher() {&lt;br /&gt;        selenium.click("menuItemPNewPublisher");&lt;br /&gt;        selenium.waitForPageToLoad("30000");&lt;br /&gt;        selenium.type("name", "Disney");&lt;br /&gt;        selenium.type("address", "24 Stars Ave");&lt;br /&gt;        selenium.type("zipCode", "91210");&lt;br /&gt;        selenium.type("city", "Hollywood");&lt;br /&gt;        selenium.type("country", "USA");&lt;br /&gt;        selenium.type("contactPersonName", "Emily");&lt;br /&gt;        selenium.type("contactPersonEmail", "emily@test.com");&lt;br /&gt;        selenium.type("contactPersonPassword", "123456");&lt;br /&gt;        selenium.type("contactPersonRetypePassword", "123456");&lt;br /&gt;        selenium.click("save");&lt;br /&gt;        selenium.waitForPageToLoad("30000");&lt;br /&gt; &lt;br /&gt;        verifyEquals(selenium.getTable("Users.1.1"), "Emily");&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This is all very well, you can basically read what it is doing, (open the "New publisher" page, fill in a form, then check the user table displays correctly), but I think we can do better.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Agile Testing Theory&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.exampler.com/old-blog/2003/08/21/"&gt;Brian Marick &lt;/a&gt;came up with this idea of "Testing Quadrants", which helps us to reason about what kinds of tests we need in an agile project. Selenium tests generally fall into the second quadrant - business facing tests that support the team. This implies they should be written in the language of the business, to help developers to understand what they are building. This is in contrast to the low-level, widget oriented script that selenium IDE produces.&lt;br /&gt;&lt;br /&gt;It is better to discover a bug as soon after insertion as possible, and the faster the tests run, the more often you will run them. The usual rule of thumb says your tests must take less than a minute for you to run them as part of a TDD cycle, and less than 10 minutes for you to run them in the CI server. For a suite of selenium tests, even 10 minutes can be ambitious.&lt;br /&gt;&lt;br /&gt;Selenium tests are fundamentally slow. They are slow because they run inside the browser using its javascript motor.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;WebDriver &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;WebDriver (new in Selenium 2.0) uses a different model of interacting with your application under test. It uses the browser's api instead of its javascript motor. This means tests execute faster and more reliably, at the cost of supporting fewer browsers. In addition, WebDriver has a well thought out, clean api, and built in support for the PageObject pattern. Having said that, WebDriver is a very recent addition to selenium, and currently has poor or no integration with Selenium IDE and Selenium Grid.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;the Page Object pattern&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The PageObject pattern is a way of organizing your test code. It tells you to model your test code after the page structure of your application. The test I listed earlier could be rewritten using this pattern, and might look something like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;   @Test&lt;br /&gt;   public void createNewPublisher() {&lt;br /&gt;           PublisherData newPublisher = new PublisherData("Disney")&lt;br /&gt;           .withAddress(&lt;br /&gt;                           new AddressData("24 Stars Ave",&lt;br /&gt;                                           "91210", "Hollywood", "USA"))&lt;br /&gt;           .withContactPerson(&lt;br /&gt;                           new UserData("Emily", "emily.bache@test.com",&lt;br /&gt;                                           "123456"));&lt;br /&gt;       &lt;br /&gt;           NewPublisherPage page = new NewPublisherPage(selenium);&lt;br /&gt;           page.enterPublisherDetails(newPublisher);&lt;br /&gt;           ViewPublisherPage viewPage = (ViewPublisherPage)page.save();&lt;br /&gt;           viewPage.verifyPublisherDetails(newPublisher);&lt;br /&gt;   }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Here we are using a data struct to hold the form data, which tells you quite obviously that a PublisherData has a name, address and contact person. Then we have the Page Object for the NewPublisherPage, which uses selenium to navigate to the relevant page in the constructor, then has methods which allow us to interact with that page. When we as it to "save", we navigate to a new page, in this case the ViewPublisherPage, which we can ask to validate the new publisher is displayed correctly.&lt;br /&gt;&lt;br /&gt;This is an improvement over the original test in several ways. I think it is much more readable, we have a certain amount of type safety from the data struct, and if the page flow, or  form data changes, there are obvious central places in the code to update all the tests. We can easily vary the form data in different tests in order to do data driven testing.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Scenario classes&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;However, in the application I've been working on, we havn't used this pattern in quite this way. The application uses a lot of frames and ajax, and a page based model didn't really fit. So we've been using the idea of "Scenario" classes instead of Page Objects. They fulfill the same purpose, but instead of modelling pages in your app, these classes group together domain actions, or services that your application provides. The Scenario classes hide all the details of how to use selenium to interact with the GUI and achieve an outcome a user is interested in. In this case, creating a publisher.&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;    @Test&lt;br /&gt;    public void createNewPublisher() {&lt;br /&gt;            PublisherData newPublisher = new PublisherData("Disney")&lt;br /&gt;                   .withAddress(new AddressData("24 Stars Ave",&lt;br /&gt;                                    "91210", "Hollywood", "USA"))&lt;br /&gt;                            .withContactPerson(&lt;br /&gt;                                    new UserData("Emily", "emily@test.com",&lt;br /&gt;                                                            "123456"));&lt;br /&gt;&lt;br /&gt;            PublisherScenarios scenarios =&lt;br /&gt;                             new PublisherScenarios(selenium);&lt;br /&gt;            scenarios.createPublisher(newPublisher);&lt;br /&gt; &lt;br /&gt;            scenarios.verifyPublisherDetails(newPublisher);&lt;br /&gt;    }&lt;br /&gt;&lt;/pre&gt;&lt;span style="font-weight: bold;"&gt;Domain Specific Languages&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So with the PageObject or Scenario patterns, you could say that my tests are written in a kind of Domain Specific Language, in that they are written in terms close to the domain of the application they are testing. The trouble is, this is still Java code, and business people generally can't read Java. A more interesting DSL would enable communication between developers and business people.&lt;br /&gt;&lt;br /&gt;This is where I turned to &lt;a href="http://fitnesse.org/"&gt;Fitnesse&lt;/a&gt; to help me. I found it pretty straightforward to put some Fitnesse tables over the top of this kind of Java code. Since the Java code is already organized in terms of the domain, it becomes natural to offer the same functionality in tables with meaningful names.&lt;br /&gt;&lt;br /&gt;I chose Fitnesse because I wanted to try it out, but I think it would be equally easy to put &lt;a href="http://cukes.info/"&gt;Cucumber&lt;/a&gt; or &lt;a href="http://code.google.com/p/robotframework/"&gt;Robot Framework&lt;/a&gt; or something like that on top, too. The whole point of these tools is that they allow you to easily write executable tests in a language anyone with knowledge of the domain can read. This is a huge benefit to developers when talking to business people.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Closing advice&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Having said all this about how to make your Selenium tests more readable, robust and faster, I still find my Selenium test suite frustratingly slow and fragile (I havn't used WebDriver enough yet to know if that is the case there too). Compared to &lt;a href="https://launchpad.net/pyusecase"&gt;PyUseCase&lt;/a&gt;, it is in the dark ages. (Unfortunately PyUseCase has no support for web applications, so there's probably no point in mentioning it, actually. But it is a great tool!).&lt;br /&gt;&lt;br /&gt;The difference between PageObjects and Scenario classes is not huge, but I like the latter, because they allow me to easily exchange Selenium for a WebService. My tests are written in terms of the services the application offers, and if I indeed implement those services as WebServices, I can call them directly from the tests. Using a WebService instead of selenium immediately makes my tests much faster and more robust.&lt;br /&gt;&lt;br /&gt;The problem with testing against a WebService is the reason we chose Selenium in the first place - ajax and browsers are not covered.&lt;br /&gt;&lt;br /&gt;So for web 2.0 application testing, I recommend both API tests and Selenium tests. Use Selenium to test the crucial parts of your GUI, but write most of your tests against some kind of WebService or API. Write your tests in terms a business user would understand, even in the Java code, and then it is easy to create a Domain Specific Language on top using another tool.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-8994585738292051325?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/8994585738292051325/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=8994585738292051325' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8994585738292051325'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8994585738292051325'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2010/01/domain-specific-languages-for-selenium.html' title='Domain Specific Languages for Selenium Tests'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-330374933576870736</id><published>2010-01-10T19:53:00.003+01:00</published><updated>2010-01-10T20:41:42.388+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pyUseCase'/><category scheme='http://www.blogger.com/atom/ns#' term='TextTest'/><category scheme='http://www.blogger.com/atom/ns#' term='GothPy'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Testing PyTDDmon</title><content type='html'>One of the things I like about &lt;a href="http://www.meetup.com/GothPy/"&gt;GothPy&lt;/a&gt; is that lots of the people in the group enjoy writing code in their spare time, and like to share with us what they're up to.&lt;br /&gt;&lt;br /&gt;A little while back, Olof came up with this little tool, &lt;a href="https://code.launchpad.net/%7Eobjarni/+junk/pytddmon"&gt;PyTDDmon&lt;/a&gt;, which is to help you when you're doing TDD. Instead of your running your tests by hand, PyTDDmon sits in the background and runs them for you. When they are green, it has a little green blob, when they are red, it tells you how many are failing, and clicking on it gives you the stacktrace. Olof put together a &lt;a href="http://www.youtube.com/watch?v=sD6qzJNQEpE&amp;amp;feature=PlayList&amp;amp;p=5F75235C3BCC4172&amp;amp;index=0"&gt;screencast &lt;/a&gt;to show how it works.&lt;br /&gt;&lt;br /&gt;Following Geoff's presentation of &lt;a href="https://launchpad.net/pyusecase"&gt;PyUseCase&lt;/a&gt; at GothPy in December, he and Olof started to discuss whether it could be used to test PyTDDmon. Since it's using the GUI library &lt;a href="http://docs.python.org/library/tkinter.html"&gt;Tkinter&lt;/a&gt; instead of pyGTK, it didn't look all that straightforward.&lt;br /&gt;&lt;br /&gt;Of course, Olof developed the app using TDD in the first place, (definite own dog food eating going on!), and his unit tests have about 48% statement coverage. The parts with least coverage are GUI-related, so there seemed to be scope to improve matters by adding tests via the GUI.&lt;br /&gt;&lt;br /&gt;Geoff sat down a few days ago with a branch of the PyTDDmon code, started trying to generalize PyUseCase to work with Tkinter, and to write some tests for PyTDDmon. (Geoff also likes writing code in his spare time :-)&lt;br /&gt;&lt;br /&gt;As I write, he's just checking in his changes and a new suite of tests for PyTDDmon that use the new, improved PyUseCase, with (basic) Tkinter support! He says the hardest part was understanding Tkinter, and after a spot of refactoring, only an extra couple of hundred lines of code were needed to support it.&lt;br /&gt;&lt;br /&gt;Subsequently adding tests for PyTDDmon was very easy (Geoff wrote most of them while I made biscuits with the children this afternoon :-) All he had to do to Olof's code was assign names to some of the widgets, and sort out a problem with closing a window. (There was a listener for a mouse click that would destroy the window, before other listeners got a chance to do anything, such as record the click in a use case log...)&lt;br /&gt;&lt;br /&gt;So now the statement coverage of the PyTDDmon tests is at 98%. I look forward to future, equally productive GothPy meetings and discussions!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-330374933576870736?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/330374933576870736/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=330374933576870736' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/330374933576870736'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/330374933576870736'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2010/01/testing-pytddmon.html' title='Testing PyTDDmon'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-7677828620050507749</id><published>2010-01-08T19:56:00.003+01:00</published><updated>2010-01-08T20:20:56.103+01:00</updated><title type='text'>joining eLabs</title><content type='html'>I've enjoyed my time working for &lt;a href="http://www.iptor.com"&gt;Iptor&lt;/a&gt;, but I found I just couldn't refuse Carl-Johan when he offered me a job at &lt;a href="http://elabs.se"&gt;eLabs&lt;/a&gt;. I first med C-J a few years ago at &lt;a href="http://www.meetup.com/got-rb"&gt;Got.rb&lt;/a&gt;, the local Ruby User Group, and I know he has a great entrepreneurial spirit and deep technical expertise. eLabs is his company, (a startup he co-owns with &lt;a href="http://edithouse.se/"&gt;Edithouse&lt;/a&gt;), and he's attracted a really competent, friendly bunch of coders to join him. This a chance for me to get to learn Ruby and Rails properly, and work in a truly agile team. Hopefully I'll be able to contribute some insights from my years working with agile advocacy, automated testing, and development in Python and Java. I'm looking forward to starting at eLabs in April.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-7677828620050507749?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/7677828620050507749/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=7677828620050507749' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/7677828620050507749'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/7677828620050507749'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2010/01/joining-elabs.html' title='joining eLabs'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-3542145844812778659</id><published>2010-01-04T22:03:00.008+01:00</published><updated>2010-01-04T23:21:42.254+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pyUseCase'/><category scheme='http://www.blogger.com/atom/ns#' term='JUseCase'/><title type='text'>JUseCase, dreams of resurrection</title><content type='html'>&lt;a href="http://jusecase.sourceforge.net/"&gt;JUseCase&lt;/a&gt; is the Java version of &lt;a href="http://texttest.carmen.se/index.php?page=ui_testing&amp;amp;n=pyusecase_intro"&gt;PyUseCase&lt;/a&gt;, for testing GUIs written in Swing. It was originally written as a master's thesis by Claes Verdoes in 2005, under Geoff's supervision. Since then it hasn't been used much, and has lain idle and unmaintained for a while. In the meantime, Geoff has made some major changes to PyUseCase, culminating in the recent release of version 3.0, which I think is hugely better than any competing tools. But then I am biassed :-)&lt;br /&gt;&lt;br /&gt;I would love to see JUseCase resurrected and to support more of the features of PyUseCase 3.0. We originally got a lot of criticism of JUseCase that it required too many changes in application code; many developers are leery of changing their code to put in hooks "just for the tests". PyUseCase 3.0 removes the need for much of that, and I think JUseCase could do the same.&lt;br /&gt;&lt;br /&gt;In JUseCase, you have to connect widgets to domain actions by adding bits of code like this:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;JTextField originField = new JTextField(“ANY");&lt;br /&gt;ScriptedTextField.connect("choose origin", originField, ScriptedTextField.EDIT);&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;i.e. the text field "originField" should record a domain action "choose origin" when it is edited. This enables JUseCase to record and replay user actions in a domain language, at a higher level of abstraction than just widget names.&lt;br /&gt;&lt;br /&gt;In PyUseCase 3.0 these kinds of code changes are replaced by the UI map file. Widgets are identified by name, something like this:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;[Name=originField]&lt;br /&gt;edited = choose origin&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;So all you have to do in the code is make sure all your widgets have unique names. Good names are useful for accessability, (blind people etc), and for internationalization, so you can argue you're not just doing it for the tests.&lt;br /&gt;&lt;br /&gt;The second thing that PyUseCase 3.0 does to reduce code changes is to automatically generate the UI log, rather than you having to insert log statements by hand. The UI log is the part of the test definition that TextTest uses to assert the application is behaving correctly. It should be a low-fidelity rendering of what the UI looks like, in plain text.&lt;br /&gt;&lt;br /&gt;For example, for the simple application in my last post, the ui log might look like this:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;---------- Window 'Book Animals for Procedures' ----------&lt;br /&gt;Focus widget is 'available procedures'&lt;br /&gt;Showing available procedures with columns: available procedures&lt;br /&gt;-&gt; abdominocentesis&lt;br /&gt;-&gt; haircut&lt;br /&gt;-&gt; re-shoe&lt;br /&gt;-&gt; milking ,&lt;br /&gt;Showing available animals with columns: available animals , animal type&lt;br /&gt;-&gt; Good Morning Sunshine | mare&lt;br /&gt;-&gt; Goat 3 | goat&lt;br /&gt;-&gt; Goat 4 | goat&lt;br /&gt;-&gt; Guicho | gelding&lt;br /&gt;-&gt; Misty | mare&lt;br /&gt;Button 'book'&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This log is created just by inspecting the GUI elements in turn, and writing out a sketch of their contents.&lt;br /&gt;&lt;br /&gt;In order to add to this log as the user interacts with the application, PyUseCase attaches itself as a listener to each widget, so it finds out when they change. Then after the user has done some actions, when the GUI event queue is empty, it takes the opportunity to write a few log statements about what has changed since the last time it logged something. In this way it produces a neat summary of what the user does and what the UI looks like after each action. I should think JUseCase could do something similar.&lt;br /&gt;&lt;br /&gt;Then all that is left to hand code is to put in the application events - basically writing a log statement that you're doing something in another thread of execution, that the tests should wait for before proceeding. There shouldn't be too many of those calls, so hopefully they can slip under the radar.&lt;br /&gt;&lt;br /&gt;Anyone looking for a masters thesis topic fancy giving it a go?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-3542145844812778659?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/3542145844812778659/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=3542145844812778659' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/3542145844812778659'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/3542145844812778659'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2010/01/jusecase-dreams-of-resurrection.html' title='JUseCase, dreams of resurrection'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-7700432393785994474</id><published>2009-12-28T21:04:00.007+01:00</published><updated>2009-12-28T22:40:47.057+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='pyUseCase'/><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='TextTest'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>big UI changes and their effect on tests</title><content type='html'>I recently read&lt;a href="http://www.exampler.com/blog/2009/11/11/big-ui-changes-and-their-effect-on-tests/"&gt; this post&lt;/a&gt; in Brian Marick's blog, and it set me thinking. He's talking about a test whose intention in some way survived three major GUI revisions. The test code had to be rewritten each time, but the essence of it was retained. He says:&lt;br /&gt;&lt;blockquote&gt; &lt;p&gt;&lt;i&gt;I changed the UI of an app and so…&lt;/i&gt; I had to rewrite the UI code and the tests/checks of the UI code. It might seem the checks were worthless during the rewrite (and in 1997, I would have thought so). But it turns out that all (or almost all) of those checks contained an idea that needed to be preserved in the new interface. They were reminders of important things to think about, and that (it seemed to me) repaid the cost of rewriting them.&lt;/p&gt; &lt;p&gt;That was a big surprise to me.&lt;/p&gt; &lt;/blockquote&gt;I'm not sure why Brian is so surprised about this. If the user intentions and business rules are the same, then some aspects of the tests should also be preserved. A change in UI layout or technology should mean superficial changes only. In fact, one of the main claims for &lt;a href="http://texttest.carmen.se/index.php?page=ui_testing&amp;amp;n=xusecase"&gt;PyUseCase&lt;/a&gt; is that by having the tests written in a domain language decoupled from the specifics of the UI, it enables you to write tests that survive major UI changes. In practice this means when you rewrite the UI, you are saved the trouble of also rewriting the tests. So Geoff and I decided to write some code and see if this was true for the example Brian outlines.&lt;br /&gt;&lt;br /&gt;In the blog post, there is only one small screenshot and some vague descriptions of the GUIs these tests are for, so we did some interpolation. I hope we have written an application that gets to the gist of the problem, although it is undoubtedly less beautiful and sophisticated than the one Brian was working on. All the code and tests is on launchpad &lt;a href="http://bazaar.launchpad.net/%7Egeoff.bache/+junk/TestEvolution/files"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;We started by writing an application which I hope is like his current GUI. You select animals in a list, click "book" and they appear in a new list below. You select procedures from another list, and unsuitable animals disappear.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_AkG8Hw7A2Pw/SzkU194jPXI/AAAAAAAAADw/addPUb2ysic/s1600-h/gui+with+book+button.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 213px;" src="http://2.bp.blogspot.com/_AkG8Hw7A2Pw/SzkU194jPXI/AAAAAAAAADw/addPUb2ysic/s320/gui+with+book+button.png" alt="" id="BLOGGER_PHOTO_ID_5420386543894478194" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;In my app, I had to make up some procedures, in this case "milking", which is unsuitable for Guicho (no udders on a gelding!), and "abdominocentesis" which is suitable for all animals, (no idea what that is, but it was in Brian's example :-). Brian describes a test where an animal that is booked should not stay booked if you choose a procedure that is unsuitable for it, then change your mind and instead choose a procedure that it is suitable for.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;select animals Guicho&lt;br /&gt;book selected animals&lt;br /&gt;choose procedure milking&lt;br /&gt;choose procedure abdominocentesis&lt;br /&gt;quit&lt;br /&gt;&lt;/blockquote&gt;This is a list of the actions the user must take in the GUI. So Guicho should disappear when you select "milking", and reappear as available, but not as booked, when you select "abdominocentesis". This information is not in the use case file, since it only documents user actions.&lt;br /&gt;&lt;br /&gt;The other part of the test is the UI log, which documents what the application actually does in response to the user actions. This log is auto generated by pyUseCase. For this test, I won't repeat the whole file, (you can view it &lt;a href="http://bazaar.launchpad.net/%7Egeoff.bache/%2Bjunk/TestEvolution/annotate/head%3A/tests/animal_procedures/disappeared_booked_animals_dont_come_back/output.ap"&gt;here&lt;/a&gt;), but I will go through the important parts:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;'select animals' event created with arguments 'Guicho'&lt;br /&gt;&lt;br /&gt;'book selected animals' event created with arguments ''&lt;br /&gt;&lt;br /&gt;Updated : booked animals with columns: booked animals ,&lt;br /&gt;-&gt; Guicho | gelding&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;This part of the log shows that Guido is listed as booked.&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;'choose procedure' event created with arguments 'milking'&lt;br /&gt;&lt;br /&gt;Updated : available animals with columns: available animals , animal type&lt;br /&gt;-&gt; Good Morning Sunshine | mare&lt;br /&gt;-&gt; Goat 3 | goat&lt;br /&gt;-&gt; Goat 4 | goat&lt;br /&gt;-&gt; Misty | mare&lt;br /&gt;&lt;br /&gt;Updated : booked animals with columns: booked animals ,&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;/blockquote&gt;So you see that after we select "milking" the lists of available and booked animals are updated, Guicho disappears, and the "booked animals" section is now blank. The log goes on to show what happens when we select "abdominocentesis":&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;'choose procedure' event created with arguments 'abdominocentesis'&lt;br /&gt;&lt;br /&gt;Updated : available animals with columns: available animals , animal type&lt;br /&gt;-&gt; Good Morning Sunshine | mare&lt;br /&gt;-&gt; Goat 3 | goat&lt;br /&gt;-&gt; Goat 4 | goat&lt;br /&gt;-&gt; Guicho | gelding&lt;br /&gt;-&gt; Misty | mare&lt;br /&gt;&lt;br /&gt;'quit' event created with arguments ''&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;/blockquote&gt;ie the "available animals" list is updated and Guicho reappears, &lt;i&gt; but the booked animals list is not updated&lt;/i&gt;. This means we know the application behaves as desired - booked animals that are not suitable for a procedure do not reappear as booked if another procedure is selected.&lt;br /&gt;&lt;br /&gt;Ok, so far so good. What happens to the test when we compeletely re-jig the UI and it instead looks like this?&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SzkZsyKlOTI/AAAAAAAAAD4/eR_j0Vgpe-4/s1600-h/gui+with+checkboxes.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 308px;" src="http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SzkZsyKlOTI/AAAAAAAAAD4/eR_j0Vgpe-4/s320/gui+with+checkboxes.png" alt="" id="BLOGGER_PHOTO_ID_5420391883688196402" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Now there is no book button, and you book animals by ticking a checkbox. Selecting a procedure will remove unsuitable animals from the list in the same way as before. So now if you change your mind about the procedure, animals that reappear on the list should not be marked as booked, even if they were before they disappeared. There is no separate list of booked animals.&lt;br /&gt;&lt;br /&gt;What we did was take a copy of the tests and the code, updated the code, and see what we needed to do to the tests to make them work again. In the end it was reasonably straightforward. We didn't re-record or rewrite any tests. We just had to modify the use cases to remove the reference to the book button, and save new versions of the UI log to reflect the new UI layout. The use case part of the test looks like this now:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;book animal Guicho&lt;br /&gt;choose procedure milking&lt;br /&gt;choose procedure abdominocentesis&lt;br /&gt;quit&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;which is one line shorter than before, since we no longer have separate user actions for selecting and booking an animal.&lt;br /&gt;&lt;br /&gt;So updating the tests to work with the changed UI consisted of:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;remove reference to "book" button in UI map file, since button no longer exists&lt;/li&gt;&lt;li&gt;in use case files for all tests, replace "select animals x, y" with a line for each animal, "book animal x" and "book animal y".&lt;/li&gt;&lt;li&gt;Run the tests. All fail in identical manner. Check the changes in the UI log file using a graphical diff tool, once. (no need to look at every test since they are grouped together as identical by &lt;a href="http://texttest.org"&gt;TextTest&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;Save the updated use cases and UI logs. (the spurious line "book selected animals" is removed from the use case files since the button no longer exists)&lt;/li&gt;&lt;li&gt;Run the tests again. All pass.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;The new UI log file looks like this:&lt;blockquote&gt;&lt;br /&gt;'book animal' event created with arguments 'Guicho'&lt;br /&gt;&lt;br /&gt;Updated : available animals with columns: is booked , available animals , animal type&lt;br /&gt;-&gt; Check box | Good Morning Sunshine | mare&lt;br /&gt;-&gt; Check box | Goat 3 | goat&lt;br /&gt;-&gt; Check box | Goat 4 | goat&lt;br /&gt;-&gt; Check box (checked) | Guicho | gelding&lt;br /&gt;-&gt; Check box | Misty | mare&lt;br /&gt;&lt;br /&gt;'choose procedure' event created with arguments 'milking'&lt;br /&gt;&lt;br /&gt;Updated : available animals with columns: is booked , available animals , animal type&lt;br /&gt;-&gt; Check box | Good Morning Sunshine | mare&lt;br /&gt;-&gt; Check box | Goat 3 | goat&lt;br /&gt;-&gt; Check box | Goat 4 | goat&lt;br /&gt;-&gt; Check box | Misty | mare&lt;br /&gt;&lt;br /&gt;'choose procedure' event created with arguments 'abdominocentesis'&lt;br /&gt;&lt;br /&gt;Updated : available animals with columns: is booked , available animals , animal type&lt;br /&gt;-&gt; Check box | Good Morning Sunshine | mare&lt;br /&gt;-&gt; Check box | Goat 3 | goat&lt;br /&gt;-&gt; Check box | Goat 4 | goat&lt;br /&gt;-&gt; Check box | Guicho | gelding&lt;br /&gt;-&gt; Check box | Misty | mare&lt;br /&gt;&lt;br /&gt;'quit' event created with arguments ''&lt;br /&gt;&lt;/blockquote&gt;It is quite explicit that Guicho is marked as booked before he disappears, and not checked when he comes back. Updating the UI map file was very easy - we viewed it in a graphical diff tool, noted the new column for the checkbox and the lack of the list of booked animals were as expected, and clicked "save" in TextTest.&lt;br /&gt;&lt;br /&gt;I only actually had like 5 tests, but updating them to cope with the changed UI was relatively straightforward, and would still have been straightforward even if I had had 600 of them.&lt;br /&gt;&lt;br /&gt;I'm quite pleased the way PyUseCase coped in this case. I really believe that with this tool you will be able to write your tests once, and they will be able to survive many generations of your UI. I think this toy example goes some way to showing how.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-7700432393785994474?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/7700432393785994474/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=7700432393785994474' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/7700432393785994474'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/7700432393785994474'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/12/big-ui-changes-and-their-effect-on.html' title='big UI changes and their effect on tests'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_AkG8Hw7A2Pw/SzkU194jPXI/AAAAAAAAADw/addPUb2ysic/s72-c/gui+with+book+button.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-2847767397350602654</id><published>2009-12-16T19:42:00.006+01:00</published><updated>2009-12-16T21:46:32.394+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='TextTest'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>PyUseCase 3.0</title><content type='html'>Geoff has been working really hard for the past few months, writing &lt;a href="http://texttest.carmen.se/index.php?page=ui_testing&amp;amp;n=pyusecase_download"&gt;pyUseCase 3.0&lt;/a&gt;. It has some very substantial improvements over previous versions, and I am very excited about it. He's written about how it works &lt;a href="http://texttest.carmen.se/index.php?page=ui_testing"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;It's a tool for testing GUIs with a record-replay paradigm, that actually works. Seriously, you can do agile development with these tests, they don't break the minute you change your GUI. The reason for this is that the tests are written in a high level domain language, decoupled from the actual current layout of your GUI. The tool lets you create and maintain a mapping file from the current widgets to the domain language, and helps you to keep it up to date.&lt;br /&gt;&lt;br /&gt;In a way it's a bit like &lt;a href="http://robotframework.org/"&gt;Robot&lt;/a&gt;, or &lt;a href="http://www.thoughtworks-studios.com/agile-test-automation"&gt;Twist&lt;/a&gt;, or &lt;a href="http://cukes.info/"&gt;Cucumber&lt;/a&gt;, that your tests end up being very human readable. The main difference is the record-replay capability. Anyone who can use the application GUI can create a test, which they can run straight away. With these other tools, a programmer typically has to go away and map the user domain language of the test into something that actually executes.&lt;br /&gt;&lt;br /&gt;The other main way in which pyUseCase is different from other tools, is the way it checks your application did the right thing. Instead of the test writer having to choose some aspects of the GUI and make assertions about what they should look like, pyUseCase just records what the whole GUI looks like, in a plain text log. Then you can use TextTest to compare the log you get today with the one you originally recorded when you created the test. The test writer can concentrate on just normal interaction with the GUI, and still have very comprehensive assertions built into the tests they create.&lt;br /&gt;&lt;br /&gt;pyUseCase, together with TextTest, makes it really easy to create automated tests, without writing code, that are straightforward to maintain, and readable by application users. Geoff has been developing his approach to testing for nearly a decade, and I think it is mature enough now, and sufficiently far ahead of the competition, that it is going to transform the way we do agile testing.&lt;br /&gt;&lt;br /&gt;:-D&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-2847767397350602654?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/2847767397350602654/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=2847767397350602654' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/2847767397350602654'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/2847767397350602654'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/12/pyusecase-30.html' title='PyUseCase 3.0'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-718527559582008824</id><published>2009-12-10T20:36:00.003+01:00</published><updated>2009-12-10T22:01:53.099+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='scrum'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Jens Östergaard on Scrum</title><content type='html'>Today I listened to a presentation about "Scrum for Managers" from Jens Östergaard. He's a big, friendly Dane who grew up in Sweden, and now lives in the UK. I first met Jens at XP2003 in Genoa, when he had just run his first successful Scrum project. These days he spends his time flying around the world, teaching Scrum courses and coaching Scrum Masters. (He'll be doing 2 more CSM courses in Göteborg in the next 6 months, and speaking at &lt;a href="http://www.scandevconf.se/"&gt;Scandinavian Developer Conference&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;One thing I noticed about his talk was that most things about Scrum hardly seem to have changed at all. Jens was largely using the same language and examples that are in the original books. The other thing that struck me was that Jens said nothing about the technical practices that are needed to make agile development work. In my world, you can't possibly hope to reliably deliver working software every sprint/iteration if you havn't got basic practices like continuous integration and automated testing in place. I asked Jens about this afterwards, and he said it was deliberate. Scrum is a project management framework that can be applied to virtually any field, not just software development. Therefore he didn't want to talk about software specific practices.&lt;br /&gt;&lt;br /&gt;When I first heard Ken Schwaber talk about Scrum (keynote at XP2002) I'm farily sure he included the XP developer practices. I can't find my notes from that speech, but I remember him being very firey and enthusiastic and encouraging us to go out and convert the world to Scrum &lt;span style="font-style: italic;"&gt;and&lt;/span&gt; XP (the word agile wasn't invented then).&lt;br /&gt;&lt;br /&gt;Scrum has been hugely successful since then. Today we had a room full of project managers and line managers who all knew something about Scrum, many of whom are using it daily in their organizations. Scrum is relatively easy to understand and get going with at the project level, and has this CSM training course that thousands of people have been on. These are not bad things.&lt;br /&gt;&lt;br /&gt;I do think that dropping the XP development practices entirely from the description of Scrum is unhelpful. I chatted with several people who are having difficulty getting Scrum to work in their organizations, and I think lack of developer practices, particularly automated testing, is compounding their problems. I think a talk given to software managers needs to say something about how developers might need coaching and training in new practices if they are going to succeed with Scrum.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-718527559582008824?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/718527559582008824/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=718527559582008824' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/718527559582008824'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/718527559582008824'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/12/jens-ostergaard-on-scrum.html' title='Jens Östergaard on Scrum'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-6142104770071332429</id><published>2009-12-04T19:34:00.005+01:00</published><updated>2009-12-04T21:21:37.649+01:00</updated><title type='text'>Scandinavian Developer Conference 2010</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_AkG8Hw7A2Pw/Sxluz_DRccI/AAAAAAAAADA/FpMrFf_aPCQ/s1600-h/sdc.gif"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 229px; height: 43px;" src="http://4.bp.blogspot.com/_AkG8Hw7A2Pw/Sxluz_DRccI/AAAAAAAAADA/FpMrFf_aPCQ/s320/sdc.gif" alt="" id="BLOGGER_PHOTO_ID_5411478266639905218" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;The &lt;a href="http://www.scandevconf.se/2010/conference/detailed-program/"&gt;programme for Scandinavian Developer Conference&lt;/a&gt; has just been published. I think we have a fantastic line up of speakers this year. I am particularly pleased &lt;a href="http://www.michaelfeathers.com/"&gt;Michael Feathers&lt;/a&gt;, &lt;a href="http://www.exampler.com/blog/"&gt;Brian Marick&lt;/a&gt; and &lt;a href="http://www.agilealliance.org/show/1879"&gt;Diana Larsen &lt;/a&gt;have agreed to join us, and that this year my husband Geoff is also a speaker.&lt;br /&gt;&lt;br /&gt;I have met Michael and Diana at many XP conferences over the years, but I missed Brian Marick the one time I was at the agile conference in North America, so I'm particularly interested to hear what he has to say. He has been very influential in the testing community, and invented the idea of &lt;a href="http://www.exampler.com/old-blog/2003/08/21/#agile-testing-project-1"&gt;testing quadrants&lt;/a&gt;, which I think is a very helpful way of thinking about testing.&lt;br /&gt;&lt;br /&gt;Michael Feathers is known for his book "Working Effectively with Legacy Code", which I reviewed early drafts of back in like 2004. He and I also competed together in &lt;a href="http://emilybache.blogspot.com/2008/08/geek-meets-idol.html"&gt;"Programming with the Stars"&lt;/a&gt; at agile2008. Michael works for Object Mentor, coaching teams in all things agile.&lt;br /&gt;&lt;br /&gt;Diana Larsen is chairman of the agile alliance, and has written a book about retrospectives together with Esther Derby. I think I first met her at XP2005, when I attended her tutorial, which I remember as outstanding. It was very interactive and all about communication skills and teambuilding. Her job seems to be all about teaching the people skills needed for agile to work.&lt;br /&gt;&lt;br /&gt;Geoff is going to be talking about&lt;a href="http://texttest.org/"&gt; texttest&lt;/a&gt;, which goes from strength to strength, and productive GUI testing with &lt;a href="https://launchpad.net/pyusecase"&gt;pyUseCase.&lt;/a&gt; Geoff has been doing an awful lot of work on this tool lately, and I am really excited about the possibilities it opens up for agile testing. I will have to write a separate post on that though, so watch this space :-)&lt;br /&gt;&lt;br /&gt;Many of the other speakers are familiar faces who I look forward to meeting up with again - &lt;a href="http://www.java.net/blogs/wwake"&gt;Bill Wake&lt;/a&gt;, (books about refactoring, XP and Ruby), Erik Lundh, (the earliest Swedish XP coach), &lt;a href="http://niclasnilsson.se/"&gt;Niclas Nilsson&lt;/a&gt; (ruby, programming guru),&lt;a href="http://jimmynilsson.com/blog/"&gt; Jimmy Nilsson&lt;/a&gt; (Domain Driven Design book), &lt;a href="http://memeagora.blogspot.com/"&gt;Neal Ford&lt;/a&gt; (Thoughtworks, productive programmer book), &lt;a href="http://www.responsive.se/thomas/"&gt;Thomas Nilsson&lt;/a&gt;, (CTO, Responsive, linköping), &lt;a href="http://ellnestam.wordpress.com/"&gt;Ola Ellnestam&lt;/a&gt; (CEO, Agical, stockholm), &lt;a href="http://marcus.ahnve.net/"&gt;Marcus Ahnve&lt;/a&gt; (programming guru), &lt;a href="http://www.hedgate.net/"&gt;Chris Hedgate&lt;/a&gt; (programming guru)...&lt;br /&gt;&lt;br /&gt;I'm also very pleased that I'm going to be speaking again this year, after the success of my previous presentation on "&lt;a href="http://emilybache.blogspot.com/2008/10/booked-for-sdc2009.html"&gt;clean code&lt;/a&gt;". This year I hope to talk about agile testing and how best to approach it.&lt;br /&gt;&lt;br /&gt;One of the reasons I keep going back to the &lt;a href="http://xp2010.org/"&gt;XP conference&lt;/a&gt; is the amount of interaction and discussion generated by the many workshops and open space sessions. There are very few straight talks, and all are either presentations of academic papers, or keynotes. When I saw the proposed programme for SDC a couple of weeks ago, I felt it was lacking something. Eight parallel tracks of presentations is all very well, but where is the interaction, the whole reason to go to a conference and not just watch presentations on infoq? So I proposed a ninth "track", devoted to discussion, called "&lt;a href="http://www.scandevconf.se/2010/conference/tracks/#disussions"&gt;conversation corner&lt;/a&gt;". Luckily my colleagues at &lt;a href="http://iptor.com/"&gt;iptor, &lt;/a&gt;who are organizing the conference, liked my idea.&lt;br /&gt;&lt;br /&gt;To get the conversations going, I am organizing four "&lt;a href="http://en.wikipedia.org/wiki/Fishbowl_%28conversation%29"&gt;fishbowl&lt;/a&gt;" style discussions, seeded by conference speakers. I've picked topics that interest me, and invited other conference speakers, who I think are also interested in these topics, to join me.&lt;br /&gt;&lt;br /&gt;I am hoping that after participating in one or two of my fishbowls, some conference attendees might feel comfortable proposing discussions of their own. To that end there will be a board with timeslots and index cards, so people can write up their topic, assign it to an empty timeslot, and hence invite more people to join them.&lt;br /&gt;&lt;br /&gt;It won't be full blown open space, there will be no opening meeting with everyone, or two minute pitches proposing sessions. I won't be explaining the law of two feet or the open space rules. But it is a step in that direction, and I hope a complement to the organized speeches going on in the rest of the conference.&lt;br /&gt;&lt;br /&gt;Perhaps you'd like to join us at the conference? Register &lt;a href="http://www.scandevconf.se/2010/registration/"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-6142104770071332429?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/6142104770071332429/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=6142104770071332429' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/6142104770071332429'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/6142104770071332429'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/12/scandinavian-developer-conference-2010.html' title='Scandinavian Developer Conference 2010'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/Sxluz_DRccI/AAAAAAAAADA/FpMrFf_aPCQ/s72-c/sdc.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-279597829934226084</id><published>2009-11-26T20:43:00.003+01:00</published><updated>2009-11-26T20:55:50.142+01:00</updated><title type='text'>Iptor</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_AkG8Hw7A2Pw/Sw7cYHyCzlI/AAAAAAAAAC4/WLd4KDHp4sc/s1600/300px-Iptor.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 300px; height: 142px;" src="http://3.bp.blogspot.com/_AkG8Hw7A2Pw/Sw7cYHyCzlI/AAAAAAAAAC4/WLd4KDHp4sc/s320/300px-Iptor.jpg" alt="" id="BLOGGER_PHOTO_ID_5408502509482462802" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;It occurred to me that I should mention that I now work for&lt;a href="http://iptor.com/"&gt; Iptor Konsult AB&lt;/a&gt; rather than IBS JavaSolutions. This is not due to my changing jobs, rather that IBS decided that since we don't do the same things as the rest of the company, we should have a separate name and image. We are even going to be a separate legal entity, although still wholly owned by IBS.&lt;br /&gt;&lt;br /&gt;I think it's a very positive development for both parties, and I personally am much more comfortable standing up and presenting myself as from Iptor than I ever was when it was IBS JavaSolutions. For a start it's not also the name of a rather unpleasant illness, and secondly it means I can avoid mentioning Java. A language I now work with daily, but don't enjoy nearly so much as python.&lt;br /&gt;&lt;br /&gt;In practice though, the name change probably won't make that much difference in my daily life.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-279597829934226084?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/279597829934226084/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=279597829934226084' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/279597829934226084'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/279597829934226084'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/11/iptor.html' title='Iptor'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_AkG8Hw7A2Pw/Sw7cYHyCzlI/AAAAAAAAAC4/WLd4KDHp4sc/s72-c/300px-Iptor.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-5505369713105102476</id><published>2009-11-26T19:43:00.005+01:00</published><updated>2009-12-13T20:28:27.833+01:00</updated><title type='text'>TextTest progress</title><content type='html'>When I wrote &lt;a href="http://emilybache.blogspot.com/2009/08/testing-texttest.html"&gt;this post&lt;/a&gt; about the public Texttest &lt;a href="http://texttest.carmen.se/index.php?page=nightjob"&gt;nightjob statistics&lt;/a&gt;, I thought they were a bit confusing and hard to understand. Geoff has now rewritten the page to contain fewer numbers, and just report the passed and failed tests from the previous night. I think it's a bit easier to read now. He has also ditched about 500 tests that were running on Solaris, since that platform is not used often, and these tests never found bugs that weren't also found on Linux.&lt;br /&gt;&lt;br /&gt;The statistics are still pretty impressive though, don't you think?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-5505369713105102476?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/5505369713105102476/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=5505369713105102476' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/5505369713105102476'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/5505369713105102476'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/11/texttest-progress.html' title='TextTest progress'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-1133316598459423579</id><published>2009-11-22T21:10:00.006+01:00</published><updated>2009-11-22T22:04:58.588+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='TextTest'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>TestNG - my opinions</title><content type='html'>It's &lt;a href="http://www.javaforum.se/jf/index.jsp?meeting=54"&gt;Java Forum&lt;/a&gt; next week, here in Göteborg. I'm giving a short talk about &lt;a href="http://testng.org/doc/index.html"&gt;TestNG&lt;/a&gt;, a tool I've been using lately.&lt;br /&gt;&lt;br /&gt;My basic conclusion is that TestNG is a very easy step from &lt;a href="http://www.junit.org/"&gt;JUnit&lt;/a&gt;, and one you don't need to take if all your tests are true unit tests (ie fast and independant). TestNG has some nice features which help when your tests are slow and/or have external dependencies, especially if they are mixed together in the same test classes as true unit tests. I think it's pretty useful for unit and integration tests. (aka quadrant 1, technology facing).&lt;br /&gt;&lt;br /&gt;Having said that, what bothers me about TestNG is that it means your test code is written in Java. For me, that makes it unsuitable for for system tests, (aka quadrant 2, business facing). If you have anything resembling an involved customer, you're going to at least want to encourage them to read the system tests to verify they are correct, and to gain confidence that the system is working.  Truly agile teams have these people helping write tests. Many customer types won't be happy working with Java. You might be able to get by, though, if you have descriptive test names, good javadoc,  and test data in separate files that they can read.&lt;br /&gt;&lt;br /&gt;Rather than spending time learning TestNG, I think you may get more payback from tools such as &lt;a href="http://www.fitnesse.org/"&gt;Fitnesse&lt;/a&gt;, &lt;a href="http://code.google.com/p/robotframework/"&gt;Robot&lt;/a&gt; or &lt;a href="http://texttest.org/"&gt;TextTest&lt;/a&gt;, which all allow you to get customers involved in reading and even writing tests. I think it could be a perfectly sensible choice to stick with JUnit for unit tests, and use one of these tools for both integration and system tests. What you choose will of course depends on the situation, for example the size of the system, the nature of the test data, and how many tools your team is willing to learn.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-1133316598459423579?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/1133316598459423579/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=1133316598459423579' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/1133316598459423579'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/1133316598459423579'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/11/testng-my-opinions.html' title='TestNG - my opinions'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-2139477711005534074</id><published>2009-11-18T21:50:00.005+01:00</published><updated>2009-11-18T22:20:57.687+01:00</updated><title type='text'>Video of "Varför går man till en Coding Dojo?"</title><content type='html'>I spoke at &lt;a href="http://smidig2009.no/"&gt;Smidig2009&lt;/a&gt; about a month ago, and they have now put up &lt;a href="http://tcs.java.no/tcs/"&gt;videos of all the talks&lt;/a&gt;. So I just had the uncanny experience of watching myself speak (&lt;a href="http://tcs.java.no/tcs/?id=13689934-3E4D-4DDF-87EE-9C9D1BD2B276"&gt;here is a link to it&lt;/a&gt;). I'm sure my swedish accent sounds better in my head when I'm talking, but I do apparently get my point across, since about a dozen people turned up to do a code kata with me in the open space in the afternoon.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-2139477711005534074?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/2139477711005534074/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=2139477711005534074' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/2139477711005534074'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/2139477711005534074'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/11/video-of-varfor-gar-man-till-en-coding.html' title='Video of &quot;Varför går man till en Coding Dojo?&quot;'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-8343179643050389407</id><published>2009-11-01T20:52:00.002+01:00</published><updated>2009-11-01T20:57:21.095+01:00</updated><title type='text'>JFokus</title><content type='html'>I've just heard that I've been accepted as a speaker at &lt;a href="http://www.jfokus.se/jfokus/speakers.jsp"&gt;JFokus&lt;/a&gt;, in Stockholm in January. I'll be saying something about how to write good tests using &lt;a href="http://seleniumhq.org/"&gt;Selenium&lt;/a&gt;, a tool I've been using a fair amount lately. I'm looking forward to the chance to meet up with the wider Java community in Sweden and find out what's new and what's hot.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-8343179643050389407?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/8343179643050389407/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=8343179643050389407' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8343179643050389407'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8343179643050389407'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/11/jfokus.html' title='JFokus'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-3325485428235402163</id><published>2009-10-19T20:56:00.002+02:00</published><updated>2009-10-19T21:27:32.876+02:00</updated><title type='text'>Smidig 2009</title><content type='html'>I'm off to Oslo on Wednesday for &lt;a href="http://smidig2009.no/"&gt;Smidig 2009.&lt;/a&gt; They've just announced the &lt;a href="http://smidig2009.no/program"&gt;programme&lt;/a&gt;, which consists of lightning talks in the morning, and open space in the afternoons. I'll be giving a lightning talk on Friday morning about &lt;a href="http://smidig2009.no/talks/28"&gt;why you might want to go to a coding dojo&lt;/a&gt;. I'm hoping there will be enough interest to run a Randori/dojo in the afternoon. Someone commented that there have been dojo meetings in Oslo before, so I'll be interested to find out if they do them the same way I've been doing them.&lt;br /&gt;&lt;br /&gt;The conference talks are mostly going to be in Norwegian, but mine isn't the only item in Swedish. I spotted Ola Ellnestam (&lt;a href="http://agical.se/"&gt;agical&lt;/a&gt;) and Thomas Nilsson (&lt;a href="http://responsive.se/"&gt;responsive&lt;/a&gt;) on the list too. So if it turns out that I find spoken Norwegian totally incomprehensible, there will be a few people I can talk to!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-3325485428235402163?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/3325485428235402163/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=3325485428235402163' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/3325485428235402163'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/3325485428235402163'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/10/smidig-2009.html' title='Smidig 2009'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-8758658150841152168</id><published>2009-10-18T22:07:00.001+02:00</published><updated>2009-10-18T22:07:54.969+02:00</updated><title type='text'>JUnit and TestNG</title><content type='html'>I wrote&lt;a href="http://jsolutions.se/?p=1495"&gt; a blog post&lt;/a&gt; about these tools on my company blog. In swedish.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-8758658150841152168?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/8758658150841152168/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=8758658150841152168' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8758658150841152168'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8758658150841152168'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/10/junit-and-testng.html' title='JUnit and TestNG'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-7995488292528303414</id><published>2009-10-02T20:32:00.006+02:00</published><updated>2009-10-02T21:44:35.125+02:00</updated><title type='text'>testing through the GUI costs less with the right tools</title><content type='html'>Bob Martin has just written a post in his &lt;a href="http://blog.objectmentor.com/articles/2009/09/29/ruining-your-test-automation-strategy"&gt;blog&lt;/a&gt; where he tells the story of a test manager who has 80 000 manual tests, and wishes they were automated instead. Bob writes:&lt;br /&gt;&lt;br /&gt;"One common strategy to get your tests automated is to outsource the problem. You hire some team of test writers to transform your manual tests into automated tests using some automation tool. These folks execute the manual test plan while setting up the automation tool to record their actions. Then the tool can simply play the actions back for each new release of the system; and make sure the screens don’t change."&lt;br /&gt;&lt;br /&gt;Bob then goes on to explain why this is such a terrible idea - and blames it all on coupling. That the tests and the GUI are coupled to the extent that when you change the GUI, loads of tests break. Wheras humans can handle a fair amount of GUI changes and still correctly determine whether a manual test should pass or fail, machines fall over all too easily and just fail as soon as something unexpected happens. So you end up re-recording them, which can cost as much as just doing the tests manually in the first place.&lt;br /&gt;&lt;br /&gt;These problems are of course bigger or smaller depending on the GUI automation tool you choose. Anything that records pixel positions will fall over when you simply change the screen resolution, let alone when you add new buttons and features in your GUI. More modern tools record the names or ids of the widgets, so they don't break if the widget simply moves to another part of the screen. In other words, you reduce your coupling.&lt;br /&gt;&lt;br /&gt;Geoff has been working on &lt;a href="http://texttest.carmen.se/index.php?page=concepts&amp;amp;n=xusecase"&gt;PyUseCase&lt;/a&gt; which takes this to another level. Instead of coupling the tests to widget names, you couple them to "domain actions". This makes your tests even more robust in the face of gui changes. A drop down list can turn into a set of radio buttons and your tests won't mind, since they just say something like "select airport SFO". This doesn't isolate you from the big changes, like moving the order of the screens in a wizard around, but since the tests are written in plain text, in a language any domain expert can read, they are relatively cheap to update.&lt;br /&gt;&lt;br /&gt;There is another respect in which machines under-perform compared to manual testers. An intelligent human will usually do a certain amount of exploration beyond the scripted test steps they have infront of them. They try to understand the purpose of the test, click around a bit and ask questions when parts of the system peripheral to the test in hand start to look odd. Machines don't do any exploration, and in fact often don't even notice errors on parts of the screen they havn't been told to look at.&lt;br /&gt;&lt;br /&gt;Geoff's PyUseCase can partly address this kind of a problem. Used together with &lt;a href="http://texttest.org"&gt;TextTest&lt;/a&gt;, it will continually scan the log the System Under Test produces, and fail the test for example if any stack traces appear. PyUseCase also automatically produces a low fidelity ascii-art-esque log of how the current screen looks, and can compare it against what it looked like last time the test ran. Changes are flagged as test failures, which will bring to your attention the change in an unrelated corner of the screen which says "32nd December" instead of "1st January".&lt;br /&gt;&lt;br /&gt;I know that sounds like we just introduced a huge amount of coupling between the tests and the way the GUI looks, and yes, we have. The difference is that this coupling is very easy to manage. If 1000 tests all fail saying "expected: 1st January, found: January 1st", TextTest handily groups all the test failures and lets you accept or reject the change en-masse. So it is very little work to update a lot of tests when the GUI just looks different, but you don't care.&lt;br /&gt;&lt;br /&gt;There is still a problem though, that the machine will not explore outside of the scripted steps you tell it to perform. So you will have to do some manual exploratory testing too, not everything can be automated.&lt;br /&gt;&lt;br /&gt;So a simplistic lets-just-automate-our-manual-tests is a bad idea because machines can't handle GUI changes as well as humans can, and because machines don't look around and explore. Potentially your automated tests will cost more than your manual tests, and find fewer bugs.&lt;br /&gt;&lt;br /&gt;So should we stick with our manual test suite then? No, of course not. The value of automated tests is not simply that you can run them more cheaply than manual tests, it is that you can run them more often - at every build, constantly supplying developers with valuable feedback rather than just at the end of the release cycle. It is this kind of feedback that enables refactoring, and lets developers build quality code from the start. That is their real gain over manual tests.&lt;br /&gt;&lt;br /&gt;Bob Martin's suggestion is that you shouldn't rely on expensive GUI tests for this kind of feedback - only perhaps 15% of your tests should be GUI reliant. The rest run against some kind of api, which is less volatile and hence cheaper to maintain. With the kinds of tools Bob I suspect has been using for GUI testing I'm not surprised he says this. I just think that with tools like PyUseCase and TextTest the costs are much reduced, and call for reconsideration of this ratio. Looking at Geoff's self tests for TextTest (a GUI intensive tool), around half are testing through the GUI, using pyUseCase. Basically I don't think GUI tests have to be as bad and expensive as Bob makes out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-7995488292528303414?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/7995488292528303414/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=7995488292528303414' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/7995488292528303414'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/7995488292528303414'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/10/testing-through-gui-costs-less-with.html' title='testing through the GUI costs less with the right tools'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-7749302338709414287</id><published>2009-09-03T20:02:00.003+02:00</published><updated>2009-09-03T20:47:57.040+02:00</updated><title type='text'>First JDojo@Gbg meeting</title><content type='html'>A little while ago we had the first meeting of our new &lt;a href="http://codingdojo.org"&gt;coding dojo&lt;/a&gt; here in Göteborg. We are focussing on learning Test Driven Development using &lt;a href="http://www.java.com"&gt;Java&lt;/a&gt; and &lt;a href="http://www.eclipse.org"&gt;Eclipse&lt;/a&gt;. I was very encouraged that two of my colleagues, Fredrik and Martin, volunteered to help organize the group.  There was actually quite a lot of interest generally, and we filled all 12 places and even have a (small) waiting list. I didn't want the group to grow too big, since the dojo style of learning should be quite participatory, and the time slot is only 2 hours. Everyone should get a chance to be heard, and to take the keyboard.&lt;br /&gt;&lt;br /&gt;At the meeting I introduced the dojo concept with a set of &lt;a href="http://wiki.europython.eu/TutorialHandouts?action=AttachFile&amp;do=get&amp;target=coders_dojo.zip"&gt;slides&lt;/a&gt; I have used before. At dojo meetings our focus should be on deliberate practice, aquiring good coding habits, mutual encouragement and feedback.&lt;br /&gt;&lt;br /&gt;We then took on &lt;a href="http://codingdojo.org/cgi-bin/wiki.pl?KataFizzBuzz"&gt;KataFizzBuzz&lt;/a&gt; which went very smoothly. I started by introducing the Kata, using this picture of the "teacher" pointing at you, asking you to say the next number in the FizzBuzz sequence. She is sufficiently scary looking that you definitely need to write a program to print a FizzBuzz cheat sheet before the next lesson!&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_AkG8Hw7A2Pw/SqAL0El4fQI/AAAAAAAAACw/5mijcbVVzGY/s1600-h/angry-teacher-pointing.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 213px;" src="http://3.bp.blogspot.com/_AkG8Hw7A2Pw/SqAL0El4fQI/AAAAAAAAACw/5mijcbVVzGY/s320/angry-teacher-pointing.jpg" alt="" id="BLOGGER_PHOTO_ID_5377310944294108418" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;I also introduced something I havn't done before at a dojo meeting - starting with some code rather than a blank editor. I had the acceptance test for the Kata already coded up and failing. When I practiced this Kata I realized the hardest part was writing the acceptance test, which captures the sequence that is written to System.out. I could have begun the meeting by written it in front of the audience, but I really wanted to get them coding, not just watching me.&lt;br /&gt;&lt;br /&gt;Martin wrote the first unit test, fizzbuzz(1) -&gt; [1] and I noticed that his style is slightly different from mine. He fixed all the compiler errors as he went along, whereas I would tend to leave them all until I finish the test, or at least until I want to run it. Maybe that is because he has worked in Java/Eclipse longer than me, and that is the way Eclipse likes you to work. Anyway, I then implemented the code to make the test pass (fake it!) and wrote the next test fizzbuzz(2) -&gt; [1,2]. So then he had to write just enough code to make it pass (a simple loop).&lt;br /&gt;&lt;br /&gt;Then we handed the keyboard to two members of the audience, and Martin and I sat down in their chairs, and the Randori was really underway. We continued with this pair and two others using this ping-pong style until after about an hour we had completed the first part of the Kata - printing out the basic fizzbuzz sequence up to 100.&lt;br /&gt;&lt;br /&gt;I suggested that the pair at the front try to run the acceptance test, which they did, and it failed. The reason was that the unit tests had been testing an internal method fizzbuzz() and the acceptance test checked that when you call main() you get the right sequence written to System.out. It was at this point I wondered if I had made the right decision when I wrote the acceptance test in advance, since that meant the guy at the keyboard clearly didn't really understand what it was for. His first thought of how to make it pass was to change it to call fizzbuzz() instead of main(), until I stopped him - "No! don't change the test! Fix the code!". I felt like I was rapping him over the knuckles with a ruler (something I am thankful my Maths teacher never did).&lt;br /&gt;&lt;br /&gt;Towards the end of the meeting so we held a 10 minute retrospective. People seemed cautiously positive towards TDD and the dojo in general, but I think they maybe still getting used to the format and working out whether it is "ok" to be openly critical. I hope for more dissent, discussion and group learning next time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-7749302338709414287?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/7749302338709414287/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=7749302338709414287' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/7749302338709414287'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/7749302338709414287'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/09/first-jdojogbg-meeting.html' title='First JDojo@Gbg meeting'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_AkG8Hw7A2Pw/SqAL0El4fQI/AAAAAAAAACw/5mijcbVVzGY/s72-c/angry-teacher-pointing.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-187648542818382445</id><published>2009-08-28T19:57:00.004+02:00</published><updated>2009-08-28T21:09:52.269+02:00</updated><title type='text'>Testing TextTest</title><content type='html'>Geoff has just put up a couple of new pages on the texttest website, with some &lt;a href="http://texttest.carmen.se/nightjob/coverage/index.html"&gt;coverage statistics &lt;/a&gt;for his self tests. He uses &lt;a href="http://nedbatchelder.com/code/coverage/"&gt;coverage.py&lt;/a&gt; to produce this report which shows all the python modules in texttest, and marks covered statements in green. I think it's pretty impressive - he's claiming over 98% statement coverage for the over 17 000 lines of python code in texttest.&lt;br /&gt;&lt;br /&gt;I had a poke around looking for some numbers to compare this to, and found on&lt;a href="http://www.c2.com/cgi/wiki?TddCodeCoverage"&gt; this page&lt;/a&gt; someone claiming &lt;a href="http://fitnesse.org"&gt;Fitnesse&lt;/a&gt; has 94% statement coverage from its unit tests, and the &lt;a href="http://www.springsource.org/"&gt;Java Spring framework&lt;/a&gt; has 75% coverage. It's probably unwise to compare figures for different programming languages directly, but it gives you an idea.&lt;br /&gt;&lt;br /&gt;Geoff also publishes the results of his nightly run of self tests &lt;a href="http://texttest.carmen.se/nightjob/texttest/test_default.html"&gt;here&lt;/a&gt;. It looks a bit complicated, but Geoff explained it to me. :-) He's got nearly 2000 tests testing texttest on unix, and about 900 testing it on windows. As you can see, the tests don't always pass, some are annoying ones that fail sporadically, some are due to actual bugs, which then get fixed. So even though he rarely has a totally green build, the project looks healthy overall, with new tests and fixes being added all the time.&lt;br /&gt;&lt;br /&gt;Out of those 3000 odd tests that get run every night, Geoff has a core of about 1000 that he will run before every significant check-in. Since they run in parallel on a grid, they usually take about 2 minutes to execute. (When he has to run them at home in series on our fairly low spec linux laptop they take about half an hour.)&lt;br /&gt;&lt;br /&gt;Note that we aren't talking about unit tests here, these are high level acceptance tests, running the whole texttest system. About half of them use &lt;a href="https://launchpad.net/pyusecase"&gt;PyUseCase&lt;/a&gt; to simulate user actions in the texttest GUI, the rest interact with the command line interface. Many of the tests use automatically generated test doubles to simulate interaction with 3rd party systems like version control, grid engines, diff programs etc.&lt;br /&gt;&lt;br /&gt;Pretty impressive, don't you think? Well I'm impressed. But then I am married to him so I'm not entirely unbiased :-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-187648542818382445?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/187648542818382445/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=187648542818382445' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/187648542818382445'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/187648542818382445'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/08/testing-texttest.html' title='Testing TextTest'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-5421338893196775815</id><published>2009-08-17T20:44:00.004+02:00</published><updated>2009-08-17T21:26:44.145+02:00</updated><title type='text'>Domain Specific Languages for Selenium tests</title><content type='html'>I've been doing some work lately creating automated functional test suites using Selenium RC to simulate user interaction with a web GUI. I discovered quickly that the tests you record directly from selenium are rather brittle, and hard to read. In order to make the tests more robust and readable, I have been extracting reusable chunks of script that make sense from the user perspective, into separate methods. For example when testing a page for registering a new provider, you might have a ProviderPage domain class, with method "createNewProvider". This method encapsulates all the selenium calls that interact with the page, and lets your test be written in terms of the domain.&lt;br /&gt;&lt;br /&gt;I just saw &lt;a href="http://patrickwilsonwelsh.com/?p=47"&gt;this article&lt;/a&gt; from Patrick Wilson Welsh basically saying the same thing, only his DSL has three layers of indirection instead of just two. As well as encapsulating page operations in a Page class, he encapsulates operations on widgets within a page. I hadn't thought of doing that. It makes the code in the Page class more readable. I might try that, and see if it improves my code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-5421338893196775815?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/5421338893196775815/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=5421338893196775815' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/5421338893196775815'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/5421338893196775815'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/08/ive-been-doing-some-work-lately.html' title='Domain Specific Languages for Selenium tests'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-3489211814265300405</id><published>2009-08-05T21:03:00.003+02:00</published><updated>2009-08-05T21:31:51.148+02:00</updated><title type='text'>What other people have written about new dojos</title><content type='html'>Gathering ideas for my new dojo :-)&lt;br /&gt;&lt;br /&gt;Ivan Sanchez wrote about &lt;a href="http://isanchez.net/2008/08/31/starting-a-coding-dojo/"&gt;starting a coding dojo&lt;/a&gt;, and he rekons a Randori is best with 10 people or less. We will be more than 10 at JDojo@gbg. He suggests a prepared kata in that case. That might be possible. His favourite starting kata is &lt;a href="http://codingdojo.org/cgi-bin/wiki.pl?KataMinesweeper"&gt;KataMinesweeper&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Danilo Sato wrote about &lt;a href="http://www.dtsato.com/blog/2008/10/21/source-of-problems-for-your-coding-dojo/"&gt;how to find suitable Katas&lt;/a&gt;, and suggests several for beginning dojos, including &lt;a href="http://codingdojo.org/cgi-bin/wiki.pl?KataMinesweeper"&gt;Ka&lt;/a&gt;&lt;a href="http://codingdojo.org/cgi-bin/wiki.pl?KataMinesweeper"&gt;taMinesweeper&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Gary Pollice wrote an article about &lt;a href="http://web.cs.wpi.edu/%7Egpollice/Dojo.html"&gt;what a coding dojo is&lt;/a&gt;, which is quite well explained, but doesn't give any specific advice for new dojos.&lt;br /&gt;&lt;br /&gt;The guys running the finnish dojo have a &lt;a href="http://wiki.agilefinland.com/?CodingDojo"&gt;similar article&lt;/a&gt; about what a coding dojo is, and some rules. They put a maximum of 15 participants on their randori. They also introduce "iterations" of 30 minutes, and spend 5 minutes planning in between.&lt;br /&gt;&lt;br /&gt;Lots of ideas to think about, anway.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-3489211814265300405?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/3489211814265300405/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=3489211814265300405' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/3489211814265300405'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/3489211814265300405'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/08/gathering-ideas-for-my-new-dojo-ivan.html' title='What other people have written about new dojos'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-4442646719186744751</id><published>2009-08-03T19:59:00.003+02:00</published><updated>2009-08-03T20:17:18.406+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Code Kata'/><category scheme='http://www.blogger.com/atom/ns#' term='Coding Dojo'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>a new dojo - JDojo@Gbg</title><content type='html'>I'm planning to start a new dojo this autumn, called &lt;a href="http://jsolutions.se/?page_id=1216"&gt;JDojo@Gbg&lt;/a&gt;. I was inspired by the guys at &lt;a href="http://responsive.se/"&gt;Responsive&lt;/a&gt; in Linköping, who I met at &lt;a href="http://jsolutions.se/?p=1142"&gt;XP2009.&lt;/a&gt; They have been running a &lt;a href="http://www.responsive.se/index.php?option=com_content&amp;amp;task=view&amp;amp;id=39&amp;amp;Itemid=72"&gt;dojo&lt;/a&gt; for some time now, and find it is an excellent way to introduce programmers from their clients to the ideas of Test Driven Development. I think we could do with more test infected programmers about the place in Göteborg, too.&lt;br /&gt;&lt;br /&gt;I already run a dojo as part of &lt;a href="http://groups.google.com/group/gothpy"&gt;GothPy&lt;/a&gt;, and &lt;a href="http://gotrb.org/about/"&gt;Got.rb&lt;/a&gt; also runs regular Kata/dojo evenings, but because those programming languages are not mainstream, many developers wouldn't consider coming along. That is why the new dojo is explicitly going to use Java, or at least, the JVM platform.&lt;br /&gt;&lt;br /&gt;I'm thinking about what Katas we are going to tackle at the new dojo, and last night I had a go at &lt;a href="http://codingdojo.org/cgi-bin/wiki.pl?KataFizzBuzz"&gt;KataFizzBuzz&lt;/a&gt; in Java. It is an extremely simple problem to solve, and initially I thought it was too easy to be a Kata actually. Then at agile2008 I was looking around for a Kata that Michael Feathers and I could perform in 4 minutes for the &lt;a href="http://emilybache.blogspot.com/2008/08/onwards-with-stars.html"&gt;"Programming with the Stars"&lt;/a&gt; competition, and it seemed to fit the bill. I was quite pleased we got done in that short amount of time (in python of course :-)&lt;br /&gt;&lt;br /&gt;A couple of people have commented that this Kata is actually quite good for teaching TDD, just because it is so simple to solve. People are forced to think about TDD instead of the problem. It can easily be made more interesting by adding new requirements too. So I think I might try it out at JDojo@Gbg.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-4442646719186744751?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/4442646719186744751/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=4442646719186744751' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/4442646719186744751'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/4442646719186744751'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/08/new-dojo-jdojogbg.html' title='a new dojo - JDojo@Gbg'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-764927994814039129</id><published>2009-07-04T10:33:00.001+02:00</published><updated>2009-07-04T10:35:10.247+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Code Kata'/><category scheme='http://www.blogger.com/atom/ns#' term='TextTest'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>europython</title><content type='html'>I just wrote a report about europython &lt;a href="http://jsolutions.se/?p=1264"&gt;on my company blog&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-764927994814039129?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/764927994814039129/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=764927994814039129' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/764927994814039129'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/764927994814039129'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/07/europython.html' title='europython'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-2202566413858500218</id><published>2009-07-02T11:29:00.001+02:00</published><updated>2009-07-02T11:35:35.053+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>Programming, History and Bletchley Park</title><content type='html'>Today at &lt;a href="http://www.europython.eu/"&gt;europython&lt;/a&gt; we listened to a keynote about &lt;a href="http://www.bletchleypark.org.uk/"&gt;Bletchley Park&lt;/a&gt;. This was the centre of British and allied codebreaking activities during the second world war, and where the first digital, programmable computer was built, Colossus. We heard about the current financial plight of the museum there, and the need for investment to renovate the huts that amongst others Alan Turing worked in. &lt;a href="http://www.savingbletchleypark.org/"&gt;Dr Sue Black&lt;/a&gt; told us about her experiences trying to help lobby the government for more money for Bletchley park, using social networking, blogs and twitter. She recounted that she had recently met an elderly gentleman, one of the surviving codebreakers. She told us how close she felt to history when he related a story about when he was decoding a nazi message during the war, and his shock when he got to the end and discovered the message was signed “Adolf Hitler, Fuhrer”.&lt;br /&gt;&lt;p&gt;&lt;/p&gt; As a professional programmer, I think the site where the first digitally programmable computer was built has to be a place worth preserving. I hope that people will be able to visit there and see the reconstructed Colossus computer and be inspired by the stories of innovation and codebreaking that it enabled.&lt;br /&gt;&lt;p&gt;&lt;/p&gt; It was particuarly poignant for me to think about this when in the next session I checked my email and found a message from my mother saying that my grandmother died this morning. She was a living link to the history of the second world war for me. During the war she was a wireless operator, transmitting and receiving messages in morse code. And now she is not there any more. I am kind of in shock. But it just confirms for me that we need museums like the one at Bletchley Park to retain contact with our history.&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;p lang="en-GB"&gt;(I wrote this post yesterday)&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-2202566413858500218?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/2202566413858500218/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=2202566413858500218' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/2202566413858500218'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/2202566413858500218'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/07/programming-history-and-bletchley-park.html' title='Programming, History and Bletchley Park'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-6177550495686104565</id><published>2009-06-03T22:15:00.002+02:00</published><updated>2009-06-03T22:17:48.490+02:00</updated><title type='text'>XP2009</title><content type='html'>I had a fantastic time at XP2009 in Sardinia, but I didn't find time to blog much about it until now. I just wrote a report of my TDD workshop on&lt;a href="http://jsolutions.se/?p=1142"&gt;&lt;span style="text-decoration: underline;"&gt; jsolutions.se&lt;/span&gt;&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-6177550495686104565?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/6177550495686104565/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=6177550495686104565' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/6177550495686104565'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/6177550495686104565'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/06/xp2009.html' title='XP2009'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-1586262851137973624</id><published>2009-05-25T12:32:00.002+02:00</published><updated>2009-05-25T12:36:57.825+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='lean'/><category scheme='http://www.blogger.com/atom/ns#' term='xp2009'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>Lean with lego</title><content type='html'>I'm at XP2009 this week, the sun is shining, the sea is blue and the italians are disorganized. I'm having a great time so far. This morning I was at a workshop led by Danilo Sato and Francisco Trindade - 'The lego lean game'. The idea was that we should learn about lean principles by playing with lego. I thought it was good fun, and we did learn quite a bit about pull, kanban and continuous improvement. I hope I will be able to run this simulation for some of my colleagues, I think it is a good practical way of learning using all the senses, not just reading books or listening to presentations. Much more kinesthetic.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-1586262851137973624?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/1586262851137973624/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=1586262851137973624' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/1586262851137973624'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/1586262851137973624'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/05/lean-with-lego.html' title='Lean with lego'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-4975111396374855744</id><published>2009-05-13T20:46:00.003+02:00</published><updated>2009-05-13T21:00:39.712+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>caffeine, the science and the propaganda</title><content type='html'>I usually follow the news in the agile world on &lt;a href="http://www.infoq.com/"&gt;infoq&lt;/a&gt;, and I like the feature whereby you can listen to selected conference presentations online. This week I was making some biscuits one evening, so I took the chance to listen to &lt;a href="http://www.infoq.com/presentations/agility-personal-level-possibilities"&gt;Linda Rising talking about "agility: possibilities at a personal level"&lt;/a&gt;. I have to say I was rather disappointed. I think her material was not that relevant to agile in the first place, many of her claims lacked credibility, and although the talk was superficially entertaining, it did not supply useful insights or conclusions. This provoked me into leaving a &lt;a href="http://www.infoq.com/presentations/agility-personal-level-possibilities#view_42417"&gt;comment&lt;/a&gt; on the infoq site. I wonder if anyone will notice.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-4975111396374855744?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/4975111396374855744/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=4975111396374855744' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/4975111396374855744'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/4975111396374855744'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/05/caffeine-science-and-propaganda.html' title='caffeine, the science and the propaganda'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-5083685062012873384</id><published>2009-05-11T20:28:00.002+02:00</published><updated>2009-05-11T20:54:58.459+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Code Kata'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>Europython</title><content type='html'>I'm looking forward to &lt;a href="http://www.europython.eu"&gt;Europython&lt;/a&gt; in Birmingham at the end of June. Geoff and I are going to be rather busy at it. They've just published the &lt;a href="http://www.europython.eu/talks/talk_abstracts/"&gt;programme&lt;/a&gt;, and between us we are holding 5 sessions. I'm running a "&lt;a href="http://codingdojo.org"&gt;coder's dojo&lt;/a&gt;", a "clean code challenge", and Geoff and I are doing a tutorial on &lt;a href="http://texttest.org"&gt;texttest&lt;/a&gt; together. Geoff is also giving talks about &lt;a href="http://texttest.org"&gt;texttest&lt;/a&gt; and &lt;a href="http://texttest.carmen.se/index.php?page=concepts&amp;amp;n=pyusecase"&gt;pyUseCase&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The coder's dojo session is a copy of the original XP2005 workshop by Laurent Bossavit and Emmanual Gaillot, only in python with different Katas. The structure is the same though - introduction, prepared Kata, randori, retrospective. I thought it worked really well in 2005, so why change a winning format?&lt;br /&gt;&lt;br /&gt;The clean code challenge is an idea I came up with. I've &lt;a href="http://emilybache.blogspot.com/2009/02/java-ish-python.html"&gt;written on this blog&lt;/a&gt; before about &lt;a href="http://www.codingdojo.org/cgi-bin/wiki.pl?KataArgs"&gt;KataArgs&lt;/a&gt;, and my dodgy python translation of Bob Martin's code.  I'm interested to know what the python community will make of it.  I'm basically planning to throw &lt;a href="http://bazaar.launchpad.net/%7Eemily-bache/%2Bjunk/KataArgs/files/head%3A/src/kata_args_javaish/"&gt;this code&lt;/a&gt; out to anyone who turns up, and ask them to refactor it into better python. I'm of course hoping they will produce some innovative, beautifully pythonic solutions, and show me what clean code looks like in python.&lt;br /&gt;&lt;br /&gt;The tutorial on texttest is essentially similar to the one Geoff and I did at Europython in 2005. It's longer though, a half day, and builds on all the experience we have had since, doing tutorials at XP2006 and agile2008 for example.&lt;br /&gt;&lt;br /&gt;All in all, I hope we'll have some time and energy left to go to the other items in the programme. It looks like being a busy conference.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-5083685062012873384?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/5083685062012873384/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=5083685062012873384' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/5083685062012873384'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/5083685062012873384'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/05/europython.html' title='Europython'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-2898710108832765955</id><published>2009-05-06T20:30:00.003+02:00</published><updated>2009-05-06T20:45:37.273+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Code Kata'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>TDD performer artists announced</title><content type='html'>As I wrote in a &lt;a href="http://emilybache.blogspot.com/2009/04/call-for-participation-in-workshop-at.html"&gt;previous post&lt;/a&gt;, I am organising a workshop at &lt;a href="http://www2.xp2009.org/xp2009/en/programme.wp"&gt;XP2009&lt;/a&gt; called &lt;a href="http://www2.xp2009.org/xp2009/en/contentview.wp?contentId=CNG134"&gt;"Test Driven Development: Performing Art"&lt;/a&gt;. I am very pleased to announce that I have four pairs of expert programmers willing to perform &lt;a href="http://www.codingdojo.org/cgi-bin/wiki.pl?PreparedKata"&gt;prepared Kata&lt;/a&gt;s at it! You can read about it &lt;a href="http://www.codingdojo.org/cgi-bin/wiki.pl?KataWorkshop"&gt;here&lt;/a&gt;. I am especially pleased that all the performers are experienced coders with previous involvement in coding dojos in places such as Stockholm, Linköping, London, São Paulo and Helsinki. I think we're going to have a great afternoon on 27th May.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-2898710108832765955?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/2898710108832765955/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=2898710108832765955' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/2898710108832765955'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/2898710108832765955'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/05/tdd-performer-artists-announced.html' title='TDD performer artists announced'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-1912902591028618737</id><published>2009-04-21T19:34:00.004+02:00</published><updated>2009-04-21T20:50:09.532+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>They learn so fast and they are so cheap</title><content type='html'>Recently I've had the priviledge of working with a team of developers where I sit in the same room as half of them, and the other half are in China. My role is to help them to develop a suite of automated system tests alongside the production code. After a few month's work, we now have quite a substantial product, with quite a substantial test suite.&lt;br /&gt;&lt;br /&gt;When we started, very few of the developers had written much in the way of system tests, and even fewer knew how to write good, maintainable ones. Over the weeks, I have been promoting practices to enhance test readability, reviewing test code, and pointing out areas that need better coverage.&lt;br /&gt;&lt;br /&gt;I've noticed that with the local developers, reviews and feedback are usually conducted face to face, informally, whereas with the offshore developers, it all goes via email, with a substantial time delay. This has meant that the Swedish developers have learnt faster, since they benefit from shorter feedback cycles, and a richer form of communication.  Having said that, the Chinese developers are doing nearly as well. They seem really motivated to deliver what I ask for, and keep requesting and responding to feedback until they have written what I consider to be some pretty good tests.&lt;br /&gt;&lt;br /&gt;It's not all sweetness and light, however. As much as learning the technical skills of writing tests, the team needs to learn the culture of maintaining them. The CI server complains the build is broken far too often, and it is because the developers generally are not running the tests before they check in. My perception is that the offshore developers are worse at this, and my interpretation is not that they are somehow less good developers, far from it. I think that they just don't have the same management support to spend time on maintaining the tests as the onshore ones.&lt;br /&gt;&lt;br /&gt;Management in Sweden has really bought into the idea that investing in automated tests pays off over the long term, and vigorously support me in discussions with recalcitrant developers. Management in China has not. My impression is that they see only the costs associated with writing, running and maintaining automated tests, and would rather hire some (ridiculously cheap) Chinese students to run manual tests instead.&lt;br /&gt;&lt;br /&gt;I would like to believe that this automated test suite is a really good investment for the future of this product. My experience tells me it should enable regression bugs to be found very soon after insertion, and enable much more frequent product releases. (You don't have to wait for a 6 week manual test cycle before each release). Over the many year lifetime of the product, this should significantly outweigh the initial investment we have made creating it, and the ongoing costs of keeping it running.&lt;br /&gt;&lt;br /&gt;The reality may be quite different. Future versions of the product will likely be developed entirely in China, and I suspect that without their Swedish colleagues' enthusiasm, the Chinese management might decide the test suite should be quietly dismantled and left to rot. That may be the right economic decision, although it makes me weep to think of it. All I can do is console myself with the thought that at least the tests are so readable they will be easy to convert into manual test cases detailed enough for dirt cheap unskilled Chinese students to perform.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-1912902591028618737?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/1912902591028618737/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=1912902591028618737' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/1912902591028618737'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/1912902591028618737'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/04/they-learn-so-fast-and-they-are-so.html' title='They learn so fast and they are so cheap'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-6908017545994228121</id><published>2009-04-02T21:12:00.003+02:00</published><updated>2009-04-02T21:22:22.819+02:00</updated><title type='text'>Call for participation in workshop at XP2009</title><content type='html'>I'm looking for some really good coders. People who can write outstanding code, and yet know that however good they are they can always get a little bit better with a little practice, feedback and reflection. The kind of coders that attend a &lt;a href="http://codingdojo.org"&gt;coding dojo&lt;/a&gt; and practice on &lt;a href="http://codekata.pragprog.com/"&gt;code katas&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Interested? Could be persuaded to attend &lt;a href="http://www2.xp2009.org/xp2009/en/programme.wp"&gt;XP2009&lt;/a&gt;? Take a look at this &lt;a href="http://codingdojo.org/cgi-bin/wiki.pl?KataWorkshop"&gt;call for participation&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-6908017545994228121?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/6908017545994228121/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=6908017545994228121' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/6908017545994228121'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/6908017545994228121'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/04/call-for-participation-in-workshop-at.html' title='Call for participation in workshop at XP2009'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-6608766333102670362</id><published>2009-03-31T19:57:00.005+02:00</published><updated>2009-03-31T21:15:54.521+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>Scandinavian Developers Conference</title><content type='html'>At the speakers dinner the night before the conference:&lt;br /&gt;&lt;br /&gt;Ola Bini: "Do you have any actual code examples in your talk about clean code tomorrow?"&lt;br /&gt;Me: "No"&lt;br /&gt;Ola Bini: "Well, I'm sorry but that means I can't come and listen to it"&lt;br /&gt;&lt;br /&gt;Not such an auspicious start perhaps, but fortunately about 125 other conference participants didn't seem to mind the lack of actual code, and did turn up for my talk. Some of them even &lt;a href="http://www.highlevelbits.com/2009/03/scandevconf-summary.html"&gt;blogged favourably&lt;/a&gt; about it. To my surprise, some guy came up to me afterwards and said he helped organize the &lt;a href="http://www.jfokus.se/jfokus/"&gt;JFokus&lt;/a&gt; conference, and did I have a Java talk I could give at it?&lt;br /&gt;&lt;br /&gt;It was a lot of work preparing my presentation, and I got some really useful feedback from the two practice runs I did, at &lt;a href="http://groups.google.com/group/gothpy"&gt;GothPy&lt;/a&gt; and for my colleagues at &lt;a href="http://www.ibs.net/se/"&gt;IBS&lt;/a&gt;. It was this feedback that prompted me to take out all the code examples I originally had in the presentation, actually.&lt;br /&gt;&lt;br /&gt;Overall the conference seemed to go really well. There were about 450 participants, about 40 speakers, and 6 parallel tracks. I attended some great sessions, too but I'll leave a summary of them to another post.&lt;br /&gt;&lt;br /&gt;Just in case you were wondering, I didn't go to Ola Bini's talk either ;-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-6608766333102670362?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/6608766333102670362/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=6608766333102670362' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/6608766333102670362'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/6608766333102670362'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/03/scandinavian-developers-conference.html' title='Scandinavian Developers Conference'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-6390038230844664025</id><published>2009-02-25T21:56:00.003+01:00</published><updated>2009-04-15T20:19:18.009+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Code Kata'/><category scheme='http://www.blogger.com/atom/ns#' term='python'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Java-ish python</title><content type='html'>I am really interested to find out more about this concept of "clean code", and in particular how it relates to programming language. To this end, I'm still chewing on &lt;a href="http://codingdojo.org/cgi-bin/wiki.pl?KataArgs"&gt;KataArgs&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;My latest idea is to start from Bob Martin's &lt;a href="http://github.com/unclebob/javaargs/tree/master"&gt;Java implementation&lt;/a&gt;, and translate this as directly as possible into python. My idea is to then refactor it to be more pythonic, and see if it turns out looking anything like his &lt;a href="http://github.com/unclebob/rubyargs/tree/master"&gt;Ruby implementation&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I have put up &lt;a href="http://bazaar.launchpad.net/%7Eemily-bache/%2Bjunk/KataArgs/files/head%3A/src/kata_args_javaish/"&gt;some code on launchpad&lt;/a&gt;, which is my attempt at a direct translation of the Java. It was really interesting to do, actually. Of course I had read the Java before, and followed along in the book all the steps to create it, but actually translating it made me understand the code on another level. When I tackled this Kata from scratch, I also got a much better understanding of it, but this was different.&lt;br /&gt;&lt;br /&gt;One thing that jumped out at me was the error handling. It's much more comprehensive than anything I've produced in my own solutions, and also compared with his Ruby solution. So I think it's a bit misleading of him to say "I recently rewrote this in Ruby and it was 1/7 the size". Of course it is smaller. It does less. Although to be fair, in a way it does more too...&lt;br /&gt;&lt;br /&gt;One thing I found awkward to translate was the use of the enum for the list of error codes. Python doesn't have a direct equivalent, being dynamic as it is. The other awkwardness was the Java iterator. In python iterators are built into the language, but don't let you backtrack, or get the current index, unlike Java ones. I was surprised to find how extensively the tests rely on this functionality. To my mind, they probe the internals of the args parser too much.&lt;br /&gt;&lt;br /&gt;By far my most interesting observation, though, is the one I want to explore more. This code is well written Java, but directly translated, it makes pretty poor python. Why is that? What, specifically, are the smells, and what are the antidote refactorings?&lt;br /&gt;&lt;br /&gt;I will no doubt post more on what I find, (with the help of my friends at &lt;a href="http://groups.google.com/group/gothpy?hl=en"&gt;GothPy&lt;/a&gt;, of course)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-6390038230844664025?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/6390038230844664025/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=6390038230844664025' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/6390038230844664025'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/6390038230844664025'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/02/java-ish-python.html' title='Java-ish python'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-8934918007437285457</id><published>2009-02-25T21:24:00.004+01:00</published><updated>2009-02-25T21:54:20.066+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Code Kata'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>fun with KataArgs</title><content type='html'>I'm having fun with this &lt;a href="http://codingdojo.org/cgi-bin/wiki.pl?KataArgs"&gt;KataArgs&lt;/a&gt;. In &lt;a href="http://emilybache.blogspot.com/2009/01/kataargs-and-clean-code.html"&gt;my last post&lt;/a&gt;, I took a closer look at Bob Martin's Java and Ruby solutions to it. Since then, we have tackled this Kata at a couple of &lt;a href="http://groups.google.com/group/gothpy"&gt;GothPy&lt;/a&gt; meetings. (My &lt;a href="http://codingdojo.org"&gt;coding dojo&lt;/a&gt;; the code is &lt;a href="http://github.com/johanlindberg/gothpy-katas/tree/master"&gt;here&lt;/a&gt;.)&lt;br /&gt;&lt;br /&gt;Several of us did some more work on the kata individually after the meetings, and a&lt;a href="http://groups.google.com/group/gothpy"&gt; lively discussion &lt;/a&gt;on our mailing list ensued. I also challenged the local Ruby user group &lt;a href="http://groups.google.com/group/gotrb"&gt;Got.rb&lt;/a&gt; to have a go at it, and one person posted his solution there too.&lt;br /&gt;&lt;br /&gt;It's all good fun, anyway, and hopefully we're all learning something about what we mean by "clean code" along the way.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-8934918007437285457?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/8934918007437285457/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=8934918007437285457' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8934918007437285457'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8934918007437285457'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/02/fun-with-kataargs.html' title='fun with KataArgs'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-4760304245564056195</id><published>2009-01-21T10:09:00.006+01:00</published><updated>2009-01-21T11:40:27.030+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Code Kata'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>KataArgs and clean code</title><content type='html'>Over Christmas I finished reading the book "Clean Code" by Robert C. Martin. I thoroughly recommend the book, which is highly practical, technical and well written. In it, Bob seeks to present the "Object Mentor school of clean code", as he puts it, "in hideous detail".&lt;br /&gt;&lt;br /&gt;The book is full of code examples, clean and less clean, and detailed advice about how to transform the latter into the former. All the examples are written in Java, though, which leaves me wondering a little if "clean code" in the Object Mentor meaning of the word, looks the same in other languages.&lt;br /&gt;&lt;br /&gt;In Chapter 14 of the book, there is a fully worked example of a little coding problem that I would call a code Kata. It's a little program for parsing command line arguments. I know, there are loads of libraries that do this already. But never mind. It's a non trivial problem yet small enough to code up fairly quickly. One thing that caught my attention was the footnote on page 200, just after he has presented his best Java solution to the Kata. "I recently rewrote this module in Ruby. It was 1/7th the size and had a subtly better structure." So where is the code, Bob? What is this subtly better structure?&lt;br /&gt;&lt;br /&gt;I had nothing better to do on Boxing Day than sit around and digest leftover-turkey-curry, so I sent a little mail to Bob asking him for the code. To my delight, I got a mail back only a few hours later, with a message that I was welcome to it, and the &lt;a href="http://github.com/unclebob/rubyargs/tree/master"&gt;url to where he'd put it on github&lt;/a&gt;. Evidently Bob also had time on his hands on Boxing Day.&lt;br /&gt;&lt;br /&gt;I have had a look at the Ruby code, and although my Ruby is fairly ropey, I think I can follow what it does (surely a sign of clean code?). The design is very similar to the Java version presented in the book, with a couple of finesses. (The next part of the post will make most sense if you first look at Bob's &lt;a href="http://github.com/unclebob/javaargs/tree/master"&gt;Java version&lt;/a&gt; and &lt;a href="http://github.com/unclebob/rubyargs/tree/master"&gt;Ruby version&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;The first finesse I spotted, is that the Ruby version defines the argument "schema" in a much more readable fashion. Rather than &lt;span style="font-family:courier new;"&gt;"l,p#,d*"&lt;/span&gt; as in the Java version, it reads&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;parser = Args.expect do&lt;br /&gt;   boolean "l"&lt;br /&gt;   number "p"&lt;br /&gt;   string "d"&lt;br /&gt; end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;ie the program expects three flags, l,p, and d, indicating a boolean, number and string respectively. You can do this in Ruby but not Java because the language allows you to pass a code block to a method invocation. (the stuff between "do" and "end" is a code block, and the class "Args" has a method "expect") I think the Ruby version is rather more readable, don't you?&lt;br /&gt;&lt;br /&gt;The second finesse I can see is that the argument marshallers dynamically add themselves to the parser, rather than being statically declared as in the Java version. &lt;span class="k"&gt;This means that if you discover a new argument type that you want to support, in the Java version you have to crack open the code for Args.java and add a new case statement in the "parseSchemaElement" method, as well as adding the new argument marshaller class. In the Ruby version, you just add the new class, no need to modify an existing one. Bob invented the &lt;a href="http://www.objectmentor.com/resources/articles/ocp.pdf"&gt;Open-Closed principle&lt;/a&gt;, so I guess it's not so surprising to see him following it :-)&lt;br /&gt;&lt;br /&gt;So in Args.java:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;private void parseSchemaElement(String element)&lt;br /&gt; throws ArgsException {&lt;br /&gt;char elementId  = element.charAt(0);&lt;br /&gt;String elementTail = element.substring(1);&lt;br /&gt;&lt;br /&gt;// long if/else statement to construct all the marshallers&lt;br /&gt;// cut for brevity&lt;br /&gt;[...]&lt;br /&gt; else if (elementTail.equals("#"))&lt;br /&gt;   marshallers.put(elementId, new IntegerArgumentMarshaller());&lt;br /&gt; else if (elementTail.equals("*"))&lt;br /&gt;[...]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;or in the Ruby code, each marshaller just tells the parser to add itself:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class NumberMarshaler&lt;br /&gt;   Parser.add_declarator("number", self.name)&lt;br /&gt;[...]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;in the Parser class:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;   def self.add_declarator(name, marshaler)&lt;br /&gt;     method_text = "def #{name}(args) declare_arguments(args, #{marshaler}) end"&lt;br /&gt;     Parser.module_eval(method_text)&lt;br /&gt;   end&lt;br /&gt;&lt;br /&gt;   def declare_arguments(args, marshaler)&lt;br /&gt;     args.split(",").each {|name| @args[name] = marshaler.new}&lt;br /&gt;   end&lt;br /&gt; &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You can do this in Ruby but not Java, since in Ruby you can dynamically construct and execute arbitrary strings as code, and add methods to classes at runtime. (The string declared as "method_text" is constructed with the details of the new marshaler, then executed as Ruby code in the next line, by Parser.module_eval) This is an example of metaprogramming.&lt;br /&gt;&lt;br /&gt;So it seems to me that the "subtly better structure" that Bob refers to in his footnote, is made possible by powerful language features of Ruby, such as metaprogramming and closures.&lt;br /&gt;&lt;br /&gt;Of course my favourite programming language is Python, which also has these powerful language features. I am rather interested to see if I can come up with an equally clean solution in Python. I am also interested if any hotshot Java or Ruby programmers out there can improve on Bob's solutions. To this end, I have added a description of this Kata to the &lt;a href="http://codingdojo.org/cgi-bin/wiki.pl?KataCatalogue"&gt;catalogue&lt;/a&gt; on&lt;/span&gt; &lt;a href="http://codingdojo.org/cgi-bin/wiki.pl?KataArgs"&gt;codingdojo.org&lt;/a&gt;. We had a go at it at our last &lt;a href="http://groups.google.com/group/gothpy"&gt;GothPy&lt;/a&gt; meeting, without any great success, although I hope we might do better at a future meeting.&lt;br /&gt;&lt;br /&gt;So please have a go at &lt;a href="http://codingdojo.org/cgi-bin/wiki.pl?KataArgs"&gt;KataArgs&lt;/a&gt; and see if you can write some really really clean code. Do let me and the community on codingdojo.org know how you get on!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-4760304245564056195?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/4760304245564056195/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=4760304245564056195' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/4760304245564056195'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/4760304245564056195'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/01/kataargs-and-clean-code.html' title='KataArgs and clean code'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-7050347967116238723</id><published>2009-01-14T20:03:00.004+01:00</published><updated>2009-01-14T20:54:41.661+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='BDD'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Behaviour Driven Development at agile2008</title><content type='html'>At &lt;a href="http://agile2008.org/"&gt;agile2008&lt;/a&gt; I attended a &lt;a href="http://submissions.agile2008.org/node/936"&gt;session&lt;/a&gt; with Dan North about Behaviour Driven Development. Someone on the &lt;a href="http://www.blogger.com/www.agilesweden.org"&gt;agile sweden&lt;/a&gt; mailing list was asking about it, so I decided to write up my notes here.&lt;br /&gt;&lt;br /&gt;Most cellphone and computer software is delivered late and over budget. The biggest contributing factor to cost bloat is building the wrong thing. So what software and business people need is "a shared understanding of what done looks like".&lt;br /&gt;&lt;br /&gt;Test Driven Development is about design, conversations, and writing examples for a system that doesn't yet exist. It's not really about testing.  However, once the system exists, your examples turn into tests, as a rather useful side effect.&lt;br /&gt;&lt;br /&gt;A User Story is a promise of a conversation, and it is in that conversation that things go wrong. The customer and developer rarely agree what "enough" and "done" look like, which leads to over- or under- engineering.&lt;br /&gt;&lt;br /&gt;Dan suggests a format for User Story cards which aims to prevent this communication gap.&lt;br /&gt;&lt;br /&gt;On the front of the User Story index card, you have the title and narrative. The narrative consists of a sentence in this format:&lt;br /&gt;&lt;br /&gt;As a &lt;stakeholder&gt;&lt;span style="font-style: italic;"&gt;stakeholder&lt;/span&gt;&lt;br /&gt;I want &lt;span style="font-style: italic;"&gt;feature&lt;/span&gt;&lt;feature&gt;&lt;br /&gt;so that &lt;span style="font-style: italic;"&gt;benefit&lt;/span&gt;&lt;benefit&gt;&lt;br /&gt;&lt;br /&gt;where &lt;span style="font-style: italic;"&gt;benefit&lt;/span&gt; &lt;benefit&gt; is something of value to &lt;stakeholder&gt;&lt;span style="font-style: italic;"&gt;stakeholder&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;On the back of the card, you have a table with three columns&lt;br /&gt;&lt;br /&gt;Given this context | When I do this | then this happens&lt;br /&gt;&lt;br /&gt;Then you have 4 or 5 rows in the table, each detailing a scenario. (If you need more than that then the story is too big and should be split)&lt;br /&gt;&lt;br /&gt;Dan finds that in his work, this leads to conversations about User Stories where "done" and "enough" are discussed, and defined.&lt;br /&gt;&lt;br /&gt;User Stories should be about activities, not features. In order to check that your User Story is an activity, you should be able to do a thought experiment where you implement the story as a task to be performed by people on rollerblades with paper. You must think about it as a business process, not a piece of software.&lt;br /&gt;&lt;br /&gt;When creating the story cards, the whole team should be involved, but it is primarily the business/end user stakeholders and business analysts who write the title and narrative on the cards. They then take in a tester to help them to write the scenarios.&lt;br /&gt;&lt;br /&gt;Are people familiar with the &lt;a href="http://en.wikipedia.org/wiki/V-Model_%28software_development%29"&gt;V model of software testing&lt;/a&gt;? When this was conceived, they thought that the whole process would take 2 years, and span the whole project. Dan ususally does it in 2 days. Many times for each project.&lt;br /&gt;&lt;br /&gt;Then Dan offered to show us how to do BDD using plain JUnit. He requested a pair from the audience, so I volunteered. At this point my notes dry up, and I am working from memory, but I think the general idea is like this.&lt;br /&gt;&lt;br /&gt;You talk about "behaviour specs" not tests. The words you use influence the way you think, and "behaviour specification" gives much better associations than "tests".&lt;br /&gt;&lt;br /&gt;Each behaviour specification should be named to indicate the behavour it is specifying. Not "testCustomerAccountEmpty" rather "customerAccountShouldBeEmpty".&lt;br /&gt;&lt;br /&gt;In the body of the spec, you can start out by typing in the prose of one of the scenarios you have on the user story, as a comment.&lt;br /&gt;&lt;br /&gt;//given we have a flimble containing a schmooz&lt;br /&gt;// when we request the next available frooble&lt;br /&gt;// then we are given a half baked frooble and the schmooz.&lt;br /&gt;&lt;br /&gt;Then you can fill in code after the "given" comment. When you have code that does what the comment says, delete the comment. Repeat with the "when" and "then" comments.&lt;br /&gt;&lt;br /&gt;In this way, you build up a behaviour specification that drives your development of the system. A few minutes later (hopefully) you have a system which implements the specification, and at that point your spec helpfully turns magically into a regression test which you can run. At that point you can start calling it a test if you like. But actually it is more helpful to your brain to continue to think of it as a behaviour specification. It leads to much more constructive conversations about the system.&lt;/stakeholder&gt;&lt;/benefit&gt;&lt;/benefit&gt;&lt;/feature&gt;&lt;/stakeholder&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-7050347967116238723?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/7050347967116238723/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=7050347967116238723' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/7050347967116238723'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/7050347967116238723'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/01/behaviour-driven-development-at.html' title='Behaviour Driven Development at agile2008'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-6995467919877413006</id><published>2009-01-10T20:58:00.003+01:00</published><updated>2009-01-10T21:22:42.152+01:00</updated><title type='text'>'Agile'? or just 'more agile than ...'?</title><content type='html'>The project manager was obviously a little irritated. "By this stage of the pre-study, we really should have the requirements a little more nailed down than this. That's two new requirements since last week. Or what does everyone think?" he looks around the table, expecting support. The business representative looks disappointed and hangs his head.&lt;br /&gt;&lt;br /&gt;Without really thinking, I follow my instinct and jump in. "It seems wrong to me to say to the customer that he can't have any more features at this stage. Perhaps he should be prepared to drop something else instead, but surely we should be prepared to respond to the needs of the business? We are still in the pre-study, after all"&lt;br /&gt;&lt;br /&gt;The project manager was not impressed. "This pre-study has already been going on for nearly 2 months, we really need to put together a budget and project plan so we can pass the next tollgate and proceed to the implementation phase." He looked around the table sternly, then his frown softened a little. "Well ok, you can have these two new requirements. Let's take a look at them"&lt;br /&gt;&lt;br /&gt;A few days later, the project manager called me into his office.&lt;br /&gt;  - "You can't go telling the customer he's allowed to change his mind. After that meeting he came to me with more requirements. Your comments confused him as to how our software development process works. Please don't do it again".&lt;br /&gt;- "But I though we were trying to be agile in this project? You know, short release cycles, end of iteration demos, like in Scrum".&lt;br /&gt;- "Yes, we are following a process which is more agile than the standard company mandated process. We have got permission to skip two of the tollgates, and 5% extra in the budget for 'adjustments' so we can respond to the customer feedback we get at each demo. We are &lt;span style="font-style: italic;"&gt;not&lt;/span&gt; doing Scrum though. Who told you that?"&lt;br /&gt;&lt;br /&gt;Sigh. I heard "agile". What I should have heard was "more agile than the standard company process".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-6995467919877413006?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/6995467919877413006/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=6995467919877413006' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/6995467919877413006'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/6995467919877413006'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2009/01/agile-or-just-more-agile-than.html' title='&apos;Agile&apos;? or just &apos;more agile than ...&apos;?'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-5273038333708375654</id><published>2008-12-17T19:19:00.003+01:00</published><updated>2008-12-17T19:28:45.820+01:00</updated><title type='text'>Would you buy a hammer from this man?</title><content type='html'>The &lt;a href="www.dyalog.com"&gt;APL community&lt;/a&gt; clearly contains some characters. I really enjoyed this &lt;a href="http://uk.youtube.com/watch?v=qSVR4Z3DA24"&gt;heartfelt plea for simplicity&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://uk.youtube.com/watch?v=qSVR4Z3DA24" target="_blank"&gt;&lt;br /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-5273038333708375654?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/5273038333708375654/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=5273038333708375654' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/5273038333708375654'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/5273038333708375654'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2008/12/would-you-buy-hammer-from-this-man.html' title='Would you buy a hammer from this man?'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-841814972559472190</id><published>2008-11-30T22:14:00.004+01:00</published><updated>2008-11-30T23:01:02.375+01:00</updated><title type='text'>small children and working hours</title><content type='html'>Michelle the manager has two small children. She regularly puts in a 45 hour week. Alan the project manager also has two small children. He officially works 80%. The first architect, Steve, has one small child. He officially works 90%. The second architect, Flo, has two small children. She officially works 100%. Also on the project team are a number of developers, testers and other experts.&lt;br /&gt;&lt;br /&gt;The project isn't doing so well, and when there are about 6 weeks left until the delivery deadline, Alan the project manager starts coming in on Fridays - the day he usually spends at home with his children. Luckily his wife's mother lives just round the corner, and since she is retired there is no problem with childcare.&lt;br /&gt;&lt;br /&gt;A short time later, he starts to make impassioned speeches to the project team about how important it is to make the deadline, and presents a strong case that overtime is needed. He asks everyone has to email him with their availability over the coming two weekends.&lt;br /&gt;&lt;br /&gt;Michelle already works weekends semi-regularly.  Her husband is in a business that is suffering from the recession, so he is only working 75% anyway, so there is no problem with childcare. She is available.&lt;br /&gt;&lt;br /&gt;Steve is hardworking and ambitious, and his wife is happy to spend more time looking after their child. Steve is available.&lt;br /&gt;&lt;br /&gt;One of the developers, Paul, has one small child, but his wife's mother is also keen to help, so childcare is not a problem. He is available.&lt;br /&gt;&lt;br /&gt;None of the other developers have children. No problem with their availability then.&lt;br /&gt;&lt;br /&gt;The thing is, Flo does have a problem. She has no extended family within reach who could be called in at such short notice. Her husband is already at home on paternity leave 100% and is finding it tough. He doesn't want to take up the slack, and she doesn't want to spend any less time with her children than she does already. After some thought, Flo tells Alan she is not available.&lt;br /&gt;&lt;br /&gt;So what happens? Everyone works extra, except Flo. Alan is frustrated because he feels he can't give her any important tasks to work on, because he knows she won't stay late to finish them. Then Flo requests to work 80% in the new year, so she can spend more time with her children. (By Swedish law, all parents with young children who have a full time job have the right to reduce their hours.) Alan is not pleased, and talks to his boss about the situation. The project must go out on time, and he feels Flo's behaviour is endangering this. The upshot is that Flo is told her contract will not be renewed.&lt;br /&gt;&lt;br /&gt;The official reason given is that "working 80% is not compatible with the rate of productivity we require of an architect at this workplace". The secondary reason given is the unwillingness to work overtime. As a contractor and not an employee, Flo has no recourse, the law doesn't apply, and she is left searching for a new contract to work on.&lt;br /&gt;&lt;br /&gt;It turns out that even in enlightened, feminist Sweden (1), even when the boss in question himself has small children and normally works 80%, even when the other architect in the team officially work less than 100%, it is still the case that a mother working the hours specified in her contract, is not able to keep her position.&lt;br /&gt;&lt;br /&gt;If this is what it is like in Sweden, God help working women in the rest of the world.&lt;br /&gt;&lt;br /&gt;(1) Just as an example how the feminist culture affects the political agenda: The main opposition party, (who polls indicate will win power at the next election), wants to quota parental leave so that each parent will be forced to take half of time available. This must be the only nation in the world that expects fathers to stay home from work for 8 months with each of their children.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-841814972559472190?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/841814972559472190/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=841814972559472190' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/841814972559472190'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/841814972559472190'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2008/11/small-children-and-working-hours.html' title='small children and working hours'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-8060801677204346392</id><published>2008-11-30T20:51:00.002+01:00</published><updated>2008-11-30T22:14:08.935+01:00</updated><title type='text'>Overtime</title><content type='html'>If you were looking to employ someone, what would you say to a candidate like this:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;highly intelligent, excellent qualifications for the job, 10 years relevant experience, hardworking, ambitious.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Sounds good, doesn't it? What if she then added:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;has 2 children, will not work overtime, (although still hardworking during normal working hours)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Perhaps not quite as interesting?&lt;br /&gt;&lt;br /&gt;Then if she went on to ask to work 80%?&lt;br /&gt;&lt;br /&gt;So the reality is, how many employers turn to the next CV at this point?&lt;br /&gt;&lt;br /&gt;Anyway it looks like I am going to be finding out. My experience as a contractor so far is not encouraging.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-8060801677204346392?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/8060801677204346392/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=8060801677204346392' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8060801677204346392'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8060801677204346392'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2008/11/overtime.html' title='Overtime'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-8847332774453742168</id><published>2008-11-23T18:22:00.003+01:00</published><updated>2008-11-23T19:43:33.922+01:00</updated><title type='text'>agile toolkit podcast</title><content type='html'>My weekend jog through the park was particularly interesting this week. Not just because of the light sprinkling of snow, bright sun and freezing temperatures. I had to watch my footing every time I heard myself interrupt Geoff or forget someone's name. Yes, I was on my own. And no, nothing wrong with my head. (nothing serious, anyway). I was listening to the latest &lt;a href="http://agiletoolkit.libsyn.com/"&gt;agile toolkit&lt;/a&gt; podcast where &lt;a href="http://www.agileitx.com/conference/speaker/robert_payne.html"&gt;Bob Payne&lt;/a&gt; &lt;a href="http://agiletoolkit.libsyn.com/index.php?post_id=404779"&gt;interviews Geoff and me&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;In a &lt;a href="http://emilybache.blogspot.com/2007/10/bob-payne-and-language-communities.html"&gt;previous post&lt;/a&gt; I was rather critical of Bob's interviewing technique, and perhaps this is justified. He is a really genuinely friendly guy though, who is warm and enthusiastic towards people and that does make up for a lot. In the interview he did make some random joke about Thoughtworks that I still don't get, but on the whole I think we got on ok.&lt;br /&gt;&lt;br /&gt;In the first part of the interview we talk alot about how &lt;a href="http://texttest.org"&gt;TextTest&lt;/a&gt; grew up in an environment of long running batch processes, and a bit about the crew planning system that Geoff wrote it to deal with. I hope listeners don't decide this is boring and switch of at this point, because it does do more than just that. I talk a bit about what we did with TextTest on &lt;a href="http://emilybache.blogspot.com/2008/08/we-pulled-it-off.html"&gt;'Programming with the stars' &lt;/a&gt;and then we discussed what else it is good for (legacy code, and even greenfield TDD development).&lt;br /&gt;&lt;br /&gt;I did try to think through beforehand all the things I was going to say, but intevitably I left out a couple of important points. Neither of us mentioned that TextTest is written in &lt;a href="http://python.org"&gt;python&lt;/a&gt; but can test any language (so long as it can produce plain text log output). I didn't make it clear that I don't work for &lt;a href="http://www.jeppesen.com/index.jsp"&gt;Jeppesen&lt;/a&gt;, rather my new employer &lt;a href="http://jsolutions.se/"&gt;IBS JavaSolutions&lt;/a&gt; kindly paid my conference ticket. I said that 'I' got the highest marks in the stars competition instead of 'we' (forgive me Michael and Geoff! We did it together, I know)&lt;br /&gt;&lt;br /&gt;Overall I think the podcast is worth listening to though. I hope it will encourage some people to try out texttest, and write automated tests for some code that they thought was untestable.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-8847332774453742168?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/8847332774453742168/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=8847332774453742168' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8847332774453742168'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8847332774453742168'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2008/11/agile-toolkit-podcast.html' title='agile toolkit podcast'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-5719942601695511654</id><published>2008-11-12T20:23:00.004+01:00</published><updated>2008-11-30T20:50:45.844+01:00</updated><title type='text'>Intimidating situations</title><content type='html'>This week I was finally invited to the  architect forum meeting. Ten more or less geeky men, and me. It's funny, I don't usually think about the gender imbalance in the software industry much. On this occasion though, I felt distinctly uncomfortable. They all seemed to know each other, and mostly ignored me. They had an annoying habit of spattering their conversation with unidentified acronyms. I left feeling somewhat disheartened.&lt;br /&gt;&lt;br /&gt;Later that evening I talked to my husband about the experience, as I often do. Seeing as we both work in the same industry, he generally has helpful comments. This was no exception, even though Geoff is currently at home with the children, enjoying his parental leave. "I understand just how you feel. Today I went to the baby rhythm and song group. Ten women with babies, and me, also with baby. They all seemed to know each other, and mostly ignored me. They tended to talk about breastfeeding and shopping."&lt;br /&gt;&lt;br /&gt;So it could be worse, I suppose.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-5719942601695511654?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/5719942601695511654/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=5719942601695511654' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/5719942601695511654'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/5719942601695511654'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2008/11/intimidating-situations.html' title='Intimidating situations'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-8413817193988233081</id><published>2008-10-24T19:58:00.007+02:00</published><updated>2008-10-24T20:30:53.813+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='conferences'/><title type='text'>booked for SDC2009</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_AkG8Hw7A2Pw/SQIRd7AK7tI/AAAAAAAAAB8/eZBCnns4N34/s1600-h/sdc2009.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 320px; height: 90px;" src="http://2.bp.blogspot.com/_AkG8Hw7A2Pw/SQIRd7AK7tI/AAAAAAAAAB8/eZBCnns4N34/s320/sdc2009.jpg" alt="" id="BLOGGER_PHOTO_ID_5260786520474447570" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;The full programme for &lt;a href="http://www.scandevconf.se/"&gt;SDC2009&lt;/a&gt; in March will be published in about a week's time, but I can already tell it will be a great event. The call for papers is now closed, and the website has been updated with photos of all the booked speakers. With only one day of talks, it looks like there will be a lot to choose from.&lt;br /&gt;&lt;br /&gt;I'm really looking forward to hearing international software gurus like &lt;a href="http://www.scandevconf.se/conference/speakers/jeff-sutherland/"&gt;Jeff Sutherland &lt;/a&gt;and &lt;a href="http://www.scandevconf.se/conference/speakers/neal-ford/"&gt;Neal Ford&lt;/a&gt;, as well as lots of cool people from Scandinavia. Clicking through the photos on the front page, there are several faces I recognize as leading agile proponents. It's actually a bit of a shock to see my own &lt;a href="http://www.scandevconf.se/conference/speakers/emily-bache/"&gt;headshot&lt;/a&gt; there in the lineup.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-8413817193988233081?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/8413817193988233081/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=8413817193988233081' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8413817193988233081'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8413817193988233081'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2008/10/booked-for-sdc2009.html' title='booked for SDC2009'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_AkG8Hw7A2Pw/SQIRd7AK7tI/AAAAAAAAAB8/eZBCnns4N34/s72-c/sdc2009.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-6731881102822661515</id><published>2008-10-07T21:07:00.002+02:00</published><updated>2008-10-07T21:20:32.581+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python'/><title type='text'>GothPy last night</title><content type='html'>The second official meeting of the Gothenburg Python User Group was last night. Eight of us turned up, despite my writing the wrong address on my meeting invite. (It is Norra Ågatan 10A, not 6A - sorry!)&lt;br /&gt;&lt;br /&gt;Anyway, in the first part of the meeting Jacob Hallen &lt;a href="http://codespeak.net/svn/pypy/extradoc/talk/ep2008/Pypy_for_the_rest_of_us.odp"&gt;explained about PyPy&lt;/a&gt;, a very interesting project. It seems &lt;a href="http://codespeak.net/pypy/dist/pypy/doc/home.html"&gt;PyPy&lt;/a&gt; aims to replace&lt;a href="www.jython.org"&gt; jython&lt;/a&gt;,&lt;a href="www.ironpython.com"&gt; iron python&lt;/a&gt;, &lt;a href="www.stackless.com"&gt;stackless&lt;/a&gt; and a host of other things, and has nearly as good performance as cpython. Jacob reckoned it would be ready for general use in about a year's time.&lt;br /&gt;&lt;br /&gt;After fika, Johan gave a short presentation about how he uses Python at Nordea. Although the company policy is only to use Java and Cobol, he has had some successes with using python too. He's written several small applications that have been quick and cheap to build and have lasted much longer than their initially projected lifetimes. Unfortunately he hasn't persuaded anyone else at Nordea to write any python yet.&lt;br /&gt;&lt;br /&gt;The coding challenge for the evening was &lt;a href="http://codingdojo.org/cgi-bin/wiki.pl?KataRomanNumerals"&gt;KataRomanNumerals&lt;/a&gt; which went very well. We split into four groups and in less than 45 mins three of the groups had working solutions, all different, all elegant in their own way. My group was the one that didn't come up with a solution and that was because I was more interested in how to define the tests than how to define the solution :-) I wanted to write the tests in a spreadsheet then generate &lt;a href="http://www.python.org/doc/2.5.2/lib/module-unittest.html"&gt;unittest&lt;/a&gt; test cases. It kind of worked. I will try again another time with &lt;a href="http://fit.zwiki.org/PythonFit"&gt;FIT&lt;/a&gt; instead.&lt;br /&gt;&lt;br /&gt;Most importantly, everyone said they enjoyed the evening and the chance to write some python code, just for fun.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-6731881102822661515?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/6731881102822661515/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=6731881102822661515' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/6731881102822661515'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/6731881102822661515'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2008/10/gothpy-last-night.html' title='GothPy last night'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-5348574244437960218</id><published>2008-10-02T21:03:00.003+02:00</published><updated>2009-01-10T20:57:52.320+01:00</updated><title type='text'>A Quality codebase</title><content type='html'>What is the quality of this codebase on a scale of 0 - 100? Zero means "perfectly designed, clean code" and 100 means "total spaghetti, impossble to make changes".&lt;br /&gt;&lt;br /&gt;Without hesitation, Andreas answered. "70".&lt;br /&gt;&lt;br /&gt;Andreas was standing at the whiteboard, sketching a timeline and drawing boxes labelled with the names of the parts of the system and the people involved. His task was to give a history lesson to the latest batch of newly arrived programmers. How did we get here?&lt;br /&gt;&lt;br /&gt;It seems that way back in about 2001 when Andreas and the rest of the team of hotshot young programmers began building this system, it was pretty good. In six weeks ten programmers had achieved more than 100 consultants from &lt;insert&gt; &lt;insert name="" of="" expensive="" consulting="" firm="" here=""&gt; had achieved in 3 months. That code was ditched shortly afterwards and Andreas' team code is still at the heart of the system today.&lt;br /&gt;&lt;br /&gt;It seems that for several years things went pretty well, Andreas' team grew slowly and the system gradually took on more and more functionality. Their focus was on working closely with the business and delivering value quickly. The team was so successful that it started pulling back work from the firm's outsourcing partners, since they were so demonstrably better at delivering valuable functionality quickly.&lt;br /&gt;&lt;br /&gt;Unfortunately the programming team is not so productive now. Over the last few years more and more people have been added, a fourfold increase in fact. Many of the original team have either left or disappeared on protracted parental leave. The quality of the codebase has deteriorated as developers unfamiliar with it have implemented new functionality at cross purposes to the original intent. It's not that they are bad programmers, but rather without guidance from more experienced people it is very hard to introduce new functionality cleanly without breaking anything. The almost total absence of automated tests doesn't help either. Programmer productivity is dropping steadily.&lt;br /&gt;&lt;br /&gt;There are various initiatives to improve the situation. For example, Andreas' training courses for new programmers. Also, several experienced programmers are working on refactoring projects. (Without the aid of tests). The question is whether this is too little, too late. Rumour has it that the size of the codebase has increased 25% in the past 6 months. Emergency patch releases are now routinely scheduled after every major release. Obvious bugs have are present in the production system that no-one seems to know how to fix.&lt;br /&gt;&lt;br /&gt;So the question I really want Andreas to answer is not the absolute quality of the codebase, but whether the quality is increasing or decreasing. Unfortunately, he couldn't tell. I fear the worst.&lt;br /&gt;&lt;/insert&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-5348574244437960218?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/5348574244437960218/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=5348574244437960218' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/5348574244437960218'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/5348574244437960218'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2008/10/quality-codebase.html' title='A Quality codebase'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-3343042631333520375</id><published>2008-09-27T19:58:00.001+02:00</published><updated>2008-09-27T20:08:40.512+02:00</updated><title type='text'>Conflict of interests</title><content type='html'>My cousin held out the keys to his flashy looking sportscar and said “Do me a favour. If you crash into something with my car and it's nearly written off, but not quite. Please back up then hit it again, harder, until it really is written off”. I laughed nervously. “yeh, sure. Of course”. Needless to say I returned his car in perfect condition a few hours later.&lt;br /&gt;&lt;br /&gt;The architect grinned as he reviewed my design proposal. “Don't worry about making the code beautiful, just make your changes work without causing extra test cyles. In fact, ugly changes are better. The sooner this code becomes legacy, the sooner we can rewrite it” I laughed nervously. “Sure, of course” He handed back my uml diagram and I went back to my computer to write some code. Beautiful code. Carefully.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-3343042631333520375?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/3343042631333520375/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=3343042631333520375' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/3343042631333520375'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/3343042631333520375'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2008/09/conflict-of-interests.html' title='Conflict of interests'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-8713931762835506078</id><published>2008-09-05T11:09:00.002+02:00</published><updated>2008-09-05T11:12:32.775+02:00</updated><title type='text'>jsolutions.se - Java nyhetskanaler</title><content type='html'>For those of you who read Swedish, I have a &lt;a href="http://jsolutions.se/?p=433"&gt;new post&lt;/a&gt; up on jsolutions.se. The gist of it is that I usually read &lt;a href="http://infoq.com"&gt;infoq&lt;/a&gt; to find out what is going on in the world, and I've just realized how biased it is compared with other Java news sources.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-8713931762835506078?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/8713931762835506078/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=8713931762835506078' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8713931762835506078'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8713931762835506078'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2008/09/jsolutionsse-java-nyhetskanaler.html' title='jsolutions.se - Java nyhetskanaler'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-3831123403494945338</id><published>2008-08-27T10:07:00.004+02:00</published><updated>2008-09-01T14:49:42.958+02:00</updated><title type='text'>Scandinavian Developer Conference in Göteborg!</title><content type='html'>&lt;a href="http://3.bp.blogspot.com/_AkG8Hw7A2Pw/SLvk1J95UzI/AAAAAAAAAB0/cfsd0CRMCtY/s1600-h/SDC2009.gif"&gt;&lt;img id="BLOGGER_PHOTO_ID_5241034193235432242" style="FLOAT: left; MARGIN: 0px 10px 10px 0px; CURSOR: hand" alt="" src="http://3.bp.blogspot.com/_AkG8Hw7A2Pw/SLvk1J95UzI/AAAAAAAAAB0/cfsd0CRMCtY/s320/SDC2009.gif" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_AkG8Hw7A2Pw/SLUPg5b0mhI/AAAAAAAAABs/Vm176NehTAU/s1600-h/sdc+logo.gif"&gt;&lt;/a&gt;I'm very excited to announce that I'm helping to organize a &lt;a href="http://www.scandevconf.se/"&gt;conference in Göteborg&lt;/a&gt; in March! This is going to be so cool. We've booked the biggest venue in town (&lt;a href="http://www.gcc.se/"&gt;Svenska Mässan&lt;/a&gt;) and are inviting high profile speakers from around the world. There will be a whole track on development processes and methodology, and I expect to see many leading agile proponents presenting there. If you're interested in presenting, there is a &lt;a href="http://www.scandevconf.se/call-for-papers/"&gt;call for papers&lt;/a&gt; open right now. Otherwise, do sign up for the &lt;a href="http://www.scandevconf.se/news.xml"&gt;rss feed&lt;/a&gt; to hear all the conference news.&lt;br /&gt;&lt;br /&gt;I really enjoy conferences, &lt;a href="http://agile2008.org/"&gt;agile2008&lt;/a&gt; was such fun, so I'm really looking forward to welcoming lots of interesting people to Göteborg in March!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-3831123403494945338?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/3831123403494945338'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/3831123403494945338'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2008/08/conference-in-gteborg.html' title='Scandinavian Developer Conference in Göteborg!'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_AkG8Hw7A2Pw/SLvk1J95UzI/AAAAAAAAAB0/cfsd0CRMCtY/s72-c/SDC2009.gif' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-3826132454829327152</id><published>2008-08-09T21:20:00.006+02:00</published><updated>2008-08-19T10:57:41.027+02:00</updated><title type='text'>Final meltdown</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_AkG8Hw7A2Pw/SKMhT8qlm5I/AAAAAAAAABU/PfnciQeMuJU/s1600-h/pairing+final.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_AkG8Hw7A2Pw/SKMhT8qlm5I/AAAAAAAAABU/PfnciQeMuJU/s320/pairing+final.JPG" alt="" id="BLOGGER_PHOTO_ID_5234063818520632210" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;The "Programming with the Stars" final was almost the last event of the whole agile2008 conference, and Michael Feathers and I were up against &lt;a href="http://submissions.agile2008.org/user/349"&gt;Lasse Koskela&lt;/a&gt; pairing with &lt;span class="HcCDpe"&gt;&lt;a href="http://www.linkedin.com/pub/5/629/964"&gt;Noah Jacobson&lt;/a&gt;. Our brief from &lt;a href="http://www.industriallogic.com/company/coaches/index.html"&gt;Joshua&lt;/a&gt; and &lt;a href="http://www.stelligent.com/content/view/5/18/"&gt;Jeff&lt;/a&gt; was "you have 8 minutes on stage. Impress us". This seemed a little vague to me, but when pressed, all they said was "you have 8 minutes. Impress us with your skills at Pairing, TDD, Refactoring and IDE expertise." So there.&lt;br /&gt;&lt;/span&gt;&lt;span class="HcCDpe"&gt;&lt;br /&gt;Yesterday (Thursday) was very intense, and I am exhausted. Geoff and I presented a 90 minute slot on &lt;a href="http://texttest.org"&gt;TextTest&lt;/a&gt; first thing in the morning. We get better every time we do it, and this was definitely the best yet. I ended the session with an extended demonstration of &lt;a href="http://codingdojo.org/cgi-bin/wiki.pl?KataBankOCR"&gt;KataBankOCR&lt;/a&gt; which I had been practicing loads, and went off without a hitch. Then at lunchtime we did "Programming with the stars" demonstrating JUseCase and TextTest (see my previous post) and directly after lunch Geoff did a 45 minute presentation of xUseCase. The room was packed and lots of people seemed interested. Afterwards Geoff and I spent some time chatting to important people from various agile tools companies.&lt;br /&gt;&lt;br /&gt;On top of all that it was the conference banquet yesterday evening. Good company, good food, generally a great evening. Today Michael was running a session first thing, I wanted to go to the keynote, and the upshot was we didn't manage to get together to plan what to do in the "Programming with the Stars" final until an hour before it started. For some inexplicable reason the python installation on my Vista machine stopped working and I couldn't get anything to run,  so we decided to use Michael's machine, (a mac)....&lt;br /&gt;&lt;br /&gt;ok ok enough with the excuses. It was a disaster. Eight minutes on stage isn't long enough to achieve much, especially when you are dog tired, unprepared, and nervous. They had warned us it would happen, but when after 4 minutes Jeff stopped us and asked the judges to give us some interim advice, I totally lost my train of thought. All I remember of the advice was Bob Martin telling us to act "perky", so the fatigue must have been showing. When we restarted for the remaining four minutes, the audience began calling out more or less helpful directives. By the end we had written about five lines of code and still had no tests running.&lt;br /&gt;&lt;br /&gt;The judges were surprisingly understanding and did give us a few points for our pairing skills (they can't have been for our coding, let's face it). Then Lasse and Noah came on stage and did a really slick, thoroughly prepared demonstration including testing with stubs, and a funny video clip. It was well done, and they deserved good marks.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="HcCDpe"&gt;So Michael and I didn't win "Programming with the Stars", but it was good fun, and we got to show off a little along the way. Now I just have to go back to being a normal programmer, pairing with other normal programmers, and Michael, well, I guess he continues to be a star...&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SKMhTRjVM3I/AAAAAAAAABM/_oqaZylRHLg/s1600-h/final+scores.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SKMhTRjVM3I/AAAAAAAAABM/_oqaZylRHLg/s320/final+scores.jpg" alt="" id="BLOGGER_PHOTO_ID_5234063806947472242" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-3826132454829327152?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://emilybache.blogspot.com/feeds/3826132454829327152/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5094340343398123932&amp;postID=3826132454829327152' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/3826132454829327152'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/3826132454829327152'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2008/08/final-meltdown.html' title='Final meltdown'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_AkG8Hw7A2Pw/SKMhT8qlm5I/AAAAAAAAABU/PfnciQeMuJU/s72-c/pairing+final.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-8564177234013611616</id><published>2008-08-07T19:56:00.005+02:00</published><updated>2008-08-09T22:02:44.443+02:00</updated><title type='text'>We pulled it off!</title><content type='html'>Today in "Programming with the Stars" our task was to do "Story Test Driven Development" (aka Acceptance Test Driven Development). With just 6 minutes on stage, this was a pretty tall order.&lt;br /&gt;&lt;br /&gt;Jeff and Joshua had suggested that we use tools like &lt;a href="http://fit.c2.com/"&gt;FIT&lt;/a&gt; or &lt;a href="http://fitnesse.org/"&gt;Fitnesse&lt;/a&gt; to create the story tests, but I thought it might be an idea to try using &lt;a href="http://texttest.org/"&gt;TextTest&lt;/a&gt;. I have an ancient Java application that I have used before to demonstrate how TextTest works together with &lt;a href="http://jusecase.sourceforge.net/"&gt;JUseCase&lt;/a&gt;, and I thought I might be able to do something with that.&lt;br /&gt;&lt;br /&gt;Michael was really cool about all this, which was great, because I thought it was quite a risk to move away from the well-known acceptance testing tools.&lt;br /&gt;&lt;br /&gt;The most important part about JUseCase is the way it helps you to interact with the customer (domain expert). So we thought it might be cool to bring in someone to act as the customer in the middle of our 6 minute slot. Geoff was the obvious choice since he wrote the tools, and knows how to write tests in them already.&lt;br /&gt;&lt;br /&gt;So in the middle of our performance, Geoff came up onto the stage for a couple of minutes. He helped us write a failing story test in JUseCase/TextTest, and then Micheal and I made the use case part of it work by adding a new widget. We didn't get the whole test passing, but it was a start.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_AkG8Hw7A2Pw/SJ3thtejL3I/AAAAAAAAABE/D_FppcO8-S8/s1600-h/judges.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_AkG8Hw7A2Pw/SJ3thtejL3I/AAAAAAAAABE/D_FppcO8-S8/s320/judges.jpg" alt="" id="BLOGGER_PHOTO_ID_5232599505473580914" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;The judges apparently loved this, we got the highest marks of the whole competition so far. Wahey! Now for the final tomorrow!&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_AkG8Hw7A2Pw/SJ3tPss7JgI/AAAAAAAAAA8/MlSylO28ZSk/s1600-h/scores+day+3.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_AkG8Hw7A2Pw/SJ3tPss7JgI/AAAAAAAAAA8/MlSylO28ZSk/s320/scores+day+3.jpg" alt="" id="BLOGGER_PHOTO_ID_5232599196027790850" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;(It has taken me some time to write this post. It feels like every time I sit down in the lobby to write it someone I have never seen before comes up to me and congratulates me or asks me if I've planned what to do in the final... this pleb-to-overnight-celebrity business is weird)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-8564177234013611616?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8564177234013611616'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/8564177234013611616'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2008/08/we-pulled-it-off.html' title='We pulled it off!'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_AkG8Hw7A2Pw/SJ3thtejL3I/AAAAAAAAABE/D_FppcO8-S8/s72-c/judges.jpg' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-273713095109093538</id><published>2008-08-07T13:04:00.004+02:00</published><updated>2008-08-09T21:09:17.616+02:00</updated><title type='text'>We scraped by with the help of the audience</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_AkG8Hw7A2Pw/SJ3qMQEJnGI/AAAAAAAAAA0/SEEzRGwOeH8/s1600-h/stars+day+2.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_AkG8Hw7A2Pw/SJ3qMQEJnGI/AAAAAAAAAA0/SEEzRGwOeH8/s320/stars+day+2.jpg" alt="" id="BLOGGER_PHOTO_ID_5232595838266088546" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;We were up last this time, rather than first, and I was so impressed with the three pairs who went before us, they all paired really well and seemed to achieve what they set out to do. &lt;a href="http://c2.com/cgi/wiki?JoshuaKerievsky"&gt;Joshua&lt;/a&gt; (one of the hosts) also decided to interview each pair just before they started coding ("so do you think you've got what it takes to go all the way?") and I had no idea what to say. On the TV shows I'm sure they coach the contestants on how to respond to that kind of question, but I was too busy worried about how I was going to remember to type enough semi-colons to say anything coherent...&lt;br /&gt;&lt;br /&gt;So, Michael produced some horrible looking C++ and led me through setting up a test so we could do "extract method" on a small portion of a hairy looking monster method. He introduced me to a technique called "sensing variable". Basically you write a test that calls the long hairy method, and in the middle of the method just after the part you want to extract, you introduce a "sensing variable" - you assign the result of what will be your extracted method to this global. Then from your test you can check what the global contains, and write an assertion for it. The next step is to do the extract method, and the test then checks that the "sensed" variable is still the same. This should ensure that you didn't make a mistake with the extract method, it is called, and returns the same as before.&lt;br /&gt;&lt;br /&gt;It's fairly simple really, but it's the kind of thing you wouldn't think of if it wasn't shown to you. In a language like C++, you need all the help you can get.&lt;br /&gt;&lt;br /&gt;Well, the judges had already awarded some very high marks to the other contestants, and our score was joint bottom, I think. Anyway, it went to audience vote between us and &lt;a href="http://www.jbrains.ca/"&gt;J.B. &lt;/a&gt;and Todd. They had done a teacher/pupil act similar to ours, on Eclipse wizardry rather than C++, and had raised considerably more laughs than we had. So I was a little surprised when we clearly got a louder cheer from the punters, and &lt;a href="http://c2.com/cgi/wiki?JeffNielsen"&gt;Jeff&lt;/a&gt; (the other host) announced we were through to the next round tomorrow!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-273713095109093538?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/273713095109093538'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/273713095109093538'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2008/08/we-scraped-by-with-help-of-audience.html' title='We scraped by with the help of the audience'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_AkG8Hw7A2Pw/SJ3qMQEJnGI/AAAAAAAAAA0/SEEzRGwOeH8/s72-c/stars+day+2.jpg' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-7478535811035521453</id><published>2008-08-05T23:40:00.008+02:00</published><updated>2008-08-19T11:03:57.025+02:00</updated><title type='text'>Onwards with the stars</title><content type='html'>&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_AkG8Hw7A2Pw/SJ3d_s48UaI/AAAAAAAAAAk/vyvIF9iF8WM/s1600-h/pairing+fizzbuzz.JPG"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://2.bp.blogspot.com/_AkG8Hw7A2Pw/SJ3d_s48UaI/AAAAAAAAAAk/vyvIF9iF8WM/s320/pairing+fizzbuzz.JPG" alt="" id="BLOGGER_PHOTO_ID_5232582428525875618" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://michaelfeathers.typepad.com/"&gt;Michael Feathers&lt;/a&gt; and I competed in the "Programming with the Stars" competition today, which was fun, if rather nerve racking. Our category was "TDD from scratch" and we chose to perform the &lt;a href="http://codingdojo.org/cgi-bin/wiki.pl?KataFizzBuzz"&gt;FizzBuzz Kata&lt;/a&gt; in python. We chose that because we thought it was simple enough we could do the whole thing in the time limit, just four minutes (!).&lt;br /&gt;&lt;br /&gt;It seemed to go smoothly, ping-pong programming, and this is the code we ended up with:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def fizzbuzz(max):&lt;br /&gt;return ["FizzBuzz" if i % 15 == 0&lt;br /&gt;    else "Buzz" if i % 5 == 0&lt;br /&gt;    else "Fizz" if i % 3 == 0&lt;br /&gt;    else i&lt;br /&gt;    for i in range(1, max+1)]&lt;br /&gt;&lt;br /&gt;assert fizzbuzz(1) == [1]&lt;br /&gt;assert fizzbuzz(2) == [1,2]&lt;br /&gt;assert fizzbuzz(3) == [1,2,"Fizz"]&lt;br /&gt;assert fizzbuzz(5) == [1,2,"Fizz", 4, "Buzz"]&lt;br /&gt;assert fizzbuzz(15)[-1:] == ["FizzBuzz"]&lt;br /&gt;&lt;br /&gt;print "\n".join(map(str, fizzbuzz(15)))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;As you can see we didn't bother with a testing framework of any kind, just a few assert statements, and the code that does the work is all one line, (although we put in some line breaks to make it readable).  I was pretty pleased we managed to do it without mishap.&lt;br /&gt;&lt;br /&gt;The judges turned out to be &lt;a href="http://blog.objectmentor.com/articles/category/uncle-bobs-blatherings"&gt;Bob Martin&lt;/a&gt;, &lt;a href="http://www.agilexp.com/rachel.php"&gt;Rachel Davies&lt;/a&gt; and &lt;a href="http://www.agile2007.org/agile2007/index.php%3Fpage=presenters%252F&amp;amp;id=928.html"&gt;Mike Hill,&lt;/a&gt; and they weren't actually as nasty to us as I feared. We got good marks from Rachel and Mike, (8/10 from both), and since Bob was mean to nearly everyone, his 5/10 was actually ok. Only one other pair scored more than us, which puts us through to the next round tomorrow. Our category is going to be "Refactoring", which is basically Michael's specialist subject, so hopefully we'll be able to come up with something good.&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_AkG8Hw7A2Pw/SJ3eboWFT-I/AAAAAAAAAAs/mvreHCNWpag/s1600-h/first+round+scores.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_AkG8Hw7A2Pw/SJ3eboWFT-I/AAAAAAAAAAs/mvreHCNWpag/s320/first+round+scores.jpg" alt="" id="BLOGGER_PHOTO_ID_5232582908342259682" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-7478535811035521453?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/7478535811035521453'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/7478535811035521453'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2008/08/onwards-with-stars.html' title='Onwards with the stars'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_AkG8Hw7A2Pw/SJ3d_s48UaI/AAAAAAAAAAk/vyvIF9iF8WM/s72-c/pairing+fizzbuzz.JPG' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-4404023180184680704</id><published>2008-08-02T04:04:00.006+02:00</published><updated>2008-08-09T21:20:41.367+02:00</updated><title type='text'>Geek meets Idol</title><content type='html'>I've just got to Toronto in advance of the &lt;a href="http://agile2008.org/"&gt;agile2008&lt;/a&gt; conference which starts on Monday, and I'm looking forward to it with great excitement and some trepidation. Until now it was the session that Geoff and I are running on Thursday that was claiming all my attention but now my head is also buzzing with another potential conference highlight.&lt;br /&gt;&lt;br /&gt;I've signed up as a contestant for the &lt;a href="http://www.agile2008.org/stage-developers.html"&gt;"Programming with the Stars"&lt;/a&gt; competition, and I got a mail today explaining that I will be performing live on stage with &lt;a href="http://www.michaelfeathers.com/"&gt;Micheal Feathers&lt;/a&gt; on Tuesday! We  will have exactly four minutes to impress the audience and the panel of judges with our impressive collaboration skills and amazing feats of coding. I've seen "Idol", I know what "panel of judges" means... we're going to be eaten alive! I just hope I can remember how to code after nearly a year at home with baby. Thankfully I am very confident that Michael Feathers not only knows how to code, but if I do manage to produce anything really dodgy, who better to sort me out than the author of &lt;a href="http://www.objectmentor.com/resources/articles/WorkingEffectivelyWithLegacyCode.pdf"&gt;"Working effectively with legacy code"&lt;/a&gt;?&lt;br /&gt;&lt;br /&gt;We are competing with five other pairs, it's a knockout competition, and the winners will be declared on Friday. Wish me luck!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-4404023180184680704?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/4404023180184680704'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/4404023180184680704'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2008/08/geek-meets-idol.html' title='Geek meets Idol'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-6893971960579548393</id><published>2008-06-13T13:09:00.004+02:00</published><updated>2008-08-21T21:02:27.908+02:00</updated><title type='text'>New Job</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_AkG8Hw7A2Pw/SK27h61sQKI/AAAAAAAAABc/n81pjXRzZ6E/s1600-h/IBS_java.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://3.bp.blogspot.com/_AkG8Hw7A2Pw/SK27h61sQKI/AAAAAAAAABc/n81pjXRzZ6E/s200/IBS_java.jpg" alt="" id="BLOGGER_PHOTO_ID_5237048133106286754" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;What do you have to do to get me to come and work for your company? Well, it seems a couple of free lunches and some good geeky conversation works pretty well. Of course, it helps if you're also offering me an exciting mix of software development work, high calibre colleagues and speaking engagements, all on my doorstep here in Gothenburg. So anyway, yesterday I signed on the dotted line for &lt;a href="http://www.ibs.net/se/kontakt/ibs-i-Sverige/ibs-java-solutions-ab.jsp"&gt;IBS JavaSolutions AB&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;JavaSolutions is responsible for the local branch of Sun's &lt;a href="http://www.javaforum.se/jf/index.jsp"&gt;JavaForum&lt;/a&gt;, which exists to support Java developers. There are regular meetings with talks and mingle, a bit like &lt;a href="http://groups.google.com/group/gothpy?hl=en"&gt;GothPy&lt;/a&gt; only on Java and without the interactive coding part. Hmm. I might have to do something about that :-) JavaSolutions also has a &lt;a href="http://jsolutions.se/"&gt;blog&lt;/a&gt; that employees are expected to contribute to. So I will have to devise some strategy for what to blog here and what to blog there.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;My first appearance in my new role will be at agile2008 in Toronto, Canada, at the beginning of August. I'll be leading a session about &lt;a href="http://www.agile2008.org/stage-tools.html"&gt;Automated Acceptance Testing&lt;/a&gt; with my husband, Geoff. During the rest of the conference I will probably be going to lots of stuff to do with agile development and testing in Java. Having spent the last 6 years working in python, I'll need to brush up my Java a little.&lt;br /&gt;&lt;br /&gt;So I'm looking forward to a fun autumn coding, learning stuff, and getting involved with GothPy and JavaForum. For the moment though, I plan to make the most of the Swedish summer together with two small children.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-6893971960579548393?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/6893971960579548393'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/6893971960579548393'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2008/06/new-job.html' title='New Job'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_AkG8Hw7A2Pw/SK27h61sQKI/AAAAAAAAABc/n81pjXRzZ6E/s72-c/IBS_java.jpg' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-1459512960051756899</id><published>2008-05-13T09:50:00.009+02:00</published><updated>2008-12-10T13:00:22.735+01:00</updated><title type='text'>GothPy</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_AkG8Hw7A2Pw/SCl1Y0lQ1XI/AAAAAAAAAAc/RjQ-__0NU0s/s1600-h/gothpy.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://3.bp.blogspot.com/_AkG8Hw7A2Pw/SCl1Y0lQ1XI/AAAAAAAAAAc/RjQ-__0NU0s/s320/gothpy.png" alt="" id="BLOGGER_PHOTO_ID_5199816314068194674" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Last night a group of eight python hackers were drawn into a darkened conference room on Odinsgatan "Odin's street" in order to exchange little-known information and to take part in obscure coding rituals. To open proceedings, Andrew Dalke shared deep insights into the enigmatic "stackless" python. Later on, fuelled by strong Swedish coffee and cucumber sandwiches, we together attempted the "BankOCR" Code Kata.  Everyone present contributed to further our art, and most took a turn working the somewhat arcane keyboard and IDE. By the end we had created a perfect although incomplete code chimera. Despite our considerable successes, it may need further work before any bank would consider taking on our design for their optical character recognition system.&lt;br /&gt;&lt;br /&gt;And now I must confess to the part I have played in this pythonic plot. It is the result of scheming between &lt;a href="http://dalkescientific.blogspot.com/"&gt;Andrew Dalke&lt;/a&gt;, &lt;a href="http://commentsarelies.blogspot.com/"&gt;Johan Lindberg&lt;/a&gt; and myself. We joined together a few weeks ago to make arrangements for the creation of this chapter of the python community. By some twist of fate, I was designated "temporär ordförande", or "acting high priest".&lt;br /&gt;&lt;br /&gt;Three hours of pythonic union notwithstanding, everyone present last night agreed that the experiment should be repeated. We look forward to the continuation of our assembly at the second Gothenburg Python User Group meeting sometime next month.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-1459512960051756899?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/1459512960051756899'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/1459512960051756899'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2008/05/gothpy.html' title='GothPy'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_AkG8Hw7A2Pw/SCl1Y0lQ1XI/AAAAAAAAAAc/RjQ-__0NU0s/s72-c/gothpy.png' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-7252166795743489777</id><published>2007-11-21T15:52:00.000+01:00</published><updated>2008-12-10T13:00:22.863+01:00</updated><title type='text'>New baby</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_AkG8Hw7A2Pw/R0RHXGsKx2I/AAAAAAAAAAU/BBZ-o2WhXxk/s1600-h/Emily+and+Miranda.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://1.bp.blogspot.com/_AkG8Hw7A2Pw/R0RHXGsKx2I/AAAAAAAAAAU/BBZ-o2WhXxk/s320/Emily+and+Miranda.jpg" alt="" id="BLOGGER_PHOTO_ID_5135307937367639906" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Miranda was born last Thursday, a healthy little girl 53cm long and weighing 3.77kg. Her big sister Karina, (now three and a half) and Geoff and I are all doing well.&lt;br /&gt;&lt;br /&gt;I hope to be at home with Miranda for about 6 months, so I don't expect to write much here for a while.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5094340343398123932-7252166795743489777?l=emilybache.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/7252166795743489777'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5094340343398123932/posts/default/7252166795743489777'/><link rel='alternate' type='text/html' href='http://emilybache.blogspot.com/2007/11/new-baby.html' title='New baby'/><author><name>Emily Bache</name><uri>http://www.blogger.com/profile/07321005413961705103</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://4.bp.blogspot.com/_AkG8Hw7A2Pw/SyFMoJGYiUI/AAAAAAAAADQ/o8lS950ayuA/S220/looking_up_cropped.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_AkG8Hw7A2Pw/R0RHXGsKx2I/AAAAAAAAAAU/BBZ-o2WhXxk/s72-c/Emily+and+Miranda.jpg' height='72' width='72'/></entry><entry><id>tag:blogger.com,1999:blog-5094340343398123932.post-1933907007959406838</id><published>2007-11-05T10:38:00.001+01:00</published><updated>2008-02-14T19:17:02.072+01:00</updated><title type='text'>Acceptance Test Driven Development screencast</title><content type='html'>&lt;span style="font-family:Arial,sans-serif;"&gt;Test Driven Development (TDD) is a way of programming where you start be specifying a (failing) test, write code until it passes, then refactor. Repeat. This technique has been hugely valuable and adopted widely since it was introduced to the world by &lt;a style="font-weight: bold;" href="http://www.amazon.com/Test-Driven-Development-Addison-Wesley-Signature/dp/0321146530"&gt;Kent Beck&lt;/a&gt; and others. The classic way to perform TDD is to specify the tests using the same programming language as the code under test, with the help of a little framework called xUnit. (Replace “x” with the language of choice). But how would TDD look if you used another tool instead of xUnit? Is there a way of capturing the advantages of the approach, but using tests that are easier to write and maintain?&lt;/span&gt; &lt;h2 class="western"&gt;&lt;span style="font-family:Arial,sans-serif;"&gt;About TDD with TextTest&lt;/span&gt;&lt;/h2&gt; &lt;p&gt;&lt;span style="font-family:Arial,sans-serif;"&gt;I begain using xUnit in 2000 and have been improving my skill at TDD ever since. Recently though I have been working less and less with xUnit tests, and more and more with using TextTest tests to drive development. This approach seems to preserve the original spirit of TDD, ie the tests are still driving development, but there are some differences and advantages. &lt;/span&gt; &lt;/p&gt; &lt;p&gt;&lt;span style="font-family:Arial,sans-serif;"&gt;When you use TextTest to drive development, your tests all end up being written in a representation that is separate from your code, ie a kind of Domain Specific Language (DSL). Your tests can be read and understood by anybody who understands the domain of the system under test, that is, they don't have to be able to read or write program code. You typically don't write new code when you write a new test, you just specify new desired program behaviour using this DSL. This makes it qu
