Showing posts with label best practice. Show all posts
Showing posts with label best practice. Show all posts

19 August 2019

Y U NO TDD

Y U No TDDDuring this year's GeeCON the crew organised an Open Space evening. (An Open Space is a self-organising meeting where the agenda is created by the people attending.) I participated and ran a session on the question why we are not doing Test Driven Development. (Y U No Do TDD?) I am running TDD trainings from time to time and wanted to get more insight where people are stuck with TDD.

Context
As I said, an Open Space is self organising, and only people interested in TDD attended my session. This is a typical problem of communities of practice - only people interested in the topic attend - which results in us living in a bubble. For example long time TDD practitioner Thomas Sundberg and Shirish Padalkar, lead consultant at ThoughtWorks, participated in the discussion. Depending on the background of each individual participant, my original question was understood as:
  • Why are you not doing TDD on production work at all?
  • Why are you not doing TDD most of the time?
  • Why are you not doing TDD all the time?
I collected the reasons not to do TDD during the session which I want to share here. Text inside quotation marks, e.g. "hi" quotes exactly what people said. While the previous three questions are slightly different, the reasons seem to be similar. I grouped the answers. I did not want to contradict or debunk these answers and have to hold back not to do so ;-)

Prototyping
I am "experimenting with something", the "expected outcome is unclear" and "it's only a prototype". Obviously these are valid reasons as Spikes are outside of TDD. These answers usually coming up quickly makes me wonder if they are kind of excuses sometimes. Experimenting with new libraries and APIs is covered further down, so what are we experimenting with? I worked with many developers who would agree that the expected outcome of their current ticket was unclear - because they did not take the time to analyse the story and understand the solution they were supposed to build? Additionally most of our prototypes go to production after all, don't they ;-)

Time Pressure
Another reason - given by some of my clients too - is their need to go fast: "I need to go very fast", there is "no time for that" and I "believe to be faster without it". While they might be wrong in the long term I understand the effects of pressure. One person made it more explicit, while he has no strong deadline, he said "I have a huge backlog, I am stressed". Indeed when I am extremely stressed, I find it hard to maintain a structured approach, especially if a lot of task switching is involved. Besides the needed skill to apply TDD under high load, much discipline is required to endure pressure. In such situations Strong Opinions and Dogma might help.

Missing the Bigger Picture
I am just "writing a script for myself". Maybe there is no need for automated tests when writing a one time script for myself. TDD has a testing aspect - and it has many other aspects like designing software, fast feedback and working incrementally. TDD is not only about testing. Some people miss that or have only partial understanding of the benefits or do not care for these benefits at the moment. The opposite reason is "because I know how the class will look like". Yes TDD is about software design as I said before, and I would like my class to work, too. Some people only want the fast feedback, e.g. using REPL based development and "looking at UI is faster".

Missing Priority on Testing
When starting with TDD, the testing aspect is most visible. After all we have to write a reasonable test first. For teams and organisations with low or missing priority on testing, people are "looking down on testing" and I got answers like "testing is a culture thing", "testing is not a first class activity" and "I am not asked to create a test by my project manager". Indeed it is hard to keep following TDD if it is looked down upon and if there is no time for quality work.

Avoiding Context Switches
There is a certain amount of context switching involved in TDD. Similar to Edward de Bono's Six Thinking Hats, we have different states which we have to be mindful of and which call for different actions. George Dinwiddie created a TDD Hat to show that. Maybe this switching is "not natural for some people". "I don't want to interrupt creative design with verification" and "I prefer staying in building hat and not change to testing hat". Similar one participant said that it is "easy to write code, harder to write tests, so I do it afterwards". I understand and there is certainly an urge to jump into the code and get hacking. I rarely feel that urge and I enjoy pair programming using the Ping Pong style because it enforces the separation of states without any (inner) discussion.

Missing TDD Skills
This is obviously the largest area and there is nothing wrong with not knowing how to apply Test Driven Development: Honest people just say "I can't do it". Many are aware of this problem and seem to be disappointed with existing material and/or look for more material to study TDD: "It is not taught at universities", "there are no good books" and "I am missing real examples". I know from my own experience that TDD is not easy to learn and some people are "scared for life after a bad experience" with it. Now the best way to learn TDD is to have someone show you while pairing with you. Even if there is no pair programming in your workplace, you can still experience it during a Coding Dojo or Coderetreat. Short of that, I recommend Kent's Beck Test Driven Development by Example, which is a short and excellent introduction.

New Language or Library
When discussing TDD and unit testing with a client, he said I "don't know the target technology" and "React is a new technology for us". I had to laugh. To me this sounded like "I got a car and know how to drive forward, but am not able to drive backwards." On the other hand I live at the dead end of a road and I see drivers working really hard to avoid driving backwards. Are they not able to do it? So maybe stopping halfway in the game (of skill acquisition) is natural after all. When working with some new language or working with an unknown API, I specially rely on tests to support me, these are Learning Tests.

It's too hard to test
I agree some things are harder to test than others. "Android is hard to test", "Vaadin is hard to test" and "some libraries are hard to test". (I have not worked with Android or Vaadin, I quote people.) We might need to know more about design to decouple things. This is definitely true for legacy code, as "existing code is usually hard to test". Some people see the root cause, like in "I don't know how to manage boundaries". In such situations we need (to know) more tooling. We definitely "need more tooling to test the UI" as UI is traditionally considered hard to test from a TDD perspective. Still, Steve Freeman and Nat Pryce, authors of Growing Object-Oriented Software Guided by Tests, always start their TDD (outer) loop with an UI test. GOOS is a great book and I recommend reading it if you want to go deeper into TDD.

It's too simple to test
If there are things which are too hard to test, there must also be things which are too simple to test, right? It is "useless to test, it is so simple" and it "makes no sense to test it". Maybe a better description is that it is "unclear what is important to test". From a TDD perspective no such things exist and I guess these reasons arise from the test after process, when looking at each public method and thinking how to test it. Further excessive test isolation, see Solitary vs. Sociable Unit Tests, will cause that.

Barriers to TDD adoption
Here is Matt Wynne's summary of Barriers to TDD adoption from a session during Lean Agile Scotland 2016. I recommend checking out the Twitter thread as Matt added detail discussions on temptation of fast reward, permission and safety to learn, "the egotist" and other reasons not covered by me.

Barriers to TDD adoption #lascot16 (C) Matt Wynne
What about test-induced design damage?
Maybe the only real reason not to do TDD is to keep the design integrity of your system. This idea was started back in 2014 by David Heinemeier Hansson, also known as DHH, and led to the whole Is TDD Dead? debate. DHH said that when using TDD code sometimes suffers tremendous design damage to achieve two testing goals: Faster tests and easy-to-mock unit tested controllers and that the design integrity of the system is far more important than being able to test it any particular layer. It is ironic that this never comes up during any group discussion or team interview. Probably because it is an expert level reason. If you followed the debate, DHH knew TDD, he used it for some time and liked it. And then, only then, did he know when not to apply it.

29 May 2015

How to Organise Your Code Katas

If you read my blog you know that I like code katas. I did my first one back in 2004 after reading Kent Beck's Test Driven Development book. I was learning Ruby and Kent had recommended creating an xUnit implementation as an exercise to get to know a new language. I did not know it was a kata, I just developed my personal RUnit following the TDD principles.

Over the years I did similar exercises and started to perform formal katas somewhere in 2009/2010. I used them for personal practise and for demo, e.g. to show students how TDD could look like as part of my QA guest lecture. At my first Code Retreat I noticed that pairing on a code kata gave me more insights, so I looked for people who would spend some time with me practising, usually remotely.

Tip: Keep the source of your katas (or at least a record)
I do keep the code of my katas. Even at Code Retreats where you are supposed to delete your code, I manage to recover the source from local history or version control. When I use online tools like Cyber-Dojo, I write down the session id and come back later to recover the code. (I know I am a bad person. ;-)

At the time of writing, I have worked on more than 230 code katas resulting in almost 300 sessions of personal or paired practise. (In remote katas we sometimes tackle larger problems and then work more than one session on it.) I have a lot of kata sources and they are all over my hard-disc. I managed to collect some of them in dedicated repositories, one for each programming language, but many are in their own projects, or even mixed up with other code in early "learning" repositories. It is a mess. (Probably it does not matter, but it is a mess nevertheless.)

Shells, organized neatlyTip: Collect all your katas in one place
In her article about code katas, Iris Classon gave some practical advice regarding katas, e.g. to collect them all in one place, to be able to compare solutions. I really liked the idea and recently I found some time to collect my katas in one place - or so I thought.

Tip: Name your code katas consistently, even across languages
I faced some problems. First not all my katas followed the same naming conventions, e.g. prime_factors and primefactors were good enough for me, but not for a unified collection. Most of my katas were in version control and I did not want to rename or move large numbers of files, because I would lose history. (Again history did not matter for katas, especially as I never looked at it - but I was not able to drop practises I followed every day.)

Tip: Put your katas in kata-only repositories
I managed to extract katas out of mixed repositories using hg convert --filemap with a filemap of simple inclusions, preserving the whole history. I also fixed some inconsistent kata folders with a filemap of renames. But hg convert created new, unrelated repositories and I had to drop and recreate some of my repos.

My vision was to place the same katas regardless of language near one another, so I would be able to count and compare them. But I did not find a way to do that with all the different languages and keeping the code working. How would I combine Java, NodeJS, Ruby and Scala sources in a consistent way, other than separating them by source folder, which they already were. I failed to merge all my katas and looked for alternatives.

In the end I created a little script that would search my hard-disc for katas, normalise their names and collect them in a single place. I grouped the sources first by kata name and then by date. The programming language did not seem that important for a combined collection and ended up after the date, resulting in the name pattern [name of kata]/[ISO date] [- optional comment] ([programming language]). The whole collection looked like:
All Katas
|-- bankocr
|-- bowlinggame
    |-- 20120924 (Java)
        `-- BowlingTest.java
    |-- 20130307 (Scala)
        `-- BowlingGameSuite.scala
    |-- 20130414 (JavaScript)
        `-- BowlingGameSpec.js
    `-- ...
|-- fizzbuzz
`-- ...
Tip: Compare your katas
In the beginning I believed that the code of the kata, the final product, did not matter, that only the process of getting there, the practise, was important. That was the reason why people published kata-casts, because the final code did not represent much. Later I discovered that looking at code of a problem that I knew well, and reading comments regarding that code, also had value. So I searched the web for source code and recordings of the katas I had done. I planned to look at them and to compare them with my solutions and to learn from them even more. Of course I never had the time to do this.

But now I can see all exercises I ever did at one glance. Now I have the opportunity to compare my solutions across time and languages. This is the perfect time to include my bookmarks of katas as well. This is going to be interesting because I never had a second look at my katas before.

14 October 2010

Digressions

Two months ago I got a brand new Android phone from my employer. I asked for it to play around and get used to Android development and bingo - it was here :-) This is a major event compared to my prior experiences with employers. But I'm digressing.

A Resolution for 2009So I've been using it for two months. I'm still not sure if it's good for people that just want to talk or text, but it's definitely great to access the internet on the go. So I started catching up with my backlog of articles in Google Reader. Currently I'm back in January 2010, so there is hope that the folder with articles to read will be empty some day. (Alas, it's just one of four, so it looks like I will stay busy for some more months.)

Today I came across Ted Neward's Predictions. I like to read Ted's posts because he doesn't take himself too serious. I especially enjoyed his busy Java developer's guide to Scala two years ago, but I'm digressing again. In his predictions he talked about different technologies and some well known companies. I will not repost his post, but he made some quite sarcastic and funny remarks that I need to share.
  • "Cloud" will become the next "ESB" or "SOA", in that it will be something that everybody will talk about, but few will understand and even fewer will do anything with. --- Well another one in the list of useless buzzwords that lacks a clear definition. Last year I was working on some enterprise integration project and the Czech bank was using AquaLogic ESB. I asked our rock star enterprise architects what exactly defines an ESB. They were not able to give a proper answer. According to the German Wikipedia the term ESB was defined by Gartner in 2002. So it's no wonder that ESB is not proper defined.

  • Being "REST"ful will equate to "I did it myself!"

  • Agile has become another adjective meaning "best practices", and as such, has essentially lost its meaning. --- What does best practice mean anyway? Most likely it is a cookbook and a collection of things that work. According to Andy Hunt best practices are for people that need guidelines. But these guidelines never capture the whole context of the problem. And Ted really hates best practices.

  • Try this: walk into a functional language forum, and ask what a monad is. Nobody yet has been able to produce an answer that doesn't involve math theory, or that does involve a practical domain-object-based example. In fact, nobody has really said why (or if) monads are even still useful. --- When diving into Scala two years ago, I tried to figure out monads. James Iry did a decent job explaining what they do, but I still have no idea what they are or why I should use them. (But probably that's different for pure languages like Haskell.)
How true. Ted, you are great.