Archive for the ‘Coding Skills’ Category

A little while back I was back in Stockholm facilitating another Code Retreat, (see previous post), this time as part of Global Day of Code Retreat, (GDCR). (Take a look at Corey Haines’ site for loads of information about this global event that comprised meetings in over 90 cities worldwide, with over 2000 developers attending.)

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.

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.

In between coding sessions, I spent quite a lot of effort reminding people about simple design, SOLID principles, and how to do TDD (in terms of states and moves). Unfortunately I found people rarely wrote enough code for any of these ideas to really be applicable, and TDD wan’t always helping people.

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.

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 here (a work in progress, he has a screencast too).

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.

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 Valtech’s blog) This is great, but could we tweak the format to encourage even more learning?

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.

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 (here) and people thought it was much better than Ron Jeffries’ TDD solution to the same problem (here). 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

“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”
(from Peter Siebel’s book “Coders At Work”, an extract of which is available in his blog)

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.

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.

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.

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:

“the idea is just to drive through the entire problem in one blow, not to craft the perfect solution first time out.”
From “Extreme Programming Installed” by Jeffries, Anderson, Hendrickson, p41

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.

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.

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.

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 screencast of myself doing the Game of Life Kata in Python. (The code I end up with is also published, here). 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.

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.

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 before about Test Driven Development, (TDD). 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.


The basic idea
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.

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.

Tool Support
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).

Most unit test tools these days give you a nice diff even on multi-line strings. For example:

download
download (1)

Which is a failing text-based test using JUnit.

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.

My husband, Geoff Bache, has created a tool called “TextTest” 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 Jeppesen Systems, (Geoff works for them, and they support development), and I’ve used it too on various projects in other organizations.

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.

Little code per test
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.

Legacy code
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.


No help with your design
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.

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.

Log statements and readability
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.

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.

Text-Based tests are completed after the code
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.

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.

“Expert Reads Output” Antipattern
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.

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.

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.

Agile Tests Manage Behaviour
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. 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. 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.

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.

I think generally it leads to more “agile” tests. They can easily respond to changes in the business requirements.

Conclusions
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.

 

This weekend I was in Stockholm to facilitate a Code Retreat, organized by Peter Lind and sponsored by Valtech. 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 Peter’s blog post about it, he has a photo too).

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 what the facilitator should do. I think he’s given a great gift to the community, not just by inventing the format, but also by documenting it thorougly.  I’ve previously led various coding dojos and “clean code day” events, but code retreat is somewhat different in format, if not in aim.

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?

For the day in Stockholm, we followed the tried and tested formula for a code retreat that Corey has laid out. I spent about 20 minutes introducing the day, the aims and the coding problem (Conway’s Game of Life). 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:

– concentrate on writing really beautiful code so the language looks like it was made for the problem. *
– partition code at different levels of abstraction. **
– Think about TDD in terms of states and moves.
– do TDD as if you meant it
– concentrate on refactoring in very small steps

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.

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.

One of the things I offered in the last session was using the cyberdojo, 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.

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.

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.

Outside of this code retreat, I’ve been trying out the codersdojo client 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.

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.

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 🙂

* “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.
** G6: Code at Wrong Level of Abstraction – advice from “Clean Code” by Bob Martin.

The classic description of TDD that most people know is the 3 rules by Bob Martin. 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.

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:

TDDStatesMoves.001

I’d like to go through each state and some of the moves you can make in each.

intro coding dojo xp2011.016

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.

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.

intro coding dojo xp2011.017

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.

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.

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.

intro coding dojo xp2011.018

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!).

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.

intro coding dojo xp2011.019

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).

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.

We can move on when we’re happy the design of the code is good (for the test cases so far).

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.

The cycle begins again with the next coding task or the next dojo session.

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.

I took some of the code I talked about struggling with in my last post, 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.

What I did find though, was that it was quite hard to make the methods as short in Python as they were in Ruby. I could 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.

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.

I’ve just listened to this talk 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 Mote. (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).

Anyway, about half way through the talk, Gary shows this code example, first in Python:

'\n'.join(obj.name
    for obj in (
        repository.retrieve(id)
        for id in ids)
   if obj)

Then the equivalent code in Ruby:

ids.map do |id|
 repository.retrieve(id)
end.compact.map do |obj|
 obj.name
end.join('\n')

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:

objs = [repository.retrieve(id) for id in ids]
objs = filter(lambda x: x, objs)
names = [obj.name for obj in objs]
'\n'.join(names)

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.

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!

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 – GothPyCon. 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.

If issues like this interest you – design, refactoring and testing -, I really hope you will come along!