Last year I wrote the same test in 24 different ways as a little advent calendar for you to enjoy. This year I'm going to do something similar but also a little bit different. I'm going to start with a simple piece of code and then show how this code can be tested for thread safety in different ways. I think it's pretty common to think that thread safety is one of those things that are really hard to test and something you typically handle by good practices and code reviews. Very similar to logging in an application. Most people don't TDD their logs. But why not? Personally I've experienced situations where fixing a bug means making something thread safe or adding a better log message. When I do this I want a test to reproduce the bug and verify the fix. These tests are typically hard to write since the code was not written to be easily tested in regards to logging or thread safety. But it doesn't have to be that way. For example there is a testing framework that basically works with verifying logs (TextTest) and thread safety can absolutely be designed using TDD. Remember; if you think it is hard, you're probably doing something wrong. Let's decide after Christmas if test driving thread safety is better than the standard way of just adding it where you know it is needed.
The Pugh decision matrix is a is a tool to help you make decisions when you're trying to sort out what alternative is the best but they all have their pros and cons. It can also be used to help a group decide on a decision. The way it works is that you first list your alternatives. And you also want to have a default decision (usually doing nothing). List this across the top of a table as in this example.
Then you need to list the consequences and properties of your decision. List these on the side like this.
Each thing on the left then needs a weight, i.e. how important are they compared to each other.
Now it's time to measure the effect of each option. Your default option (if you have any) should be neutral in regards to all effects so put zeros in that column. Then write down if the other options is better or not than the reference (i.e. the default option). If it's better, put a one in that box and if it's worse put minus one there. If effect is comparable to the default option put a zero.
Now calculate the sum for each column and remember to use the weight for each row and you should have a decision on top. In this case go to bed. So how do you feel about that decision? If you think it's good you're done but if not you should revisit the weights and also try to find more attributes to put on the left side. Or maybe even a new option. Repeat until you get a decision you're ready to make.
So now you have another tool to make decisions. You don't want to use this for all your decisions but it can be useful at times.
I bet your answer to this question is; by giving a good tip. So what do you do if the service was bad? Here I predict two different answers, either you don't give a tip or you complain to the management of the restaurant. If don't tip I bet you leave the restaurant with a bad feeling about your visit. Also the waiter might not know that you were unhappy with the service and think you're just another cheap tourist with no manners. By complaining to management however you typically get a better experience since the restaurant will try to compensate in various ways. This leaves you with a good impression of the restaurant and the waiter knows what he did wrong and can correct the behavior. So in my opinion, talking to management or maybe even the waiter immediately is the best way to handle a bad experience. And by talking to management you also make sure the management knows one of the employees did something wrong. I'm sure they want to know.
But what about really good service? By giving a great tip you make the waiter happy but that's it. And you're not really enforcing specific good behaviors. And maybe even worse; management doesn't know that the waiter did a great job. Why not consider talking to management when you have a really good experience? I'll bet the waiter will be happy even though they'll probably wonder when you ask to speak with the manager. So if you want to be real nice you should probably tell the waiter that you want to talk to the manager and explain what a good job they've done.
And don't stop at restaurant visits. If somebody you work with do something great you should tell their boss too. I'll bet they both want the boss to know when the employee does something good. Don't just strike down on bad behaviors, enforce good behaviors too!
Assume that you have some important object that performs some important task. It may look something like this:
1: public class ImportantObject
3: public void ImportantMethod()
5: // Do things.
You've done everything right and created this object using BDD/TDD but one day everything changes. You need to make this object thread safe. The straight forward way to do this would look like this:
1: public class ImportantObject
3: private readonly object _lock = new object();
5: public void ImportantMethod()
9: // Do things.
But that is tricky to drive using specifications/tests, right? So over the next 24 days I'll show you a few ways to do this and by Christmas eve we should have something nice that works. And I'll be using xUnit.Net to write the specs/tests.
This time we did a new Kata - variant of poker hands. Instead of being so specific about the interface the user story we used for the Kata was simply; Given two five card hands I want to know which hand is the winner. We also choose to use the object calisthenics rules. The biggest benefit from not having a specified interface was that we did not have to do any string parsing and could design our interface as we wanted. That definitely felt like a kick start for an object calisthenics session. In the retrospect we also noted that in some cases it is good to bend the object calisthenics rules for the sake of progress with the Kata. Sometimes it is just not worth following the rules strictly. But each breach of the rules should be carefully considered since the purpose of the rules is to flush out changes you would normally never see.
The poker Kata is definitely an interesting one and I can see how the solution can take many different paths. Looking forward to try it again.
Today I got that feeling of how the use of one word, interpreted differently by different people result in misunderstandings. It was when I read this which IMHO is full of misunderstandings (including some of the comments). One example is that refactorings must break unit tests. No that can never happen because refactoring is about changing internal structure and design without changing the functionality. What is typically a pain with a bunch of unit tests in place is when you realize your design sucks and you want to rewrite something. The border when you go from refactor to rewrite may be gray but refactorings are always small and should never change the functionality (including the API). So when I say unit tests makes it easier for me to do refactorings that says nothing about when I need rewrite/change something.
There is a valid point that having unit tests means you have to change unit tests when you need to rewrite/change something. But if you've written your unit tests and code in a good way this impact should be small. Just because you feel something makes your life harder sometimes does not mean it is wrong, it might mean you're doing it wrong. And one way to prevent yourself from having to do these cumbersome rewritings is to make sure your code is very simple and that each entity only does one thing. Something that happens almost by itself if you're doing TDD... In my experience, every time I find a solution hard to test or hard to change because the tests breaks massively with a small change, it does not mean TDD is a bad idea. It has always meant that I should solve the problem in a different way where the code is easy to test and tests are not fragile.