grzesiek-galezowski / tdd-ebook

Test-Driven Development - Extensive Tutorial. Open Source ebook
https://leanpub.com/tdd-ebook
Other
361 stars 57 forks source link

Update 220_Designing_for_composabiity_interfaces.md #23

Closed robi-y closed 9 years ago

robi-y commented 9 years ago

typos

grzesiek-galezowski commented 9 years ago

Many thanks!! Actually these were not typos, but my bad English :-D. Thank you again!

robi-y commented 9 years ago

Great, note that I'm also not an English speaker, so I would think of some English editor help. Cheers :+1:

On Tue, Jun 23, 2015 at 10:08 AM, Grzegorz Gałęzowski < notifications@github.com> wrote:

Many thanks!! Actually these were not typos, but my bad English :-D. Thank you again!

— Reply to this email directly or view it on GitHub https://github.com/grzesiek-galezowski/tdd-ebook/pull/23#issuecomment-114385883 .

robi-y commented 8 years ago

Hello Grzesiek, Congrat. for the latest book release. You mentioned you where lecturing in Krakau - are your lectures about TDD and testing? In case you have slides to share I might use that too. Thanks and regards, Reuven

On Tue, Jun 23, 2015 at 12:38 PM, Reuven Yagel - JCE robi@post.jce.ac.il wrote:

Great, note that I'm also not an English speaker, so I would think of some English editor help. Cheers :+1:

On Tue, Jun 23, 2015 at 10:08 AM, Grzegorz Gałęzowski < notifications@github.com> wrote:

Many thanks!! Actually these were not typos, but my bad English :-D. Thank you again!

— Reply to this email directly or view it on GitHub https://github.com/grzesiek-galezowski/tdd-ebook/pull/23#issuecomment-114385883 .

grzesiek-galezowski commented 8 years ago

Hi, Reuven,

The lectures are on object-oriented design, especially on the topic of code qualities and principles behind design patterns. Most of the lectures I give are in Polish, however, I have some in English. One with slides is a quickie on Devoxx. It's only 15 minutes long. Another is a screencast with Fizz Buzz kata I did some time ago in Java.

Other than that, I have some slides on the design approach leading to a need for mock objects. The video is in Polish and slides are in odp format, however, if you are interested in any, I can translate them for you.

Aside that, I have some slides for a two-day training on TDD, however, some time ago I stopped doing slide-based TDD trainings. Today, my TDD training is mostly based on randoris and live exercises. This is because I found explaining all the values, principles and practices in details has no value if one does not try TDD at all, which was usually the case. So nowadays, I stress getting people in front of a keyboard and having them try to code something using TDD.

martinmoene commented 8 years ago

Randori, i.e. free style ?

grzesiek-galezowski commented 8 years ago

More like the following: https://agilepainrelief.com/notesfromatooluser/2008/10/tdd-randori-session.html#.Vm-klOJAqnY http://dojo.wikidot.com/randori http://media.pragprog.com/titles/ebdojo/randori.pdf

By the way, I was not the one to pick this name :-)

In a one-shot course, I do three randoris and when I do it as a series, I do like five. They are:

  1. Fizz Buzz - to show triangulation and stress refactoring to abstractions. Many teams make the same mistake during refactoring which I can share if you're interested
  2. Message validation - to show mocks in action. The instruction is at: https://drive.google.com/file/d/0B0nzjz32viZmdzZTU2ZyZFJoX2c/view?usp=sharing In this exercise, I make attendees recreate a design using mocks and TDD. I explain to them that while mocks are usually used in a creative way, this exercise is being done primarily to let them experience how the flow of TDD with mocks feels like
  3. The third exercise is refactoring only. There is some bad code and a single characterization test written to protect it (sometimes I let people write this test). Java code is at: https://github.com/grzesiek-galezowski/TrainingExamples/tree/master/Java/alarms-randori C# code is at: https://github.com/grzesiek-galezowski/TrainingExamples/tree/master/TellDontAsk/AlarmsProcedural When randoris are done as a series of meetings, I do this twice - one time to let the participants try to solve this and the second time I guide them on where and how to use automated refactorings (so it's a form of a guided randori)
  4. LED Display: https://drive.google.com/file/d/0B0nzjz32viZmTGlhakFqT1ZqdHM/view?usp=sharing (requires libre office) This one is to show advanced triangulation and code rot, as I introduce new requirements that make the code worse and worse if it is not structured properly
  5. The last one is a state machine - I use a modified version of the Pacman ghost exercise: http://oddwiring.com/archive/websites/mndev/MSB/GD100/fsm.htm Usually, I do this two times as well - one time I tell the participants to test the whole machine as a black box, the second time I give them a diagram of the state pattern and tell them to test each part separately, mocking the rest. After the second session, I have them compare the approaches.
martinmoene commented 8 years ago

Wow, thanks.

Fizz Buzz - to show triangulation and stress refactoring to abstractions. Many teams make the same mistake during refactoring which I can share if you're interested.

If easy to share...

Have you seen Kevlin Henney's FizzBuzz Trek presentation (slides)?

robi-y commented 8 years ago

Thanks a lot (wasn't aware we are corresponding on a PR... so happy that other found it useful too :-)

grzesiek-galezowski commented 8 years ago

@martinmoene no, didn't see that, maybe I need to take a look. Sure, I can share the mistake, I think it will make it to the book one day. I watched a bit of the FizzBuzz Trek and it looks like Kevlin shows the same example as one of the first ones. Not sure yet what conclusions he draws from it.

Usually, when doing FizzBuzz, most of the teams ended up with a structure that looked like this (remember this is a variant of fizz buzz without printing, just a converter that turns int into a corresponding string):

public class FizzBuzzAlgorithm
{
  public string ApplyTo(int number)
  {
    if(number % 3 == 0 && number % 5 == 0)
    {
      return "FizzBuzz";
    }

    if(number % 3 == 0)
    {
      return "Fizz";
    }

    if(number % 5 == 0)
    {
      return "Buzz";
    }

    return number.ToString();
  }
}

Then I ask them to remove the duplication of the division conditions and of the strings Fizz, Buzz and FizzBuzz, as the first if is really a combination of fizz and buzz in both the predicates and generated values.

The way people often approach this is removing duplication using control flow. They end up with something like this:

public class FizzBuzzAlgorithm
{
  public string ApplyTo(int number)
  {
    string result = "";

    if(number % 3 == 0)
    {
      result += "Fizz";
    }

    if(number % 5 == 0)
    {
      result += "Buzz";
    }

    if(result != string.Empty)
    {
      return result;
    }

    return number.ToString();
  }
}

At first sight, it looks like the problem is solved - the duplication is removed. However, it introduces a confusing part of control flow:

if(result != string.Empty)
{
  return result;
}

This in no way resembles any domain rule. It is here only to bypass the fact, that the resulting string is not always a concatenation (what I have in mind is the return number.ToString(); part). Digging a bit more into the code, we can spot that the (result != string.Empty) is a disguised flag. We could as well write the whole code like this:

public class FizzBuzzAlgorithm
{
  public string ApplyTo(int number)
  {
    bool fizzOrBuzzFlag = false;
    string result = "";

    if(number % 3 == 0)
    {
      result += "Fizz";
      fizzOrBuzzFlag = true;
    }

    if(number % 5 == 0)
    {
      result += "Buzz";
      fizzOrBuzzFlag = true;
    }

    if(fizzOrBuzzFlag)
    {
      return result;
    }

    return number.ToString();
  }
}

This kind of programming is what I usually call "capture the flag" programming. It is a result of trying to remove duplication by taking advantage of the current flow of control instead of optimizing for common abstractions and clear statement of domain rules. This makes different rules tied to each other and the resulting code is more confusing and harder to refactor and change. Let's imagine, for example, how we would need to change the code if we added a requirement that e.g. in case a number is dividable by 7, the resulting string is "BuzzFizz"...

By the way, some people tend to even think that the version with concatenation is faster then the original. This is, of course, false, since in "FizzBuzz" case, the approach before removing duplication just returned a constant, while the second one does two string concatenations :-D

I see a lot of things like this in production code.

martinmoene commented 8 years ago

Thanks!

My take on FizzBuzz, despite the tests by no means arrived at via TDD.