wtorek, 30 kwietnia 2013

The mythical independency principle

We're having a hypothetical conversation with Joe, a developer in a Scrum team.

- Joe, how is your team doing in terms of unit tests?
- Very good! We have a developer in our team, Jack, who is proficient in writing good unit tests. He works with other developers to understand what they are planning to implement and then writes dozens of unit tests that they can use to validate their work.
- Wait a minute, so he's the only one in the team who writes unit tests?
- Yes. That's his specialization. Because of this, not only is he able to write really good, maintainable tests, but is also so productive that an average of five tests per day is for him a piece of cake.
- But the unit tests aren't a separate development activity, they are integral part of developing the right code!
- This is what I used read on the Internet, but the reality is what we are doing here is in accordance with the independency principle.
- Tell me more about it.
- We are avoiding the Initial Error. If one developer writes the tests and another writes the implementation we know that they compared one thing against the other. If the same person would write the test and the implementation we would risk misinterpreting the requirements and doing wrong test for wrong implementation, with the test still passing.
- You must be kidding me (...)

OK, I could go on like this for hours. Remember: do not let anybody talk you into the Initial Error or Independent Unit Testing story. Consider the following short example, as an argument against views like those Joe presents.

You've bought one of these fancy new TV sets that can be hanged on the wall. In order to mount it, you need to mount a handle onto the wall. When the handle is mounted, the rest is simple - the TV set is compatible with the handle and you just put it on the handle. The trouble is, it takes more than one screw to mount the handle to the wall. How are you going to mount the handle so that it is in perfectly horizontal position? Use tape measure, perhaps? Or even a laser device to set the screws precisely? I might be a good idea, but our old friend Joe comes along and denies you the use of a tape measure, not to mention the laser. He says:

I will bring here a friend of mine with tape measure and the laser and once you are finished with the mounting he will measure it precisely to independently see whether your understanding of the word "horizontal" is same as yours.


czwartek, 18 kwietnia 2013

Code Kata: text game from 1982

* * * W A R N I N G * * *
This Code Kata can seem very strange for people born in the nineties.

The goal is to implement a text-based game in which the player walks through dungeons in order to accomplish a task. The basic characteristics of an implementation are as follows:
  • the game generates random dungeons as a group of ROOMS and PATHS that join the ROOMS
  • the generation does not leave unreachable ROOMS
  • the user is presented with the information about the ROOM  they are in and the ROOMS reachable directly from the current ROOM
  • the user can move from the current ROOM to the directly reachable ROOMS by entering a command
This may seem very boring at first, but let's add some delighters:
  1. We do all of the implementation using "TDD, as if you meant it", of course
  2. Initially, the goal may be simply to get to a given ROOM
  3. Then, we may start adding attributes to ROOMS; a possible attribute is something that the user can collect, such as diamonds; N diamonds are placed in the dungeon and the game is finished when the user collects all of them; additional attributes can be used to describe the look a ROOM
  4. When that's done, we can refactor our implementation so that we do not use IF statements
  5. When that's done, we can refactor our implementation so that we do not use for/while loops
  6. We can work on the implementation a little bit more to get rid of excessive tabs (let's allow only up to two tabs in the body of a function, per Robert Martin's suggestion)
  7. We can get better by limiting the number of lines of a function (how about < 5 lines per function?)
  8. I'm guessing you did all of this with classes and objects; how would you do it with pure functions and no objects?

niedziela, 14 kwietnia 2013

Enjoyment of failed tests

We usually feel bad about failed tests. No surprise, as it simply means that something got wrong or that some tests have been invalidated by the recent change to the code. But can we feel good about a failed test? I think we can and here is why.

If I add a new tests for functionality that does not exist yet, it will either not compile or will fail. Watching it is not entirely upsetting experience, because the bright side of it is that we have evidence that the newly added test get at all executed. And it is good that it got executed, this is what we expected.

Another occasion when we could look at the failing tests with a smile is just after making a "very small change that should not break anything". And after this change we see a dozen of failed tests. Imagine doing this change without unit tests at all and keeping the belief that "it couldn't have really broken anything" for the next few months.

czwartek, 11 kwietnia 2013

Estimation, estimation... ehh

Steve McConnell gives an excellent overview of estimation methods in his great book "Software Estimation - Demystifying the Black Art". Probably, the most prominent part of the book is the Cone of Uncertainty.

On the other hand, we may spot from time to time the sentence "Estimation is waste". So, where's the Truth? Is it waste or not? And is estimation a fine skill to have? Here is my personal opinion:

Estimation is a Good Thing when we want to answer questions like:
  • how many months will pass until the project will have been finished? (if the unit is weeks, don't bother estimating)
  • can we do the work that is ahead of us with the staff the we have, or do we need more people / more teams in order to do it? How many do we need?
  • in order to satisfy customer needs, we can implement solution A, B or C; the solutions have different costs and different attributes in terms of scope, risk, maintenance, etc. Estimation of cost helps us with making the right choice
Estimation is unnecessary and is really pure waste when:
  • we have some work ahead of us that we need to undertake now, regardless of cost
  • we have ahead of us a chunk of a bigger effort, such as a small feature or a group of user stories and we feel this work will take us just several iterations, or less, to accomplish

The last bullet may be surprising at first, but let's honest about it: a team of N people is working on something. The team is asked for an effort estimate for several next user stories. Usually, the person asking the question imagines that the effort associated with this work is X. The development team is telling them this is twice as much or half of X. What serious decision can be made in this situation based on comparing X with 2*X? Providing any number in this case opens possibility for endless discussion. The best thing the team can do is to work on these user stories and do not waste their time arguing what the "real" effort estimate should be. Velocity is much important and tangible measure here, than effort.

wtorek, 9 kwietnia 2013

Python profiling for beginners

def bar(i):
    return i*i

def foo():
    for i in range(0,1000000):
        bar(i)


Let's try to use these two silly functions to do a profiling exercise.

First of all, we need to import cProfile. And then call: cProfile.run('foo()')

Output (from my laptop):
         1000004 function calls in 3.564 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    1.926    1.926    3.564    3.564 <pyshell#11>:1(foo)
  1000000    1.638    0.000    1.638    0.000 <pyshell#9>:1(bar)
        1    0.000    0.000    3.564    3.564 <string>:1(<module>)
        1    0.000    0.000    3.564    3.564 {built-in method exec}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}


At the first glance, it may look criptic, but: the total time is the time spent in a function excluding the time spent in callees. The cummulative time is the time spent in a function including the time spent in callees. Therefore, these two times are equal for bar function. ncalls and percall are self-explanatory.

But we can go further. I highly recommend trying out a GUI application that can read the cProfile output, such as RunSnakeRun from http://www.vrplumber.com/programming/runsnakerun For this simple case it'd be useless, but for much more complex call tree, it is of great help.

In order to use it, we need to run cProfile giving it the dump file name as the second argument:


cProfile.run('foo()', 'dump.txt')

poniedziałek, 8 kwietnia 2013

Velocity calculations

Let's starts with some facts and numbers. There is five of us in the team. In the last three iterations, we completed the scope worth of 9, 13 and 12 story points. We feel comfortable commiting 10-11 story points in an iteration and we never commit more than 12.

Case #1
If Harry joins our team next iteration, will you comfortably commit 12, on the average?
No. We may be delivering 12 from then on, but the reality is we don't know. It may be 12, but odds are it will be 14 or 8.

Case #2
If Jack leaves your team next iteration, will we comfortably commit about 8?
Not necessarily. We may still be able to deliver functionality worth of 10 story points. But that's not all. We are not sure how you will react to that, but without Jack we may be able to deliver 13 or 14 pretty easily.

Case #3
So you are telling me that arithmetic does not work in Scrum?
No, it's better to put it this way: arithmetic does work in general, but it does not properly describe a complex system, such as a Scrum team working on a project.
So what is the real message behind all of this?
The fact is that our team of five great engineers delivers about 11 story points each iteration. You cannot scale it, you should not theoretize about what the velocity would be, if we switched from 3 weeks to 4 weeks' iterations. You can't know what this number would be, if two of us left our side activities and focused only on the project. You can't know what this number would be, if all of us worked overtime We can commit to delivering 10-11 points each iteration and that's the only fact.