Open SAP Course: Unit Testing: Week Two : TDD
The artist known as “Test Driven Development” has been arrested and sentenced to death by the ABAP police. Read on for the gory details of the trial.
The jury are being asked if Test Driven Development is the answer to all our prayers, or is it a load of old nonsense, the ravings of madmen, the lowest of the low, not worth spitting at if it crawled past you in the street?
That jury is out, which is most likely why SAP made “Test Driven Development” the second installment in their Open SAP Course about unit testing.
Now is the Table of our Contents, made glorious summer by this Son of York:-
- The Missing Link
- Emperor with No Clothes Jumps off a Bridge
- Running Around in Circles
- SAP say it’s good – so it must be good?
- I say it’s good – so it must be good?
- HFSD say it’s good – so it must be good?
- Re-Inventing the Wheel, but this time it is SQUARE
- Squaring the Circular Wheel
- What I Had for Breakfast
- Dancing with you in the Summary Rain
Here we go Looby Loo!
The Missing Link
The first week in the Open SAP course was an introduction to unit testing as a concept. Love it or hate it, it caused a lot of discussion on the SCN which is a positive thing.
Here is a link to my blog about the first week, where I am broadly positive:-
Here is a link to a blog by Jelena on the same subject, she is a lot more sceptical:-
Emperor with No Clothes Jumps off a Bridge
Jelena is struggling to see the practical value in unit testing as it does not seem to relate to common SAP programming tasks like writing ALV reports. Many people have levelled the exact same argument as to why bother writing an ALV report in an OO way i.e. you appear to be solving a problem that does not exist, and taking a lot of extra effort to do so.
She wonders if unit testing is just an Emperor with No Clothes, despite a large number of TDD type advocates (like me) insisting he is fully clothed. Once again this description has often been applied to Robert Martin, author of “Clean Code” and inventor of the SOLID principles. Luckily when I look at him he appears to be wearing clothes, which is probably a good thing. In the latest Marvel film “Ragnarok” the Mighty Thor has a really bad experience with the Incredible Hulk in this regard.
Jelena – quite rightly – bemoans the lack of practical examples of real world situations where unit testing is supposed to help. All the examples on the internet are incredibly simple, and do not appear to relate to anything your average ABAP developer does in their day to day work. Some of the examples are related to SFLIGHT or even about Monsters! How ridiculous can you get! The moral is clear – all you TDD evangelists – stop using SFLIGHT examples.
Some people – and I have been guilty of this sin – use the “everyone else does it” argument as in “everyone else thinks the world is flat, so it must be flat”.
I have found that a large number of developers from 1944 (earliest example of TDD I have found) to date who do not program in ABAP are proponents of Test Driven Development, whereas in ABAP the take up is precisely zero.
I will come back to this later on but suffice it to say that whilst the take up of unit testing in ABAP world is very low indeed, the take up of Test Driven development is ZERO. I have never heard any ABAP developer say they do it for real. Even I have never done it, I am constantly claiming I am going to start doing it “soon” probably just after I invent Nuclear Fusion.
Jelena uses an argument my mother often used as in:-
Mother: Why did you do that?
Child: Billy Smith did it.
Mother: If Billy Smith jumped off a bridge, would you do it as well?
Then of course, the next week if Billy Smith did something she approved of which I didn’t do she (my mother, not Jelena) would use the exact reverse argument on me, but just let that go. That’s what mothers do, and they are always right, as one learns quite quickly growing up.
Anyway, getting back on track, just because the vast majority of developers are jumping off the TDD Bridge like a horde of lemmings, and not one solitary ABAP person is, the implication is that they are all raving mad, and the only sanity is to be found in SAP world, which we can clearly see is not flat, where the others cannot.
It is going to get even worse next week, when the SAP course instructors start talking about pair programming, but let’s ignore that for now and focus on the anomaly of virtually 100% adoption in non-ABAP languages, and 0% adoption in ABAP.
In order to try and make sense of this disparity, let us explain to the jury what TDD is all about, why certain people think it is good (the defence), a very good argument as to why it is no great shakes (the prosecution), and my attempt to square the circle (summing up).
Running Around in Circles
I think it might even be time to mention the course I am supposed to be blogging about. This week’s course was a lot shorter than the first, and focused on describing the process of Test Driven Development.
The SAP presenter’s description of TT was, not surprisingly, exactly the same as I had read in books like “Clean Code” and which I have tried to describe in my blogs.
TDD follows a short cycle – five to fifteen minutes – in which you do the following steps again and again.
Write a test for whatever functionality you are about to add, but have not added yet. That test will fail (because you have not added that functionality yet) and you will even get a syntax error hence this step is called the RED step.
Write the absolute minimum amount of production code that will make that unit test past i.e. write some code, run the unit tests, and keep going till the test passes. You would think this would be the GREEN and indeed it is, but that does not mean we are finished.
Now improve the code you have written i.e. refactor it, which is improving the code whilst keeping the functionality the same. This is the BLUE step. You will know if you have broken the functionality because the new test that just passed will start to fail.
In other words – define what “this” is / make the code to do “this” work / make the code to do “this” good – in that order. As we will see later this thought process is not actually a staggeringly new mind blowing concept.
So this is good is it?
Yes, lots of people say so.
Oh yes – what sort of people, and why do they say it’s good?
Let’s have a look. If TDD is being sentenced to death then it is time to call the witnesses for the defence.
SAP say it’s good – so it must be good?
As might be imagined the presenters of a course aimed at teaching Test Driven Development took the position that TDD was a good thing. It would have been most surprising if they had spent several eighteen minute videos jumping up and down and screaming four letter insults at the concept, and imploring the audience not to touch it with a ten foot bargepole. Though it would have been quite funny. Maybe I should do a training course on Web Dynpro in that vein.
Sadly most of the arguments in favour of TDD were of the “it is good because it is” variety.
What they stressed – and rightly so – was to break down the big requirements into the tiny requirements needed to get the big requirement working. Instead of writing a method that does fifteen different things, have fifteen methods doing one thing each, and then a “mother” method which calls them all one by one, like a duck with all its babies walking I a straight line behind it.
That way you write a test for each of the fifteen things one by one, which means the red/green/blue cycle does not take all day, and it also enforces good practice which is – one method does one thing only.
Another one I noted down that was new to me is that TDD enforces the “YAGNI” principle. That stands for “You Ain’t Gonna Need It” and refers to programmer’s propensity to add all sorts of fancy bells and whistles and functionality that has not been asked for “just in case”. With TDD you are literally forced to write only the code you need to make the test pass and since those tests should mirror the specification you should not really have any tests for things not in the specification.
The other point they made was that with the new ABAP constructs you can write the unit tests in a very compact way (not that this has anything to do with TDD directly). For example you can use the VALUE construct to define an internal table of expected results, without actually having to define and fill the internal table first.
Oh dear – that is all the notes I had made from their talk. That doesn’t sound like compelling evidence so far does it? Oh well, I will just have to call my second witness for the defence – myself!
I say it’s good – so it must be good?
Thank you so much for asking me! It is a pleasure to be here!
I am not going to give away my primary argument in favour of TDD just yet, I need it later, so I will present my secondary argument, which revolves around the concept of “executable specifications”.
Now in my experience 99.99% of developers hate writing documentation, so it is fairly likely you will come across such a developer sooner or later. We don’t want to write documentation – we want to write code – we don’t even want to write documentation INSIDE code, which is why I think efforts like ABAPDOC won’t get that much traction. Thus the idea of self-documenting code is very appealing. Usually this takes the form of meaningful variable and method names.
Many years back I had a great big specification for the customer open item matching program that I had to write (which beats the pants off F-32). I did everything procedurally in those days. However since I did have a good detailed specification – which is a rarity I can tell you, usually they (specifications) are on the back of a post-it note – I thought to myself that after the event i.e. after I had written the entire program and was thinking about sending it to test I would do a little experiment.
I went through every paragraph in the specification that described something the program was supposed to do and thought I would cut and paste that text as a comment into my program as the comment at the top of the form routine that actually did what the paragraph was asking for.
I went through the paragraphs one by one, and if I could find any code to place that paragraph in front of, then something was rotten in the state of Denmark.
At the end of the process the entire specification was inside the code as comments – what you might call an “embedded specification”. I was so happy.
Now, what would happen, hypothetically, if I went back to that program after ten years and looked at one of the routines and found the code had all changed to fix bugs and add new requirements but the comment at the top of each routine had not changed at all? The comment would be a load of nonsense now, worse an outright lie, and confuse any developers coming along as they would read the comment and look at the code and get really puzzled.
With the TDD approach you are going through the specification and instead of putting it into the code as a comment, after the event (of writing the production code) you are putting it into the code as code (test code) before the event (writing the production code). This is what is called an “executable specification” as the test code not only says what the program is supposed to do as defined by the business analyst, it actually proves the production code fulfils these requirements, by running the tests.
In both cases (embedded as comments and executable as test code) the business analyst could read the code and see if what they had specified was being done by the program. The difference is that the comments could lie. The test code cannot lie as it promises to do something and when run it either passes or fails that promise. It is a contract of sorts – we ae back to one of favourite concepts “design by contract”.
This way when the developer changes the code to add a new requirement or whatever, instead of not bothering to update the comment, they have no choice but to update the test code, as the test would now fail. So at the end of the day the tests always reflect what the code does NOW as opposed to what it was supposed to do at some point in the past.
It seems trivial but another argument in favour of the TDD approach it is so easy with ABAP in Eclipse.
Have a look at this series of blogs I wrote about the “Visitor” pattern:-
You will see here I write the tests before the production code (When I said earlier I had never done this, I meant I had never done it at work, only whilst playing). I also note how easy Eclipse makes the process.
This is important because if something is difficult to do, and you don’t really want to do it in the first place, then that is a built in argument against doing whatever it is and thus a mega nail in the coffin.
I am keeping another argument in reserve for later (just like those lawyers do in the USA crimes shows) but in the meantime here is the third and final witness for the defence. Mr. First, or “Head” to his friends.
HFSD say it’s good – so it must be good?
Who in the world is “Head First” you may be asking. Well this is a series of books on software design and development.
I have always said that the two textbooks that influenced my ABAP programming the most (despite both of them using Java as an example) were “Clean Code” by Robert Martin, and “Head First Design Patterns by Elisabeth freeman et al).
The relevant “Head First” book (in this criminal case) is “Head First Software Development”.
These books are very entertaining, just like I try to be, but are slightly closer to the real world in their examples, even if it may not seem so at first glance e.g. a company selling an application that makes duck noises.
It is always difficult with examples – too simple and you get crucified for not being realistic and if you make it realistic then you get crucified for making it so complicated no-one can understand whatever it is you are trying to explain. The middle ground is so hard to find and you see it very rarely indeed – however I think the Head First people have got it as close to target as I have seen.
I suppose what keeps them grounded is the examples pretend you are a small independent software company trying to sell software to customers, and bugs and the like mean you don’t get paid i.e. they are always stressing the financial impact of bad software design and development processes. Their position is that the more unit tests you have the more money you make.
That has to resonate with somebody, managers mostly, but surely the developers can see the big picture also? Wouldn’t it be ironic, as the song says, if a manager read these books instead of a developer, and then initiated a unit test or TDD rule, instead of squashing them when a developer suggested them?
You might say “hang on I do not work for a start-up so the burning need for money is just not there” but don’t the managers of big companies (like SAP) keep telling us we should try and act like start-ups? Is the argument “I cannot possibly be as good a programmer in a big mature company as I could be in a start-up” valid?
Anyway, in the HF software development book they do everything in the form of a story and the development team get major egg on their faces when some of their code which they think works perfectly gets demoed to a customer, and it all falls over spectacularly and the development team are even more surprised than the angry customer who starts screaming “Can’t you do ANYTHING right?”
Our customers are generally internal business users, but I can guarantee they get just as angry, In my industry a lot of the end users spend half their time on building sites, and are actual customers spend all their time on building sites, so the language people use when things go wrong is not precisely what you would get in a Jane Austen novel.
So three guesses what the recommended solution to avoid this sort of problem is? No prizes for guessing it is the good old unit testing approach, and the framework they describe for Java looks a lot more basic and difficult to use than what ABAP provides.
Chapter seven in the Head First book on software development ends with the words “in steps test driven development”.
I cannot recommend these books enough, as I said, it does not matter to me the example language is Java, the principles surely apply to any programming language.
At this point the defence rests its case. It is time for the prosecution to have a go. They only have one witness, but it is a “star” witness, with a killer argument as to why TDD is a load of old baloney.
Re-Inventing the Wheel, but this time it is SQUARE
Jelena was by far not the only one wondering about the actual utility of all this unit testing / TDD nonsense. One of the most interesting blogs coming out of the responses to the SAP Open course was by Bärbel Winkler who posted a blog as follows:-
In essence she is saying that your average ABAP programmer has been writing programs in a way that is pretty much exactly the same as the TDD approach, so what is all the fuss about? Put that way none of this is new at all?
The prosecution rests.
I am now going to be the Judge and Jury, which is of course is incredibly unfair, as I am biased and have made up my mind before hearing any of the arguments. So this is just like real life!
Here is my summary, before deciding whether to sentence TDD to the death penalty or not.
Squaring the Circular Wheel
Let me try to square the circle. I would first certainly agree that the TDD concept is not new at all, given it began in 1944 when computers were the size of a house, whereas ABAP started about 30 years later.
In the book 1984 George Orwell talked about “Double Think” where you have two separate contradictory opinions and believe them both at once. I have seen some people in real life actually able to do this, and not realise they are doing it, so it is not as crazy a concept as Orwell might have imagined.
In this case we have two contradictory statements – one being that if you asked any ABAP developer if they were doing test driven development they would all say no, and the contrary opinion (in the bog above) that in a very real sense ABAP developers have been doing pretty much the exact same thing since day one.
In both cases the process is I described earlier – “think about whatever “it” is you want to implement / write code to do ‘it” / make the code to do “it” good.
The abstract concept is identical – the only concrete difference with TDD as described in the course is the use of unit tests in the “think about it” phase, which is an implementation detail.
So if we consider this on an abstract level everything changes – instead of 0% of ABAP developers using a TDD type approach in fact a large majority of them do just that, but just never would have referred to their approach by such a name.
The only difference – and I think it is an important one – is as follows:-
In the traditional approach you think about each part of the program in turn, write the code, and run it, then fix it, until it works, and move on to the next part. In the end the program works as designed.
In the TDD approach you write a test that represents what you think about each part of the program in turn, write the code then run it, then fix it, until it works, then move on to the next part. In the end the program works as designed.
That sounds identical does it not, apart from in the second one you have all the extra effort of writing test code instead of just thinking about it? Moreover – as the Head First people warn- if you want to test different possibilities then you have to write two lines of test code for every line if production code, maybe even THREE lines. So it is madness, is it not?
I would say that if a program was written only once and never changed, the yes it would be utter lunacy, I should be locked up in a padded cell next to the guy who thinks he is Napoleon, and the even worse guy in the next cell who is so mad he puts sandwiches in letter boxes without putting a stamp on them first. I imagine that last joke would fall flat on the younger generation who have never been near a post box in their life, and would be really puzzled by the song “Sylvia’s Mother”. I might as well make jokes about C45 cassettes.
In any event, I would say that 5% of a programs life cycle is the initial build, and then it goes live, and then the remaining 95% of its life cycle revolves around bug fixes and enhancements.
So when I come to change the program six months later, if the original programmer had done the TDD in their head, then when I changed the code I would have no idea if my change had broken anything that went before. This is fragile. The more changes I make the weaker the program becomes.
If the original programmer had done the TDD using test code though I would know at once if my changes had broken anything, as I could run the unit tests. In addition I would add my new change as a unit test, and the cycle would repeat. This is anti-fragile. The more changes I make the stronger the program becomes.
Hence Michael Feathers definition of legacy code, which is “code without tests” as in:-
Code without tests is bad code. It doesn’t matter how well-written it is; it doesn’t matter how pretty or object-oriented or well-encapsulated it is. With tests, we can change the behaviour of our code quickly and verifiably. Without them, we really don’t know if our code is getting better or worse. —Michael Feathers, Working Effectively with Legacy Code
The obvious counter argument is that the programs – like ALV reports – are so simple it does not matter if they are “legacy code” or not. My position is that the simplest program becomes more complex over time, like barnacles growing on the bottom of a boat, because if a user actually uses a code they will always want something more based on another of my favourite quotes, this time from the Roman Empire.
“No-One is Ever Satisfied with anything” – Petronius.
NOTHING has changed in the last two thousand years. When I moved to Australia and explained to my father my job was implementing a new software system he got really worried and asked me “what happens to your job when everybody is happy with the system?” Even back then I was not overly concerned about such a situation coming to pass.
Thus I would argue that every single program with a lifespan over a few months (and many program intended as “one-off” get used for years) will be bombarded with change request and get more and more code added to them. That is going to happen as sure as eggs are eggs. It is your choice how to deal with that – will every change make the program more brittle and prone to errors, or will every change make it more resistant to future changes?
That sounds trite, but I really believe it to be the case – based on actual experience. The first example is the most complicated program I have ever written, one that took four years to write. I understand not everyone gets to write such a monster, and are probably happy they do not have to. Anyway, it never breaks, no matter how many changes are made, and if it DID break a building or a bridge or some such would fall down, because it controls the ingredients in the concrete.
A slightly more common example – one of our most business critical programs started life as a simple ALV report and now the whole business depends on it and it is fragile as broken glass with its seven hundred subroutines and stuffed with global variables and it has no tests and every change is more dangerous than the last.
What I Had for Breakfast
This is what I am doing this year, along with colleagues. Our most business critical programs are in some sense “dead men walking” as in they work fine, but every change is more dangerous than the last. So we are going to re-write the two most critical ones.
Greenpeace had a very good analogy. An aircraft has many thousands of rivets. Every change you make takes out one rivet.
There are so many rivets each change does not matter at the start. The question would be – would you fly in an aircraft every month knowing it had less rivets than the month before? At some stage the whole thing is going to fall to bits, mid-air.
Greenpeace would say the aircraft is the world, and the species that go extinct every day are the rivets.
In your program (upon which the fate of the entire human species does not hopefully depend) each individual change may not make the overall program more fragile, but it might, and some changes will 100% not in and of themselves but in the “accident waiting to happen” sense.
I am going around in circles now, so it is time to break off.
Dancing with you in the Summary Rain
Take the Red Pill
Ostensibly this blog as about week two of the Open SAP Course on Unit Testing. In reality I spent 1% of the blog talking about the content of the course, and the rest in a (biased) analysis of whether unit testing and TDD were a good thing or not, and I am going to give it a pardon and say “TDD you are free to go”.
Naturally you may totally disagree with anything or everything I have said above. I which case the magic of the SAP Community comes into play, even if there a lot less people visiting it than before. A healthy debate about anything is just what it needs…