Cost of Testing

posted on October 1st, 2009 ·

A lot of people have been asking me lately, what is the cost of testing, so I decided, that I will try to measure it, to dispel  the myth that testing takes twice as long.

For the last two weeks I have been keeping track of the amount of time I spent writing tests versus the time writing production code. The number surprised even me, but after I thought about it, it makes a lot of sense. The magic number is about 10% of time spent on writing tests. Now before, you think I am nuts, let me back it up with some real numbers from a personal project I have been working on.

Total Production Test Ratio
Commits 1,347 1,347 1,347
LOC 14,709 8,711 5,988 40.78%
JavaScript LOC 10,077 6,819 3,258 32.33%
Ruby LOC 4,632 1,892 2,740 59.15%
Lines/Commit 10.92 6.47 4.45 40.78%
Hours(estimate) 1,200 1,080 120 10.00%
Hours/Commit 0.89 0.80 0.09
Mins/Commit 53 48 5

Commits refers to the number of commits I have made to the repository. LOC is lines of code which is broken down by language. The ratio shows the typical breakdown between the production and test code when you test drive and it is about half, give or take a language. It is interesting to note that on average I commit about 11 lines out of which 6.5 are production and 4.5 are test. Now, keep in mind this is average, a lot of commits are large where you add a lot of code, but then there are a lot of commits where you are tweaking stuff, so the average is quite low.

The number of hours spent on the project is my best estimate, as I have not kept track of these numbers. Also, the 10% breakdown comes from keeping track of my coding habits for the last two weeks of coding. But, these are my best guesses.

Now when I test drive, I start with writing a test which usually takes me few minutes (about 5 minutes) to write. The test represents my scenario. I then start implementing the code to make the scenario pass, and the implementation usually takes me a lot longer (about 50 minutes). The ratio is highly asymmetrical! Why does it take me so much less time to write the scenario than it does to write the implementation given that they are about the same length? Well look at a typical test and implementation:

Here is a typical test for a feature:

ArrayTest.prototype.testFilter = function() {
  var items = ["MIsKO", {name:"john"}, ["mary"], 1234];
  assertEquals(4, items.filter("").length);
  assertEquals(4, items.filter(undefined).length);

  assertEquals(1, items.filter('iSk').length);
  assertEquals("MIsKO", items.filter('isk')[0]);

  assertEquals(1, items.filter('ohn').length);
  assertEquals(items[1], items.filter('ohn')[0]);

  assertEquals(1, items.filter('ar').length);
  assertEquals(items[2], items.filter('ar')[0]);

  assertEquals(1, items.filter('34').length);
  assertEquals(1234, items.filter('34')[0]);

  assertEquals(0, items.filter("I don't exist").length);
};

ArrayTest.prototype.testShouldNotFilterOnSystemData = function() {
  assertEquals("", "".charAt(0)); // assumption
  var items = [{$name:"misko"}];
  assertEquals(0, items.filter("misko").length);
};

ArrayTest.prototype.testFilterOnSpecificProperty = function() {
  var items = [{ignore:"a", name:"a"}, {ignore:"a", name:"abc"}];
  assertEquals(2, items.filter({}).length);

  assertEquals(2, items.filter({name:'a'}).length);

  assertEquals(1, items.filter({name:'b'}).length);
  assertEquals("abc", items.filter({name:'b'})[0].name);
};

ArrayTest.prototype.testFilterOnFunction = function() {
  var items = [{name:"a"}, {name:"abc", done:true}];
  assertEquals(1, items.filter(function(i){return i.done;}).length);
};

ArrayTest.prototype.testFilterIsAndFunction = function() {
  var items = [{first:"misko", last:"hevery"},
               {first:"mike", last:"smith"}];

  assertEquals(2, items.filter({first:'', last:''}).length);
  assertEquals(1, items.filter({first:'', last:'hevery'}).length);
  assertEquals(0, items.filter({first:'mike', last:'hevery'}).length);
  assertEquals(1, items.filter({first:'misko', last:'hevery'}).length);
  assertEquals(items[0], items.filter({first:'misko', last:'hevery'})[0]);
};

ArrayTest.prototype.testFilterNot = function() {
  var items = ["misko", "mike"];

  assertEquals(1, items.filter('!isk').length);
  assertEquals(items[1], items.filter('!isk')[0]);
};

Now here is code which implements this scenario tests above:

Array.prototype.filter = function(expression) {
  var predicates = [];
  predicates.check = function(value) {
    for (var j = 0; j < predicates.length; j++) {
       if(!predicates[j](value)) {
         return false;
       }
     }
     return true;
   };
   var getter = Scope.getter;
   var search = function(obj, text){
     if (text.charAt(0) === '!') {
       return !search(obj, text.substr(1));
     }
     switch (typeof obj) {
     case "bolean":
     case "number":
     case "string":
       return ('' + obj).toLowerCase().indexOf(text) > -1;
    case "object":
      for ( var objKey in obj) {
        if (objKey.charAt(0) !== '$' && search(obj[objKey], text)) {
          return true;
        }
      }
      return false;
    case "array":
      for ( var i = 0; i < obj.length; i++) {
        if (search(obj[i], text)) {
          return true;
        }
      }
      return false;
    default:
      return false;
    }
  };
  switch (typeof expression) {
    case "bolean":
    case "number":
    case "string":
      expression = {$:expression};
    case "object":
      for (var key in expression) {
        if (key == '$') {
          (function(){
            var text = (''+expression[key]).toLowerCase();
            if (!text) return;
            predicates.push(function(value) {
              return search(value, text);
            });
          })();
        } else {
          (function(){
            var path = key;
            var text = (''+expression[key]).toLowerCase();
            if (!text) return;
            predicates.push(function(value) {
              return search(getter(value, path), text);
            });
          })();
        }
      }
      break;
    case "function":
      predicates.push(expression);
      break;
    default:
      return this;
  }
  var filtered = [];
  for ( var j = 0; j < this.length; j++) {
    var value = this[j];
    if (predicates.check(value)) {
      filtered.push(value);
    }
  }
  return filtered;
};

Now, I think that if you look at these two chunks of code, it is easy to see that even though they are about the same length, one is much harder t write. The reason, why tests take so little time to write is that they are linear in nature. No loops, ifs or interdependencies with other tests. Production code is a different story, I have to create complex ifs, loops and have to make sure that the implementation works not just for one test, but all test. This is why it takes you so much longer to write production than test code. In this particular case, I remember rewriting this function three times, before I got it to work as expected. :-)

So a naive answer is that writing test carries a 10% tax. But, we pay taxes in order to get something in return. Here is what I get for 10% which pays me back:

  • When I implement a feature I don’t have to start up the whole application and click several pages until I get to page to verify that a feature works. In this case it means that I don’t have to refreshing the browser, waiting for it to load a dataset and then typing some test data and manually asserting that I got what I expected. This is immediate payback in time saved!
  • Regression is almost nil.  Whenever you are adding new feature you are running the risk of breaking something other then what you are working on immediately (since you are not working on it you are not actively testing it). At least once a day I have a what the @#$% moment when a change suddenly breaks a test at the opposite end of the codebase which I did not expect, and I count my lucky stars. This is worth a lot of time spent when you discover that a feature you thought was working no longer is, and by this time you have forgotten how the feature is implemented.
  • Cognitive load is greatly reduced since I don’t have to keep all of the assumptions about the software in my head, this makes it really easy to switch tasks or to come back to a task after a meeting, good night sleep or a weekend.
  • I can refactor the code at will, keeping it from becoming stagnant, and hard to understand. This is a huge problem on large projects, where the code works, but it is really ugly and everyone is afraid to touch it. This is worth money tomorrow to keep you going.

These benefits translate to real value today as well as tomorrow. I write tests, because the additional benefits I get more than offset the additional cost of 10%.  Even if I don’t include the long term benefits, the value I get from test today are well worth it. I am faster in developing code with test. How much, well that depends on the complexity of the code. The more complex the thing you are trying to build is (more ifs/loops/dependencies) the greater the benefit of tests are.

So now you understand my puzzled look when people ask me how much slower/costlier the development with tests is.

→ 31 CommentsTags: Uncategorized

Hello World, <angular/> is here

posted on September 28th, 2009 ·

If you see this text, than you are not reading this blog on our site, and the page will be static. To get the full effect please read the original blog on http://blog.getangular.com/2009/09/26/hello-world-angular-is-here/

Hi I am <angular/>! What is your name?
(Please enter your name into the text box).

Hello {{person.name}}! Please to meet you!


We would like to introduce to you a new way of building web applications! All you need is basic working of HTML & CSS and you can declaratively build a web-application in minutes.

Here are the kinds of things yo can do:

  • Bring static HTML to life with just a few keystrokes.
  • Persist your data in the cloud
  • Embed your application in existing web page, such as this blog article

Here is what you need to know:

  • Basic Knowledge of HTML & CSS
  • Optional: JavaScript if you want to take the application to the next level.

Here is what you DO NOT NEED to know:

  • Databases or SQL.
  • Back end technology such as Java, Ruby, C# or the likes.
  • For most things, you don’t even need to be a programer.

Well {{person.name}}, believe it or not, but this page is just a wordpress blog written in few minutes with a text editor. I have than added few extra angular tags to the HTML and the page came alive as you can see. Let me take you on the tour of what <angular/> can do.

Why don’t you tell me what you like to do for fun:

Hobby:

{{person.name}} likes to:

  • {{hobby}} [ X ]

Now lets save your hobbies:

Great! here is a QR code which if you scan with your iPhone (App: NeoReader) or Android Phone (App: Barcode reader) it will take you back to this page:

{{$window.location.href|qrcode}}

Congrats {{person.name}}, you have successfully saved your hobbies to the cloud. To access them later here is a permanent url which you can send to your friends or use to edit your hobbies later: {{$window.location.href}}


I am sure you are wondering how all of this magic is made. Well, here is a hint, go watch the screen-cast here. Than come back and check the source of this page, as well as the debug view of the internal state of the page here:

person={{person}}

<angular/> is still in beta, but we are looking for few brave souls to start building web apps and give us feedback. As a beta user we will work closely with you to help you get started and resolve any issues which you may run into. If interested, sign up on our mailing list (http://groups.google.com/group/angular) and send us an email with the kind of application you would like to build.

Happy coding and looking forward to hear from you…

The <angular/> team.

→ 4 CommentsTags: Uncategorized

Checked exceptions I love you, but you have to go

posted on September 16th, 2009 ·

Once upon a time Java created an experiment called checked-exceptions, you know you have to declare exceptions or catch them. Since that time no other language (I know of) has decided to copy this idea, but somehow the Java developers are in love with checked exceptions. Here, I am going to “try” to convince you that checked-exceptions, even thought look like a good idea at first glance, are actually not a good idea at all:

Empirical Evidence

Let’s start with an observation of your code base. Look through your code and tell me what percentage of catch blocks do rethrow or print error? My guess is that it is in high 90s. I would go as far as 98% of catch blocks are meaningless, since they just print an error or rethrow the exception which will later be printed as an error. The reason for this is very simple. Most exceptions such as FileNotFoundException, IOException, and so on are sign that we as developers have missed a corner case. The exceptions are used as away of informing us that we, as developers, have messed up. So if we did not have checked exceptions, the exception would be throw and the main method would print it and we would be done with it (optionally we would catch in main all exceptions and log them if we are a server).

Checked exceptions force me to write catch blocks which are meaningless: more code, harder to read, and higher chance that I will mess up the rethrow logic and eat the exception.

Lost in Noise

Now lets look at the 2-5% of the catch blocks which are not rethrow and real interesting logic happens there. Those interesting bits of useful and important information is lost in the noise, since my eye has been trained to skim over the catch blocks. I would much rather have code where a catch would indicate, pay, attention here something interesting happens here, rather than, it is just a rethrow. Now, if we did not have checked exceptions, you would write your code without catch, test your code (you do test right?) and realize that under these circumstances an exception is throw and deal with it. In such a case forgetting to write a catch block is no different than forgetting to write an else block of the if statement. We don’t have checked ifs and yet no one misses them, so why do we need to tell developers that FileNotFound can happen. What if the developer knows for a fact that it can not happen since he has just placed the file there, and so such an exception would mean that your filesystem has just disappeared and your application is not place to handle that.

Checked exception make me skim the catch as most are just rethrows, making it likely that I will miss something important.

Unreachable Code

I love to write tests first and implement as a consequence of tests. In such a situation you should always have 100% coverage since you are only writing what the tests are asking for. But you don’t! It is less than 100% because checked exceptions force you to write catch blocks which are impossible to execute. Check this code out:

bytesToString(byte[] bytes) {
  ByteArrayOutputStream out = new ByteArrayOutputStream();
  try {
    out.write(bytes);
    out.close()
    return out.toSring();
  } catch (IOException e) {
    // This can never happen!
    // Should I rethrow? Eat it? Print Error?
  }
}

ByteArrayOutputStream will never throw IOException! You can look through its implementation and see that it is true! So why are you making me catch a phantom exception which can never happen and which I can not write a test for? As a result I cannot claim 100% coverage because of things outside my control.

Checked exceptions create dead code which will never  execute.

Closures Don’t Like You

Java does not have closures but it has visitor pattern. Let me explain with concrete example. I was creating a custom class loader and need to override load() method on MyClassLoader which throws ClassNotFoundException under some circumstances. I use ASM library which allows me to inspect Java bytecodes. The way ASM works is that it is a visitor pattern, I write visitors and as ASM parses the bytecodes it calls specific methods on my visitor implementation. One of my visitors as it is examining bytcodes decides that things are not right and needs to throw a ClassNotFondException which the class loader contract says it should throw. But now we have a problem. What we have on a stack is MyClassLoader -> ASMLibrary -> MyVisitor. MyVisitor wants to throw an exception which MyClassLoader expects but it can not since ClassNotFoundException is checked and ASMLibrary does not declare it (nor should it). So I have to throw RuntimeClassNotFoundException from MyVisitor which can pass through ASMLibrary which MyClassLoader can catch and rethrow as ClassNotFoundException.

Checked exception get in the way of functional programing.

Lost Fidelity

Suppose java.sql package would be implemented with useful exception such as SqlDuplicateKeyExceptions and SqlForeignKeyViolationException and so on (we can wish) and suppose these exceptions are checked (which they are). We say that the SQL package has high fidelity of exception since each exception is to a very specific problem. Now lets say we have the same set up as before where there is some other layer between us and the SQL package, that layer can either redeclare all of the exceptions, or more likely throw its own. Let’s look at an example, Hibernate is object-relational-database-mapper, which means it converts your SQL rows into java objects. So on the stack you have MyApplication -> Hibernate -> SQL. Here Hibernate is trying hard to hide the fact that you are talking to SQL so it throws HibernateExceptions instead of SQLExceptions. And here lies the problem. Your code knows that there is SQL under Hibernate and so it could have handled SqlDuplicateException in some useful way, such as showing an error to the user, but Hibernate was forced to catch the exception and rethrow it as generic HibernateException. We have gone from high fidelity SqlException to low fidelity HibernateException. An so MyApplication can not do anything. Now Hibernate could have throw HibernateDuplicateKeyException but that means that Hibernate now has the same exception hierarchy as SQL and we are duplicating effort and repeating ourselves.

Rethrowing checked exceptions causes you to lose fidelity and hence makes it less likely that you could do something useful with the exception later on.

You can’t do Anything Anyway

In most cases when exception is throw there is no recovery. We show a generic error to the user and log an exception so that we can file a bug and make sure that that exception will not happen again. Since 90+% of the exception are bugs in our code and all we do is log, why are we forced to rethrow it over and over again.

It is rare that anything useful can be done when checked exception happens, in most case we die with error, so make that the default behavior of my code with no additional typing.

How I deal with the code

Here is my strategy to deal with java:

  • Always catch all checked exceptions at source and rethrow them as LogRuntimeException.
    • My runtime un-checked exception which says I don’t care just log it.
    • Here I have lost Exception fidelity.
  • All of my methods do not declare any exceptions
  • As I discover that I need to deal with a specific exception I go back to the source where LogRuntimeException was thrown and I change it to <Specific>RuntimeException (This is rarer than you think)
    • I am restoring the exception fidelity only where needed.
  • Net effect is that when you come across a try-catch clause you better pay attention as interesting things are happening there.
    • Very few try-catch calluses, code is much easier to read.th
    • Very close to 100% test coverage as there is no dead code in my catch blocks.

→ 19 CommentsTags: Uncategorized

It is not about writing tests, its about writing stories

posted on September 2nd, 2009 ·

I would like to make an analogy between building software and building a car. I know it is imperfect one, as one is about design and the other is about manufacturing, but indulge me, the lessons are very similar.

A piece of software is like a car. Lets say you would like to test a car, which you are in the process of designing, would you test is by driving it around and making modifications to it, or would you prove your design by testing each component separately? I think that testing all of the corner cases by driving the car around is very difficult, yes if the car drives you know that a lot of things must work (engine, transmission, electronics, etc), but if it does not work you have no idea where to look. However, there are some things which you will have very hard time reproducing in this end-to-end test. For example, it will be very hard for you to see if the car will be able to start in the extreme cold of the north pole, or if the engine will not overheat going full throttle up a sand dune in Sahara. I propose we take the engine out and simulate the load on it in a laboratory.

We call driving car around an end-to-end test and testing the engine in isolation a unit-test. With unit tests it is much easier to simulate failures and corner cases in a much more controlled environment. We need both tests, but I feel that most developers can only imagine the end-to-end tests.

But lets see how we could use the tests to design a transmission. But first, little terminology change, lets not call them test, but instead call them stories. They are stories because that is what they tell you about your design. My first story is that:

  • the transmission should allow the output shaft to be locked, move in same direction (D) as the input shaft, move in opposite (R) or move independently (N)

Given such a story I could easily create a test which would prove that the above story is true for any design submitted to me. What I would most likely get is a transmission which would only have a single gear in each direction. So lets write another story

  • the transmission should allow the ratio between input and output shaft to be [-1, 0, 1, 2, 3, 4]

Again I can write a test for such a transmission but i have not specified how the forward gear should be chosen, so such a transmission would most likely be permanently stuck in 1st gear and limit my speed, it will also over-rev the engine.

  • the transmission should start in 1st and than switch to higher gear before the engine reaches maximum revolutions.

This is better, but my transmission would most likely rev the engine to maximum before it would switch, and once it would switch to higher gear and I would slow down, it would not down-shift.

  • the transmission should down shift whenever the engine RPM fall bellow 1000 RPMs

OK, now it is starting to drive like a car, but still the limits for shifting really are 1000-6000 RPMs which is not very fuel efficient way to drive your car.

  • the transmission should up-shift whenever the estimated fuel consumption at a higher gear ration is better than the current one.

So now our engine will not rev any more but it will be a lazy car since once the transmission is in the fuel efficient mode it will not want to down-shift

  • the transmission should down-shift whenever the gas pedal is depressed more than 50% and the RPM is lower than the engine’s peak output RPM.

I am not a transmission designer, but I think this is a decent start.

Notice how I focused on the end result of the transmission rather than on testing specific internals of it. The transmission designer would have a lot of levy in choosing how it worked internally, Once we would have something and we would test it in the real world we could augment these list of stories with additional stories as we discovered additional properties which we would like the transmission to posses.

If we would decide to change the internal design of the transmission for whatever reason we would have these stories as guides to make sure that we did not forget about anything. The stories represent assumptions which need to be true at all times. Over the lifetime of the component we can collect hundreds of stories which represent equal number of assumption which is built into the system.

Now imagine that a new designer comes on board and makes a design change which he believes will improve the responsiveness of the transmission, he can do so because the existing stories are not restrictive in how, only it what the outcome should be. The stories save the designer from breaking an existing assumption which was already designed into the transmission.

Now lets contrast this with how we would test the transmission if it would already be build.

  • test to make sure all of the gears work
  • test to make sure that the engine is not allowed to over-rev

It is hard now to think about what other tests to write, since we are not using the tests to drive the design. Now, lets say that someone now insist that we get 100% coverage, we open the transmission up and we see all kinds of logic, and rules and we don’t know why since we were not part of the design so we write a test

  • at 3000 RPM input shaft, apply 100% throttle and assert that the transmission goes to 2nd gear.

Tests like that are not very useful when you want to change the design, since you are likely to break the test, without fully understanding why the test was testing that specific conditions, it is hard to know if anything was broken if the tests is red.. That is because the tests does not tell a story any more, it only asserts the current design. It is likely that such a test will be in the way when you will try to do design changes. The point I am trying to make is that there is huge difference between writing tests before or after. When we write tests before we are:

  • creating a story which is forcing a particular design decision.
  • tests are a collection of assumptions which needs to be true at all times.

when we write tests after the fact we:

  • miss a lot of reasons why things are done in particular way even if we have 100% coverage
  • test are often brittle because they are tied to particulars of the current implementation
  • tests are just snapshots and don’t tell a story of why the component does something, only that it does.

For this reason there are huge differences in quality when writing assumptions as stories before (which force design to emerge) or writing tests after which take a snapshot of a given design.

→ 10 CommentsTags: Uncategorized

Sharing My Slide Deck from RTAC

posted on August 21st, 2009 ·

Just Wanted to share the latest slide deck with you, which I was presenting at RIM Test Automation Conference. I know that without the sound to go with it there is limited value, but I hope you get at least something out of it.

Psychology of Testing

→ 7 CommentsTags: Uncategorized

Super Fast JS Testing

posted on August 12th, 2009 ·

by Shyam Seshadri

Before I jump into how exactly you can perform super fast and easy JS testing, let me give you some background on the problem.

Javascript is a finicky language (Some people even hesitate to call it a language). And it can easily grow and become a horrible and complicated beast, incapable of being tamed once let loose. And testing it is a nightmare. Once you have decided on a framework (of which there are a dime a dozen), you then have to set it up to run just right. You need to set it up to actually run your tests. Then you have to figure out how to run it in a continuous integration environment. Maybe even run it in headless mode. And everyone solves it in their own ways.

But the biggest problem I have with most of these frameworks is that executing the tests usually requires a context switch. By that, I mean to run a JSUnit test, you end up usually having to open the browser, browse to a particular url or html page which then runs the test. Then you have to look at the results there, and then come back to your editor to either proceed further or fix your tests. Works, but really slows down development.

In java, all it takes is to click the run button in your IDE to run your tests. You get instant feedback, a green / red bar and details on which tests passed and failed and at what line. No context switch, you can get it to run at every save, and proceed on your merry way. Till now, this was not possible with Javascript.

But now, we have JS Test Driver. My colleagues Jeremie and Misko ended up running into some of the issues I outlined above, and decided that going along with the flow was simply unacceptable. So they created a JS Testing framework which solves these very things. You can capture any browser on any machine, and when you tell it to run tests, it will go ahead and execute them on all these browsers and return you the results in your client. And its blazing fast. I am talking milliseconds to run 100 odd tests. And you can tell it to rerun your tests at each save. All within the comforts of your IDE. And over the last three weeks, I have been working on the eclipse plugin for JS Test Driver, and its now at the point where its in a decent working condition.

The plugin in actionThe plugin in action

The plugin allows you to, from within Eclipse, start the JS Test Driver server, capture some browsers, and then run your tests. You get pretty icons telling you what browsers were captured, the state of the server, the state of the tests. It allows you to filter and show only failures, rerun your last launch configuration, even setup the paths to your browsers so you can launch it all from the safety of eclipse. And as you can see, its super fast. Some 100 odd tests in less than 10 ms. If thats not fast, I don’t know what is.

For more details on JS Test Driver, visit its Google Code website and see how you can use it in your next project and even integrate it into a continuous integration. Misko talks a little bit more about the motivations behind writing it on his Yet Another JS Testing Framework post. To try out the plugin for yourselves, go add the following update site to eclipse:

http://js-test-driver.googlecode.com/svn/update/

For all you IntelliJ fanatics, there is something similar in the works.

→ 10 CommentsTags: Uncategorized

How to think about OO

posted on July 31st, 2009 ·

Everyone seems  to think that they are writing OO after all they are using OO languages such as Java, Python or Ruby. But if you exam the code it is often procedural in nature.

Static Methods

Static methods are procedural in nature and they have no place in OO world. I can already hear the screams, so let me explain why, but first we need to agree that global variables and state is evil. If you agree with previous statement than for a static method to do something interesting it needs to have some arguments, otherwise it will always return a constant. Call to a staticMethod() must always return the same thing, if there is no global state. (Time and random, has global state, so that does not count and object instantiation may have different instance but the object graph will be wired the same way.)

This means that for a static method to do something interesting it needs to have arguments. But in that case I will argue that the method simply belongs on one of its arguments. Example: Math.abs(-3) should really be -3.abs(). Now that does not imply that -3 needs to be object, only that the compiler needs to do the magic on my behalf, which BTW, Ruby got right. If you have multiple arguments you should choose the argument with which method interacts the most.

But most justifications for static methods argue that they are “utility methods”. Let’s say that you want to have toCamelCase() method to convert string “my_workspace” to “myWorkspace”. Most developers will solve this as StringUtil.toCamelCase(”my_workspace”). But, again, I am going to argue that the method simply belongs to the String class and should be “my_workspace”.toCamelCase(). But we can’t extend the String class in Java, so we are stuck, but in many other OO languages you can add methods to existing classes.

In the end I am sometimes (handful of times per year) forced to write static methods due to limitation of the language. But that is a rare event since static methods are death to testability. What I do find, is that in most projects static methods are rampant.

Instance Methods

So you got rid of all of your static methods but your codes still is procedural. OO says that code and data live together. So when one looks at code one can judge how OO it is without understanding what the code does, simply by looking at the relationship of data and code.

class Database {
  // some fields declared here
  boolean isDirty(Cache cache, Object obj) {
    for (Object cachedObj : cache.getObjects) {
      if (cachedObj.equals(obj))
        return false;
    }
    return true;
  }
}

The problem here is the method may as well be static! It is in the wrong place, and you can tell this because it does not interact with any of the data in the Database, instead it interacts with the data in cache which it fetches by calling the getObjects() method. My guess is that this method belongs to one of its arguments most likely Cache. If you move it to Cache you well notice that the Cache will no longer need the getObjects() method since the for loop can access the internal state of the Cache directly. Hey, we simplified the code (moved one method, deleted one method) and we have made Demeter happy.

The funny thing about the getter methods is that it usually means that the code where the data is processed is outside of the class which has the data. In other words the code and data are not together.

class Authenticator {
  Ldap ldap;
  Cookie login(User user) {
    if (user.isSuperUser()) {
      if ( ldap.auth(user.getUser(),
             user.getPassword()) )
        return new Cookie(user.getActingAsUser());
    } else (user.isAgent) {
        return new Cookie(user.getActingAsUser());
    } else {
      if ( ldap.auth(user.getUser(),
             user.getPassword()) )
        return new Cookie(user.getUser());
    }
    return null;
  }
}

Now I don’t know if this code is well written or not, but I do know that the login() method has a very high affinity to user. It interacts with the user a lot more than it interacts with its own state. Except it does not interact with user, it uses it as a dumb storage for data. Again, code lives with data is being violated. I believe that the method should be on the object with which it interacts the most, in this case on User. So lets have a look:

class User {
  String user;
  String password;
  boolean isAgent;
  boolean isSuperUser;
  String actingAsUser;

  Cookie login(Ldap ldap) {
    if (isSuperUser) {
      if ( ldap.auth(user, password) )
        return new Cookie(actingAsUser);
    } else (isAgent) {
        return new Cookie(actingAsUser);
    } else {
      if ( ldap.auth(user, password) )
        return new Cookie(user);
    }
    return null;
  }
}

Ok we are making progress, notice how the need for all of the getters has disappeared, (and in this simplified example the need for the Authenticator class disappears) but there is still something wrong. The ifs branch on internal state of the object. My guess is that this code-base is riddled with if (user.isSuperUser()). The issue is that if you add a new flag you have to remember to change all of the ifs which are dispersed all over the code-base. Whenever I see If or switch on a flag I can almost always know that polymorphism is in order.

class User {
  String user;
  String password;

  Cookie login(Ldap ldap) {
    if ( ldap.auth(user, password) )
      return new Cookie(user);
    return null;
  }
}

class SuperUser extends User {
  String actingAsUser;

  Cookie login(Ldap ldap) {
    if ( ldap.auth(user, password) )
      return new Cookie(actingAsUser);
    return null;
  }
}

class AgentUser extends User {
  String actingAsUser;

  Cookie login(Ldap ldap) {
    return new Cookie(actingAsUser);
  }
}

Now that we took advantage of polymorphism, each different kind of user knows how to log in and we can easily add new kind of user type to the system. Also notice how the user no longer has all of the flag fields which were controlling the ifs to give the user different behavior. The ifs and flags have disappeared.

Now this begs the question: should the User know about the Ldap? There are actually two questions in there. 1) should User have a field reference to Ldap? and 2) should User have compile time dependency on Ldap?

Should User have a field reference to Ldap? The answer is no, because you may want to serialize the user to database but you don’t want to serialize the Ldap. See here.

Should User have compile time dependency on Ldap? This is more complicated, but in general the answer depends on wether or not you are planning on reusing the User on a different project, since compile time dependencies are transitive in strongly typed languages. My experience is that everyone always writes code that one day they will reuse it, but that day never comes, and when it does, usually the code is entangled in other ways anyway, so code reuse after the fact just does not happen. (developing a library is different since code reuse is an explicit goal.) My point is that a lot of people pay the price of “what if” but never get any benefit out of it. Therefore don’t worry abut it and make the User depend on Ldap.

→ 42 CommentsTags: Uncategorized

Software Testing Categorization

posted on July 14th, 2009 ·

You hear people talking about small/medium/large/unit/integration/functional/scenario tests but do most of us really know what is meant by that? Here is how I think about tests.

Unit/Small

Lets start with unit test. The best definition I can find is that it is a test which runs super-fast (under 1 ms) and when it fails you don’t need debugger to figure out what is wrong. Now this has some implications. Under 1 ms means that your test cannot do any I/O. The reason this is important is that you want to run ALL (thousands) of your unit-tests every time you modify anything, preferably on each save. My patience is two seconds max. In two seconds I want to make sure that all of my unit tests ran and nothing broke. This is a great world to be in, since if tests go red you just hit Ctrl-Z few times to undo what you have done and try again. The immediate feedback is addictive. Not needing a debugger implies that the test is localized (hence the word unit, as in single class).

The purpose of the unit-test is to check the conditional logic in your code, your ‘ifs’ and ‘loops’. This is where the majority of your bugs come from (see theory of bugs). Which is why if you do no other testing, unit tests are the best bang for your buck! Unit tests, also make sure that you have testable code. If you have unit-testable code than all other testing levels will be testable as well.

A KeyedMultiStackTest.java is what I would consider great unit test example from Testability Explorer. Notice how each test tells a story. It is not testMethodA, testMethodB, etc, rather each test is a scenario. Notice how at the beginning the test are normal operations you would expect but as you get to the bottom of the file the test become little stranger. It is because those are weird corner cases which I have discovered later. Now the funny thing about KeyedMultiStack.java is that I had to rewrite this class three times. Since I could not get it to work under all of the test cases. One of the test was always failing, until I realized that my algorithm was fundamentally flawed. By this time I had most of the project working and this is a key class for byte-code analysis process. How would you feel about ripping out something so fundamental out of your system and rewriting it from scratch? It took me two days to rewrite it until all of my test passed again. After the rewrite the overall application still worked. This is where you have an AHa! moment, when you realize just how amazing unit-tests are.

Does each class need a unit test? A qualified no. Many classes get tested indirectly when testing something else. Usually simple value objects do not have tests of their own. But don’t confuse not having tests and not having test coverage. All classes/methods should have test coverage. If you TDD, than this is automatic.

Medium/Functional

So you proved that each class works individually, but how do you know that they work together? For this we need to wire related classes together just as they would be in production and exercise some basic execution paths through it. The question here we are trying to answer is not if the ‘ifs’ and ‘loops’ work, (we have already answered that,) but whether the interfaces between classes abide by their contracts. Great example of functional test is MetricComputerTest.java. Notice how the input of each test is an inner class in the test file and the output is ClassCost.java. To get the output several classes have to collaborate together to: parse byte-codes, analyze code paths, and compute costs until the final cost numbers are asserted.

Many of the classes are tested twice. Once directly throughout unit-test as described above, and once indirectly through the functional-tests. If you would remove the unit tests I would still have high confidence that the functional tests would catch most changes which would break things, but I would have no idea where to go to look for a fix, since the mistake can be in any class involved in the execution path. The no debugger needed rule is broken here. When a functional test fails, (and there are no unit tests failing) I am forced to take out my debugger. When I find the problem, I add a unit test retroactively to my unit test to 1) prove to myself that I understand the bug and 2) prevent this bug from happening again. The retroactive unit test is the reason why the unit tests at the end of KeyedMultiStackTest.java file are “strange” for a lack of a better world. They are things which I did not think of when i wrote the unit-test, but discovered when I wrote functional tests, and through lot of hours behind debugger track down to KeyedMultiStack.java class as the culprit.

Now computing metrics is just a small part of what testability explorer does, (it also does reports, and suggestions) but those are not tested in this functional test (there are other functional tests for that). You can think of functional-tests as a set of related classes which form a cohesive functional unit for the overall application. Here are some of the functional areas in testability explorer: java byte-code parsing, java source parsing, c++ parsing, cost analysis, 3 different kinds of reports, and suggestion engine. All of these have unique set of related classes which work together and need to be tested together, but for the most part are independent.

Large/End-to-End/Scenario

We have proved that: ‘ifs’ and ‘loops’ work; and that the contracts are compatible, what else can we test? There is still one class of mistake we can make. You can wire the whole thing wrong. For example, passing in null instead of report, not configuring the location of the jar file for parsing, and so on. These are not logical bugs, but wiring bugs. Luckily, wiring bugs have this nice property that they fail consistently and usually spectacularly with an exception. Here is an example of end-to-end test: TestabilityRunnerTest.java. Notice how these tests exercises the whole application, and do not assert much. What is there to assert? We have already proven that everything works, we just want to make sure that it is wired properly.

→ 14 CommentsTags: Uncategorized

Computer Engineer vs. Computer Scientist

posted on July 11th, 2009 ·

Which one are you? I am an engineer. But maybe we should first define the differences between the two. Engineer cares about how the system is put together whereas CS cares about how it works. Do you care about the technology or the algorithm?

The Interview

Since I am on engineer, these are the kind of questions I ask in an interview:

  • Imagine you are an evil developer, how do you make code hard to test?
  • How would you store a math expression tree, such that you would have an evaluate() method and a toString() method which would print the tree in an infix notation placing the parenthesis only when necessary.

On the other hand a CS asks these “algorithmic” questions:

  • Write a merge sort method which merges ‘n’ files into one.
  • Write a method to reverse a string in place.

The solution to engineer’s question is a set of classes interacting to define a system. Whereas a solution to a CS question is a single method doing something complex. Now, I don’t know about you but when was the last time when your application consisted of a single method. When was the last time when your system broke down because someone did not know how to write one of these algorithmic methods? When was the last time when your system broke down because the interaction between classes has gone too complex? I believe that most people are asking the wrong questions in the interview.

Algorithms

Now there is a time and place when an algorithm is exactly what the doctor ordered. Video/voice codecs, image compression, revision control, database optimization, and so on. But notice that all of these are nothing without some “application” around it. Video codec is nothing without YouTube around it, and DB engine is nothing without countless utilities, and database drivers which go with it. Chances are, when you are building an application, you will fail because  your class interaction will go out of hand, not because you did not know how to solve some algorithmic problem. Libraries have already been written for the most (80%) of the algorithmic problems out there. So why do you insist that an interview candidate knows how to sort integers. Is that what he/she will be doing all day long? While building your web application?

Engineer vs CS

The thing is you need both, and preferably in one person. It is also true that no one is 100% engineer or 100% CS, there is a blend in all of us. Algorithms require raw brain power, whereas engineering requires prior knowledge (best practices) which you cannot get by thinking about the problem harder. You can only get “engineering” knowledge by learning from others. I have seen too many people focusing too much on brain power alone. We hire young kids and we let them loose on a code-base, and than we wonder why we can’t change anything because everything is tightly coupled. Hint, it is not because they are stupid.

The Reality

The truth is in the ten years or so I have been out of school I have been fighting bad code every step of the way. I can’t remember when was the last time I had to solve an algorithmic problem. The most complex/algorithmic intensive code I have written was Testability Explorer, which is a byte code analysis engine which tries to determine how testable your code is. I have written it in my free time, and the thing which enabled me to write such a complex “algorithm” were unit tests, and lots of them! I had to rely on “best-engineering-practices” to build something which is “algorithm intensive”. In other words it is my engineering background not my CS which made it possible. I think CS, is required but insufficient.

Going Forward

I would love for the industry to reflect on itself and realize that its problems is not lack of CS majors, or a the lack of bright people, but a lack of good old fashion engineers, thetn maybe we may start asking a lot more questions, to which the answer is not a single method, but a collection of classes interacting together. It took a handful of scientist to come up with an atom bomb, but it took countless of engineers to work out everything else, and software is no different. You need a handful of CS, and an army of engineers.

→ 30 CommentsTags: Uncategorized

Why are we embarrassed to admit that we don’t know how to write tests?

posted on July 7th, 2009 ·

Take your average developer and ask “do you know language/technology X?” None of us will feel any shame in admitting that we do not know X. After all there are so many languages, frameworks and technologies, how could you know them all? But what if X is writing testable code? Somehow we have trouble answering the question “do you know how to write tests?” Everyone says yes, whether or not  we actually know it. It is as if there is some shame in admitting that you don’t know how to write tests.

Now I am not suggesting that people knowingly lie here, it is just that they think there is nothing to it. We think: I know how to write code, I think my code is pretty good, therefore my code is testable!

I personally think that we would do a lot better if we would recognize testability as a skill in its own right. And as such skills are not innate and take years of practice to develop. We could than treat it as any other skill and freely admit that we don’t know it. We could than do something about it. We could offer classes, or other materials to grow our developers, but instead we treat it like breathing. We think that any developer can write testable code.

It took me two years of writing tests first, where I had as much tests as production code, before I started to understand what is the difference between testable and hard to test code. Ask yourself, how long have you been writing tests? What percentage of the code you write is tests?

Here is a question which you can ask to prove my point: “How do you write hard to test code?” I like to ask this question in interviews and most of the time I get silence. Sometimes I get people to say, make things private. Well if visibility is your only problem, I have a RegExp for you which will solve all of your problems. The truth is a lot more complicated, the code is hard to test doe to its structure, not doe to its naming conventions  or visibility. Do you know the answer?

We all start at the same place. When I first heard about testing I immediately thought about writing a framework which will pretend to be a user so that I can put the app through its paces. It is only natural to thing this way. This kind of tests are called end-to-end-tests (or scenario or large tests), and they should be the last kind of tests which you write not the first thing you think of. End-to-end-tests are great for locating wiring bugs but are pretty bad at locating logical bugs. And most of your mistakes are in logical bugs, those are the hard ones to find. I find it a bit amusing that to fight buggy code we write even more complex framework which will pretends to be the user, so now we have even more code to test.

Everyone is in search of some magic test framework, technology, the know-how, which will solve the testing woes. Well I have news for you: there is no such thing. The secret in tests is in writing testable code, not in knowing some magic on testing side. And it certainly is not in some company which will sell you some test automation framework. Let me make this super clear: The secret in testing is in writing testable-code! You need to go after your developers not your test-organization.

Now lets think about this. Most organizations have developers which write code and than a test organization to test it. So let me make sure I understand. There is a group of people which write untestable code and a group which desperately tries to put tests around the untestable code. (Oh and test-group is not allowed to change the production code.) The developers are where the mistakes are made, and testers are the ones who feel the pain. Do you think that the developers have any incentive to change their behavior if they don’t feel the pain of their mistakes? Can the test-organization be effective if they can’t change the production code?

It is so easy to hide behind a “framework” which needs to be built/bought and things will be better. But the root cause is the untestable code, and until we learn to admit that we don’t know how to write testable code, nothing is going to change…

→ 17 CommentsTags: Uncategorized