Showing posts with label TDD. Show all posts
Showing posts with label TDD. Show all posts

July 12, 2013

Confitura 2013 afterthoughts

Confitura, the biggest free-of-charge Java conference in Europe, took place on the 6th of July in Warsaw. TouK's presence was heavy, with 5 separate talks, all chosen in call for papers, no sponsored bullshit. We were sponsoring deck chairs during the conference, and beer on the after-party, though. Both were quite popular. Oh, and we had Bartek Zdanowski with TouK Lab, doing funny things with lights, Jenkins, and raspberry-pi.
Last year, together with Tomasz Przybysz, I had a talk about Groovy and Grails. This year I had the pleasure of presenting revised Test Driven Traps.

Now, this wasn't the same talk I had in Tallinn. In fact, I rewrote most of it, with three major changes.

While at first I was focused on three goals of TDD (security, design, feedback), I've noticed that I underestimate the value of communication. The funny thing is, I do use TDD in that manner frequently, it just didn't appear to me as very important. Which, as an afterthought, was a big mistake.

Perhaps the reason for it, is how people distinguish between TDD, BDD (Behaviour Driven Development) and ATDD (Acceptance Test-Driven Development). I use Spock most of the time, and Spock mixes all three approaches very well. To be quite honest, I've been mixing all three of them in every testing tool I ever had. Whether my tests looks more like BDD or ATDD (that is, had more emphasis on communication and specification) depends on the nature of the project, and the nature of my client. Technology is not a problem here. It just used to be more awkward to write down user stories as a tests, in languages which were not as flexible as Groovy.

I had a lot of success using tests as a communication tool. Both internally, with developers, including myself while returning to an old code base, and with external clients. But I also had some failures.

A few months ago, while doing a mobile banking project, I had a session with a domain expert. We were trying to get to the bottom of fees and pricing in a specific payment scenario. While we were siting and talking, I wrote down a simple specification
static Closure fixed = {BigDecimal value -> new FixedFeeAddedCalculator(value: value)}
static Closure percentage = {BigDecimal value -> new PercentageFeeCalculator(value: value)}

def "should calculate fees"() {
    given:
        biller.feeCalculator = billerFeeType.call(billerFee)
        biller.feesForChannels = [new FeePerChannel(channel: Channel.USSD, feeCalculator: channelFeeType.call(feeForChannel))]
        biller.feesForPrefixes = [new FeePerPrefix(msisdnPrefix: "123", feeCalculator: prefixFeeType.call(feeForPrefix))]
    when:
        BillerFees billerFees = biller.calculateFees(productPrice, "1234", Channel.USSD)
    then:
        billerFees.total + productPrice == totalMoneyPaid
        billerFees.feeForChannel == feeForChannelPaid
        billerFees.feeForPrefix == feeForPrefixPaid
    where:
        productPrice | feeForChannel | channelFeeType | feeForPrefix | prefixFeeType | billerFee | billerFeeType || totalMoneyPaid | feeForChannelPaid | feeForPrefixPaid | feeForBillerPaid
        100          | 7             | fixed          | 3            | fixed         | 10        | fixed         || 120            | 7                 | 3                | 10
        100          | 7             | percentage     | 3            | percentage    | 10        | percentage    || 120            | 7                 | 3                | 10
        123.4        | 10            | percentage     | 10           | percentage    | 10        | percentage    || 160.42         | 12.34             | 12.34            | 12.34
        123.45       | 10            | percentage     | 10           | percentage    | 10        | percentage    || 160.47         | 12.34             | 12.34            | 12.34
        123.45       | 10.05         | percentage     | 10.05        | percentage    | 10.05     | percentage    || 160.68         | 12.41             | 12.41            | 12.41
        100.99       | 0.99          | percentage     | 9.99         | percentage    | 0.09      | percentage    || 112.17         | 1                 | 10.09            | 1
        100.99       | 0             | percentage     | 0            | fixed         | 0.01      | percentage    || 101.00         | 0                 | 0                | 0.01
        10           | 0             | fixed          | 0            | fixed         | 100       | fixed         || 110.00         | 0                 | 0                | 100
}
Those static fields/closures are a little hack, so that I'm able to use something more readable in the 'where' clause, than a 'new' with the name of the class. After we confirmed, that it looks OK, but we don't really know whether this is accurate, I just copied the 'where' part with a little description, and sent it to the bank for confirmation. It looked pretty much like what the bank likes to send with their requirements. The expert was happy with this, I was happy with this, we've had that working for us before.

No word about fees and pricing has been heard from them since. And that's about six months now.
Which shows, that no matter how good your tools are, no matter how smart domain experts are, if you have a fundamental problem with communication with your client, you are doomed anyway. And working through a proxy with clients from another continent, all I have are problems in communication. The technology is simple and easy, compared to that.

But I digress, I do encourage you to think of tests as a communication tool. It's a blast when it works. And it does help a lot with keeping our domain knowledge up to date. Something requirement documents fail miserably to do.
The thing I do not know, is whether it is better to keep specifications and user stories separate from the rest of your tests or not. I've tried both approaches, but I don't have any conclusion yet.
I also added a few simple thought on domain setup, to my presentation. Most systems need some domain objects before even unit tests will run. You can create that step by step, calling each constructor in every test, but this soon becomes a DRY violation, and a pain in the ass, as the domain gets more complex. Not to mention refactoring problems. A simple factory helps, but doesn't change that much, so in my experience, the best way it to have your aggregate roots built in a single class, preferably using the same builders you use in production code (if you use any). This kind of setup definitely simplifies writing new tests, and is trivial to refactor.

But that's most useful for unit tests. For integration tests, there are three approaches I'm aware of. The first one is the 'go crazy, copy data from production'. Fortunately, this is possible only if you join an existing project, that had no tests before, so I'll just skip that, as I am inherently incompatible with such situations. The other two are more practical.

You can have an empty database (you can even create it on the fly), where every test has to provide the data (domain objects) required for itself, or you can have a prepopulated database, with a precise set of data, representing some sample domain objects, and have that reflected in your test code in form of static finals. In both approaches, a rollback (for transactional Dbs) or a manual clean-up (for everything else) keeps the database at the initial state.

Everybody seems to prefer an empty database. But a prepopulated database has two great advantages: it usually simplifies test setups, and may have big impact on test performance. Just a few weeks ago I switched one of our projects to use the prepopulated database, and saved 15 seconds of test time.
15 seconds may not look like much, but our integration tests run now in 1m30s. I've saved another 2 seconds, by removing an ugly sleep in one test, and I can save a few more seconds, by just not being wasteful.

And that brings me to the next change in my presentation. I've pointed out the importance of performance in TDD. You have 30 seconds for unit tests, before you loose the patience of a developer. Make your tests run more than 3 minutes, and devs will only run them before push to the repo. Make them even longer, and nobody's gonna care about tests anymore.

This is a single reason, why I thing GORM (Grails object-relational mapping) is not good enough for bigger projects. Grails use Active Record pattern, with a nifty mocking of database access methods via @Mock annotation, for unit tests. But with a complex domain and large aggregate roots, you get a heavy performance hit because of those annotations, and you end up with unit tests having half the speed of integration tests.

And that's pretty bad. I have ~900 unit tests running in about 2.5 minutes, on i7. And most of that is due to @Mock annotations. I could bring it down to less than 30 seconds, if I could mock those bastard database calls the normal way, but with active record, I would either have to do meta-programming, or go into mixins and categories. The first option is error-prone, the second very cumbersome. Both are probably inefficient. Comparing the amount of work required to make those unit tests fast, with mocking a simple repository interface, puts all the other benefits of Grails active record into question. My conclusion is to not use GORM, if I'm going for anything more than 300 man-days. Or not use Grails altogether.

Those conclusions are kind of obvious, I suppose. The reason why I don't see them used too often, is because people do not treat tests as a normal object (or functional) oriented code. That at least was my excuse for years and years, till I finally found out, this approach ends up in unmaintainable test code, that keeps you production code from ever being refactored as well.

And that's pretty much all of my presentation changes.


Confitura 2013 was a fantastic experience. I am usually scared shitless, when giving a talk at a conference. Somehow, maybe because I know a lot of people on the audience personally, I'm less scared in here. During the first half of this year, I gave 6 talks, led two workshops, helped organize Warsaw Java User Group, and wrote a book. Confitura was a great finish for that marathon. Now I need a summer break.

April 25, 2010

How fast is TDD exactly?

This is a true story, but for the sake of protecting some people, all the names and other details have been skipped or changed.

It starts on some Thursday with some new guy asking me “how much TDD is slowing down the programmer”? I don't have to think twice, my instant answer is: “programming with TDD is faster than programming without”. The guy doesn't believe me, some other SQL guy joins, doubting as well. I see no point in explaining it to people who don't touch OO code. They won't believe anyway, as it is counter-intuitive, if you have not experienced it yourself. But then, life has a funny way of giving you proofs right when you need them.

Next day I'm being asked to help put out some fire. There was a project running, two junior programmers were writing a small application, one of them doing the frontend, one doing the backend. No help from any senior or architect along the way. No code reviews, no pair programming, no nothing. Things, as expected, went terribly wrong, deadlines are weeks behind, the client is furious, and the software is not doing the stuff it's supposed to. Oh, and the backend programmer is already on the way to another continent. Some guys tried to debug the problem, but after six hours of getting nowhere, they gave up. A classic FUBAR example.

All right, I say. I know the frontend programmer, he's a good guy, I like doing pair programming with him. He doesn't know much about the other guy's code, but he knows the business domain. I'll help as much as I can. So we checks out the code, we setup the IDE and look inside the backend.

And the abbys looks back into us.

We stare into the Eye of Terror. A complete chaos, infested with chaos spawns. A terrible place to look at. Things can break your mind in here. It's twisted, it's evil and it's tragic. Pretty much every principle of OOP is violated. I could give it as an example of things that should not be, except I'd hurt the audience. There are no tests, there is a lot of faulty inheritance, with abstracts knowing about the children, there are hundreds of 'ifs', 'elses' and even some 'case-switches'. Hell, there are even misleading comments! There is a 'new' keyword in every constructor, no IoC, no interfaces, no nothing. No sane mind can leave this place intact.

We take a deep breath, and we try to find out where the problem might exactly be, but as we dig into this Big Ball of Mud, we realize that the problem we are facing is just a tip of an iceberg. The software does not guarantee anything, and as far as we can tell, there is a shitload of bugs all around the place. The main algorithm is so twisted that it takes us hours to understand it, while the purpose of the whole thing is dead simple.

Ok, so we've nailed down the possible problem. I'm suggesting writing a test to repeat the bug client had reported, and then fixing it, but the problem is, that the code, the way it is now, can only be tested end-to-end, so we have a lot of setup to do. My fellow programmer's mind is already burned out, he asks me to call it a day. He also says, that he'd rather rewrite the whole module instead of digging any further, because if he has to look again into this mess, he will never be normal again.

All right. I'm a bit more resistant, but I've not exhausted myself with debugging it before, and I've seen things, you people “wouldn't want to believe”.

So we set up an emergency pair programming session on Saturday. Now it's late Friday, and I'm heading for two parties I've planned to visit that night.

Saturday, 1pm. Sun is shining, weather is beautiful, girls are dancing in the middle of the town. I'm heading for the meeting. I'm expecting some heavy code crunching today, killing chaos monsters and stuff, but when I get there, the other guy says he couldn't sleep. Knowing the main purpose and the twisted algorithms, he has been working till 4am, writing everything from the scratch. Maybe not everything, but the main stuff anyway. He's been doing TDD, and though he has lost some benefits of discovering optimal interfaces/architecture, because he's been writing interface-first, then Red-Green-Refactor style, he got it quite well.

The code is doing about 80% of what it's supposed to do, test coverage is sky-high  (except for DTOs), there are some minor issues with ubiquitous language and so on, but for a single person junior programming this is a pretty sweet piece of code.

“Great job” I say, amazed by his late-night work. What should we do now?

So I help him write an acceptance test. We make it run all clean and green. We talk about the decisions he has made, I'm giving him advices and suggestions, but I can clearly see, that the guy has defeated an ugly dragon last night. He took his TDD spear, stormed the whole army of enemy warriors, killed them all and now he's on his way for the princess. Well done man, If I had a medal with me, I'd give it to you right now. You deserve a big thanks from all of the humanity for putting the beast down.

And he's saying, that if he ever had doubts about TDD, he doesn't have any now. He has really learned something that night, he gained a lot of experience points, and he has leveled up at least two times.

There is still some work to be done, but it's easy from now on. The client is safe and sound.

And now for the conclusion: it took him LESS time to rewrite the whole module, using TDD, that it took, to find one bug in the old application.

How's that for an answer?

PS: pictures are from www.studiocombo.pl

March 28, 2010

Winter Agile Tuning Review

I've found Winter Agile Tuning conference purely by accident, reading someone's blog. I have to admit that I've never heard about it before event though it was a second edition already. As I had ma chance to talk with, Jakub Dziwisz, one of the organizers, I understood why. Jakub didn't think about it as a country wide conference, more like an way to animate local Agile society. Well Jakub, I've counted at least four people from Warsaw and quite a bunch of speakers from abroad, so I believe you'll do well with changing your target audience expectations for the next edition.

Having an Agile conference somewhere nearby (I consider Cracow nearby as it's 3h by train from Warsaw) in a suitable time, is a good enough reason to go. After  I'd checked the website I knew, I cannot let it pass by. The program was interesting, with some well known names (i.e. Szczepan Faber, guy who wrote Mockito, the best mocking library in Java world), it was practically free of charge (50zł) and it was starting at 2pm on Saturday.

2PM! Do you know what that means? It means that you do not have to get up at 5am to catch a train or at 4am to get there by car. You don't have to be totally exhausted, intoxicating yourself with gallons of energy drinks. You don't have to get there a day before, wasting a perfectly sweet Friday night. It means that you get up at 8am, like normal people, you have enough time to eat lunch, and after the conference it's exactly the right moment to go to an afterparty.

I wish all the conferences would start at at least at noon.

Back to the event. I went there with a friend of mine, Tomasz Przybysz, one of not so many programmers I've met, that actually cares about the quality of his work, and as there were two tracks and two of us, we've decided to split and exchange the knowledge during breaks.

I've chosen the 'Craft' track while Tomasz went for the 'People'. That was a pretty good choice of mine and I only wish I could be on '10 tips that ScrumMasters should know...' by Nigel Baker. But let's start from the beginning.

Sweetest acceptance tests

The first lecture was given by Bartosz Bankowski and Szczepan Faber. At the last moment, they've changed the topic of the presentation from an enigmatic 'Be a VIP and rid your WIP' to 'Sweetest acceptance tests'. Can't say I was disappointed.  They took us through an example of working with Sweetest which is a sort of a plugin to a wiki that allows for a very fluid and direct translation between a wiki-defined set of acceptance requirements and automatic (junit) acceptance tests.

How does it work exactly? It's quite simple: you talk with your client, you both write his requirements in a wiki, the tool creates junit automatic acceptance tests for you. Here's a demo.

It fits very well with a TDD/BDD approach and allows you to have a bit more contact with the client, as the client can see on the wiki what his own acceptance requirements are and which are already implemented.

Lately, we've spent two days creating acceptance test scenarios for my client in doc format, which could allow him to formally say 'yes'. We've been doing it by checking his requirements (again), checking whether we have implemented them right, and writing all down.  The thing is, that since we do TDD/BDD, we already have all the tests that tell me whether his requirements are met, because we start implementing a new feature by writing a test for it. The main failure of the situation was that we've been writing those scenarios AFTER the whole project was implemented. Had we had them written down BEFORE, maybe even had them connected to unit tests, we'd be done before we've started.

That's what Sweetest is for.

Not that it's something totally new. If you're doing TDD you are already implementing client's requirements as tests (or at least you should start every feature with a single test for it, and then go down the implementation and Red-Green-Refactor line up to the point when it's fully working and is fully covered), but everything that helps with communication, well.. helps. And as in my example, can save you a few days writing docs.

I've been to another conference in Cracow last year where Szczepan was presenting Mockito framework. Just like the last time, his presentation was vivid, fluent, interesting and straight to the point. That's what makes a happy Panda.

Let them speak in their own language

Next was Konrad Pawlus 'Let them speak in their own language. How we enabled domain experts to build acceptances tests - case study'. Konrad shared his experience with developing Test Driven software for financial market. The clue was to allow domain experts, guys used to Excel, to verify software in a way that was familiar to them.

To do that Konrad (or his team) created a Visual Basic tool, that could convert xls files with example calculation to a scripting language, and then fire up this scripting language in a similar manner to junit tests. At the end, domain expert could verify everything down to the last number (and knowing that Excel actually creates a lot of errors with rounding that is very important), create new tests to check scenarios they never thought about before.

This is quite a cool way to bring customer into testing and have a robust feedback right away instead of getting a lot of bugs and change requests at the end. It's not something new as well, there are frameworks like FitNesse by Robert C. Martin that accomplish this, the thing was that for some clients/projects you need to have an exact Excel equivalence in calculations, which means simulating Excel's errors as well. Even those, the customer is not aware of. That's where it's nice to actually verify everything back with Excel.

Estimation of software complexity in Agile projects

After that came Jarosław Swierczek with his 'Estimation of software complexity in Agile projects'. Now that was quite cool and controversial lecture. Jarosław stated that SCRUM's poker planning is nothing more than an expert estimation, something that have also occurred to me some time before.

Don't be fooled by the 'expert' part, expert estimation is nothing more than calculations based on intuition, something which may work for experienced people and repeating projects, but often end up with pulling numbers out of your ass. Sure, the poker thing helps a lot, having other people verify your 'out-of-ass' calculations helps as well, but it's still intuition. We would wish that it's at least heavy wizardry but it's not. It's not science at all.

Jarosław Swierczek stated that according to some statistics a bit more than 70% of expert estimation is wrong, when wrong means more than 30% difference. Unfortunately I had no chance to ask him where did he have this percent from and I believe that this may not be true for poker planning (does intuition work better for a group?), so it all stays as anecdotal evidence.

Anyway, he was able to show us a nice, scientific formula for estimating complexity and time-cost. Things that were especially interesting:

- You need at least two years of historical data (estimations of complexity and time + the actual results) to be able to do anything more than 'pull numbers out of your ass'.

- You need to choose a formal method of calculating complexity and stick with it (event the Functional Point method is not that bad)

- Complexity has got NOTHING to do with the time it takes to finish something

- How much time it takes, depends your team's performance, which should be calculated from sprint to sprint, which is depending on stuff like technology/experience/distractions, and can actually be calculated by expert method ('my intuition tells me I'm gonna be super fast/slow because I have a lot/little experience in this technology')

Jarosław has got his own consulting company Aion www.aion.com.pl where they help other companies with estimating complex projects, so of course you should be wary about marketing bullshit, but what he presented made a lot of sense to me.

Journey through tests and prototypes

The fourth lecture was given by Piotr Trochim, a game developer (his current linked-in profile shows CD Projekt RED, the company behind 'The Witcher'). Piotr was talking about TDD in game development, a situation which is quite different to typical enterprise/b2b/Internet development in that you create a hell lot of prototypes of different ideas before actually deciding what you are going to put into the trunk of your repository.

Well, we (Internet/intranet software developers) actually create a few prototypes too, especially when changing the technology, so it applies as well to us.

Since creating well written prototype does not pay off in the long run and only slows down the prototyping, Piotr suggested this change is TDD cycle:

- First create a working prototype or a few prototypes (max 4h) if you need to have to choose between something. Don't worry about tests, do it as simple and fast as possible.

- Decide whether the idea/technology is fine to be used on production

- DELETE the prototype(s) completely (never commit the prototype as it is very badly written)

- Now write the solution again, using TDD and best practices

- When you're finished, create a tool to help monitor/debug the solution. This could be anything from stuff as simple as logging annotation (so you can turn logging into debug mode and see what happens), to state visualizers.

For me the most important part was to NEVER commit the prototype and always delete it completely. This is something I've seen way too often, when programmers commit a completely chaotic prototype just because it works and try to extend it later with very poor results. It usually ends in refactoring bigger/longer than actually writing the same stuff the proper way.

It was also interesting to note, that while Piotr is using C++ for development, he creates most of the prototypes in C#, as it's simply easier.

Yeah, I wouldn't like to return to C++. The expressiveness of this language simply sucks.

BDD and Ruby On Rails using Cucumber and Rspec

Last lecture was from Pawel Wilkosz about BDD and Ruby On Rails using Cucumber and Rspec. Frankly speaking I was tired, I don't work with Ruby and using TDD for more than last 4 years I didn't have much to learn in here.  That's where I'd rather be on 'People' track, where all the guests were having an Open Space kind of discussion.

And then there was an afterparty, but that's a completely different story.

You can find official pictures from the conference in here.
All pictures by Krzysztof Dorosz.