lördag 28 april 2012

SharePoint, TDD, code monkeys and Agile

I have been reading Eric Shupps (albeit old) thoughts on the matter of SharePoint and TDD as well as Andrew Woodwards series of articles about the subject. Thought I would share a few words on the subject since I find it truly fascinating.

First up though. There is a difference between unit testing and TDD. I don't subscribe do a single school or train of thought about TDD. In my head TDD is a way to use unit testing to achieve greater results then by writing tests to validate code already written. TDD can drive design, test should be written and fail before code is written. Unless you are doing exploratory coding (ie when you are not sure what the test case is. It's a good point to try and think more about what you are doing before diving into the code since this can lead you down a pretty deep rabbit hole).

While Eric gives a good summary of what he means with TDD and where it stems from I have a few issues that popped into my mind while reading his article that I want to study in more depth.

Pair programming

First a few notes about pair programming (which doesn't really have a 1:1 mapping to TDD but is still an interesting topic).

In the blog post mentioned above he quickly concludes the following regarding pair programming:

"First of all, companies quickly discovered that pair-programming is a tremendously inefficient process." [...] "putting two of them [developers] on the same coding task is rarely cost-effective".

And then he ends with:

"Finally, it has been my personal experience that two coders working side-by-side tend to engage in more discussion about how things should be done in a perfect world than they do actually writing any code. They are by their nature perfectionists, and each always wants to prove that they have the best and most innovative ideas."

I was a bit sad to not see any references to these claims beyond his own experiences, in general I find that it's quite hard to find any sources at all on the subject. 

The way that the Eric poses the problem it is more a problem of communication and ego, not the pair programming paradigm in my humble opinion. Angela Harms has done a really great talk about this subject at the Ruby Midwest conference as well as an appearance on the Ruby Rogues podcast

If I attempt to summarize her words bluntly she says that for pair programming to function you need to check your ego at the door. The process is not about finding the perfect solution, it's about figuring out how to move forward and combining brainpower. Being able to admit that you don't understand what is going on and that you don't know everything is step one in this process. The real point of pair programming and Agile in general is to bring problems to the surface early. If noone is admitting that the problems exists, you can't do anything about it.

Another great resource that should is the talk from Agile Roots named What We Learned in 8829 Hours of Pair Programming.

TDD Zealotry

"Developers who become adherents to the new programming religion of the moment quickly slip into the fatal trap of assuming, despite all evidence to the contrary, that their methodology makes the code they create bulletproof"

This is true and also the main point of Eric's post. A lot of my writing below could be considered nitpicking, but I like to see it more as a way to show what I object to.

"You can see this in action by listening to any TDD adherent as they bandy about phrases like "100% code coverage", "atomic validation", "no debugging" and other such phrases designed to reinforce their own misguided sense of infallibility."

In my humble opinion code coverage is not and should not be an end goal. 100 % code coverage can even be a bad thing. It's interesting thought, the whole time I was reading Eric's article I couldn't stop thinking about how different our views on TDD and it's evangelists is. Perhaps this has something to do with that I got into TDD from the ruby/rails community where TDD/BDD is the norm and the debate is around the concept of TDD and how it should be applied. In my mind there is no one true way of doing TDD.

It's perhaps fitting that the greatest battle is fought inside the ranks of the same militia? (Follow the link-trail around DHH's "Testing like the TSA" article to see what I mean).

"It is vitally important to emphasize that unit testing is only one part of the overall quality assurance lifecycle."

This actually neatly summarizes the whole argument.

Quality and the process of software development

Eric then goes on to reason about unit tests in relation to functional requirements and that writing the minimum amount of code is what give us unpredictable bugs among other things that I found hard to see the reasoning behind. But then he states that: 

"I'm sorry to point out this blatantly obvious fact but developers don't really know squat about quality and even less about how to achieve it."

This made me very upset, not at Eric but at the state of the developer in the world as seen from the eyes of some non-developers. The notion of developers as code monkeys that only care about solving the immediate problem at hand, system or users be damned always upsets me. If your developers have this approach to writing software, everything Eric is talking about up to this point is true and makes sense (although it's not related to the TDD practice).

Granted, there are lots of developers in the world who sees it as a job and nothing more. But why shouldn't developers care about quality? Do we not want developers who care about quality? The customers problem we are solving? The value we are bringing to the customers business? Why would we not want to promote something that makes developers think about these questions?

Interestingly enough this is the point he is actually arguing in the article. The way we are working is broken, the way we conduct software engineering is broken. But somehow he manages to wrestle this into an argument that unit testing only proves that an individual part work but not that it will work as a part of a holistic system. True, this is not what unit tests are about, this is functional and integration testing.

TDD, more than code and unit tests

The thing about TDD is this, it provides more value then just testing the individual parts. The tests that come out of the process are a great compliment to documentation. Especially if the TDD practice of red, green, refactor has been implemented.

Imagine having a test suite with passing tests, when you change something you can see if the unit still works as intended, even after the code has been changed. As long as we have passing tests we have documentation that actually represents the current snapshot of the system. This is what allows TDD to drive design, when we decouple and abstract things we can be confident that the unit still behaves as intended. This only holds true if the unit tests actually test our logic, not just snippets here and there.

Tests are a great supplement to documentation, if the documentation is out of date we can check the tests to see how it differs, or if we read the tests first the documentation will make more sense since we can see what approach the developer who wrote the code took to the problem.

Real testers are great for really bringing the wrath of god (synonym to putting the system in the hands of a user) upon our system. But what do testers really know about the details of the code? Why should they care? Other developers care about what other developers have done.

Understanding how the system works as a whole is crucial to the successful launch of a system. Although I don't see anyone arguing otherwise.

It's also worth noting that while TDD does drive a certain style of design (that can go overboard just as Eric talks about) it's always up to developers/architects to be pragmatic and ensure that the design still has a point and brings value. 

Agile, not just a word

Eric do strike a good point that I would like to expand somewhat on (this is where I go on a side-track):

"TDD assumes that everyone in the development lifecycle both understands and is willing to assume the overhead of enforcing the restrictions of the methodology"

The key words in this quote is understands and is willing. Can you see where I am going with this?

It is my firm belief that Agile in general wont work when people don't care or understand. When you don't care you are not going to put in more effort then you have to to keep your job. When you don't understand you rely on someone guiding you and telling you exactly what to do.

Of course pair programming, TDD or Agile in wont work when you don't have the people you need. Agile does not work in an 18:th century coal mine or the corporation where you have to sign a sheet of paper to go the bathroom.

I also object to the general thinking that we should only meet the required functional requirements. This kind of thinking assumes that the software development life-cycle is based around:
Order it from company X -> Create it -> Launch it -> Use it -> Throw it away -> Repeat with company Y, return to X when everyone has forgotten what they did last time.

The process should be:
Need it -> Think about it -> Build the minimum that you need -> Use it -> Think about it -> Build the next minimum you need -> Think about it

Testing SharePoint

Back to the point at hand.

Here I present a few simple rules for using TDD or even straight up unit testing within a SharePoint project:
  1. Don't over-test the SharePoint API, test your logic

    Don't test the retrieval of SPListItems from the Contracts list. Extract into ContractItem's and test those. Focus on core logic and have faith that Microsoft has tested it's internal API's. Mock where needed, not everywhere.
  2. Don't measure code coverage.

    Code coverage is arbitrary and says nothing about what we are testing or why we are testing it.
  3. At least test the happy path.

    If I give this method this input, does it work?
  4. Write enough tests so that you feel comfortable with the code you wrote.

    We do after all think about what is going to happen when we write code, let's put the assumptions into tests. I dare anyone to write a non trivial regexp and know if it works without testing it.
  5. Remember the refactor in Red, green, refactor.

    The first passing test is not a signal to move on to the next piece of code. It's the signal to refactor the code that you just wrote.
The list is quite far from what a purist TDD evangelist would describe. But I am pragmatic, and I think that until better tools are provided that allows us to do true TDD, we should stay in this kind of grey area of TDD.

I also agree with Eric about the fact that TDD isn't a silver bullet to anything, especially not quality. To write good code you have to know how to write good code. You learn how to write good code by writing code and learning from your seniors. This however raises the point that using TDD by itself is pointless unless you take other Agile practices to heart. TDD must be combined with things like code reviews, pair programming and the philosophy of continuous improvement to create good coders.

Talking about TDD without talking about the software philosophy surrounding it is like talking about how to reduce the price of wood without knowing what your building.

Now go read part 2 where Eric clearly has had time to reflect and formulate his points in greater detail.

1 kommentar:

  1. Great post! I don't know much about sharepoint, but I will comment based on my experiences of working with quality in consumer software.

    I think you touched on a very important point here. No quality process makes you "bulletproof". The best you can do is reduce your level of risk by adding "safe guards".

    Of course there comes a point where the costs start to outweigh the benefits. But I feel if you are being responsible, you need at least the following:

    1) Integration tests
    2) Automated acceptance tests
    3) Manual exploratory testing

    This gives you a lot of advantages:
    a) Find obvious issues quickly
    b) Make sure the system works in the real world, and that what has worked in the past continues to do so. From the users perspective!
    c) Finding things you would not otherwise have found, and learning what automated tests you still need to build.

    Also, manual testers are important because they can feedback on the "feeling" of what you build. They can say when they were confused or annoyed... And this dialogue is what enables you to turn working software in to great software.

    Final point, I think it's really important at the end of the day that we remember, working software is what we are after, so, making sure it works for the user is priority 1.

    I have a talk about setting up automated regression testing, not very in depth, more of an overview... But I thought I would include it anyway: