{"id":1460,"date":"2011-02-09T15:25:51","date_gmt":"2011-02-09T05:25:51","guid":{"rendered":"http:\/\/www.somethinkodd.com\/oddthinking\/?p=1460"},"modified":"2011-02-09T15:25:51","modified_gmt":"2011-02-09T05:25:51","slug":"unit-tests-considered","status":"publish","type":"post","link":"https:\/\/www.somethinkodd.com\/oddthinking\/2011\/02\/09\/unit-tests-considered\/","title":{"rendered":"Unit-tests considered&#8230;"},"content":{"rendered":"<p>Here is a short, fictionalised, autobiographical play I wrote. All of the parts are played by me.<\/p>\n<p><strong>Business Analyst:<\/strong> We need to transfer files from place to place, we need a progress bar to tell us how much is complete and an estimate of how long to go.<\/p>\n<p><strong>Programmer:<\/strong> Okay, let&#8217;s have a layered architecture.<br \/>\n<a href=\"http:\/\/www.somethinkodd.com\/oddthinking\/wp-content\/uploads\/2011\/02\/progress_layers.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.somethinkodd.com\/oddthinking\/wp-content\/uploads\/2011\/02\/progress_layers-300x225.png\" alt=\"\" title=\"Layer Diagram for Architecture\" width=\"300\" height=\"225\" class=\"aligncenter size-medium wp-image-1462\" srcset=\"https:\/\/www.somethinkodd.com\/oddthinking\/wp-content\/uploads\/2011\/02\/progress_layers-300x225.png 300w, https:\/\/www.somethinkodd.com\/oddthinking\/wp-content\/uploads\/2011\/02\/progress_layers-150x112.png 150w, https:\/\/www.somethinkodd.com\/oddthinking\/wp-content\/uploads\/2011\/02\/progress_layers.png 960w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><br \/>\nAt the bottom is the built-in I\/O subsystem, that takes packets and transfers them.<\/p>\n<p>Above that is File Transfer layer, which takes care of breaking the file into packets, and sending them down to the I\/O subsystem. It notifies its client with a message for every 256 KB transfer completed.<\/p>\n<p>Above that is the Progress Tracker layer. It monitors the messages, and estimates how long there is to go. Estimation is a black-art. We may need to try several different strategies here until we find one we can trust.<\/p>\n<p>Finally, at the top is a simple Progress Bar, that uses the estimates to display to the user.<\/p>\n<p><strong>Unit Test Advocate:<\/strong> Make sure you have an automated test suite that can be run at any time to convince everyone it is working.<\/p>\n<p><strong>Programmer:<\/strong> Okay, good idea. Let&#8217;s get started. First, I will build the File Transfer layer. Easy! Now in order to test it, I need to be able to simulate various  transfer success and failure scenarios. Looks like I need to write a I\/O subsystem simulator. Not quite so easy, but now it is done. Now, I have automated testing, and I trust my File Transfer layer.<\/p>\n<p>Next, the Progress Tracking layer. I am going to use quadrilateral wavelet theory to perform the estimates. It was tricky, but it is done. I can use the I\/O simulator to stimulate the File Transfer layer to test all the different scenarios in the Progress Tracking layer. Testing is a little painful, because there is a lot of working out of quadrilateral wavelet theory by hand, but done!<\/p>\n<p>Now, the Progress Bar. This is fairly straightforward to write. There aren&#8217;t many test cases, but so let&#8217;s plonk it on top of the Progress Tracking layer. The test cases I have cover most of the code paths, and just a little bit more hand-computed quadrilateral wavelet theory, and I can cover the rest. The same computations can be used to throw in a few more cheap tests of the Progress Tracking layer. Done!<\/p>\n<p><strong>Unit Test Advocate:<\/strong> It took a while to develop those unit-tests, but now you can be confident it works.<\/p>\n<p><strong>Programmer:<\/strong> Yes, they are beautiful. I am so happy.<\/p>\n<p><strong>Business Analyst:<\/strong> Users are reporting that the progress bar sometimes goes backwards. Also, when it says there is an hour left to go, they leave for an hour and they come back and it isn&#8217;t done. They hate that.<\/p>\n<p><strong>Programmer:<\/strong> That&#8217;s not a coding bug; that is consistent with quadrilateral wavelet theory. It tends to underestimate. Let&#8217;s go with monopolar superpositioning theory. It tends to overestimate, which will make people less annoyed.<\/p>\n<p>It&#8217;ll take me a while to implement that, and I need to maintain the old version in the meantime. I am going to create a parallel implementation of the Progress Tracking layer with a different name. When it is ready, I will just swap over the Progress Bar to import the new layer rather than the old one.<\/p>\n<p>Whew! That was hard work. But it is done, and I have unit-tested it, with a lot more calculations by hand. <\/p>\n<p>Now I can delete the Quadrilateral Wavelet implementation. Wait! My unit-tests for the Progress Bar depends on the exact results from the Quadrilateral Wavelet implementation. They won&#8217;t work with the results from the new implementation.<\/p>\n<p>Oh well. Rather than delete it, I will just leave it in place and treat it simulator test code. The live code will use the Monopolar Superpositioning version of the Progress Tracking later. That is unit-tested. It will also use the Progress Bar (which is unit-tested with a simulator that happens to generate its results using some weird formula that doesn&#8217;t matter anymore). The API is simple enough, there were no changes to the Progress Bar required. There should be no integration problems. Look, there wasn&#8217;t. Perfect.<\/p>\n<p><strong>Business Analyst:<\/strong> Hey, I have a quick request. Users are reporting that the progress bar isn&#8217;t updated frequently enough. Change it to update every 1 KB transferred.<\/p>\n<p><strong>Programmer:<\/strong> NOOOO!<\/p>\n<p><strong>Business Analyst:<\/strong> What? That&#8217;s a simple enough change. It is one constant in the File Transfer layer. Shouldn&#8217;t take long at all. You have lots of unit-tests, so changes should be cheap and safe.<\/p>\n<p><strong>Programmer:<\/strong> But when I change the constant in the File Transfer layer, I also have to change the test cases for the File Transfer layer. Which is fine &#8211; that&#8217;s the accepted cost of writing unit-tests.<\/p>\n<p>Then I have to change the equivalent constant in the formula used by Monopolar Superpositioning layer. And then I have to rework out all the Progress Layer test cases by hand, with the new numbers.<\/p>\n<p>But, worse! Then I need to change the Quadrilateral Wavelet code &#8211; that I can barely remember and isn&#8217;t used in production code. And then fix its test-cases. And then recalculate all the test-cases I need to test the Progress Bar. This will take days.<\/p>\n<p>That&#8217;s a lot of work to maintain the tests for the Progress Bar &#8211; a component that isn&#8217;t being touched and is already unit-tested and trusted, when the customers are calling for an unrelated new feature in the File Transfer Layer.<\/p>\n<p>Maybe I could just throw-away the Progress Bar unit tests?<\/p>\n<p><strong>Unit Test Advocate:<\/strong> DON&#8217;T YOU DARE! One day, you will need to refactor it, and so you should maintain a working set of test cases until then. So, write a simulator for the Progress Layer to test the Progress Bar.<\/p>\n<p><strong>Programmer:<\/strong> The Progress Bar just imports the lower layer. I can&#8217;t just pass a new value in during the test. <\/p>\n<p><strong>Unit Test Advocate:<\/strong> So, your code isn&#8217;t made to be easy to test! Rewrite it to be parameterised by Progress Layer, so you can substitute a mock sub-layer. <\/p>\n<p><strong>Programmer:<\/strong> That&#8217;s a lot of refactoring. These unit-tests are starting to cost me a lot of time.<\/p>\n<p><strong>Unit Test Advocate:<\/strong> Refactoring is easy, if you have a good set of unit tests.<\/p>\n<p><strong>Programmer:<\/strong> Fuck off. <\/p>\n<p><strong>Julian:<\/strong> Bugger this for a joke. I have working code; I just can&#8217;t prove it. I am off to write a blog article.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Here is a short, fictionalised, autobiographical play I wrote, in which unit-tests cause more technical debt than the code.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_s2mail":"yes","footnotes":""},"categories":[23,35,34,1],"tags":[],"class_list":["post-1460","post","type-post","status-publish","format-standard","hentry","category-based-on-a-true-story","category-heroic-failures","category-software-development","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/www.somethinkodd.com\/oddthinking\/wp-json\/wp\/v2\/posts\/1460","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.somethinkodd.com\/oddthinking\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.somethinkodd.com\/oddthinking\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.somethinkodd.com\/oddthinking\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.somethinkodd.com\/oddthinking\/wp-json\/wp\/v2\/comments?post=1460"}],"version-history":[{"count":7,"href":"https:\/\/www.somethinkodd.com\/oddthinking\/wp-json\/wp\/v2\/posts\/1460\/revisions"}],"predecessor-version":[{"id":1468,"href":"https:\/\/www.somethinkodd.com\/oddthinking\/wp-json\/wp\/v2\/posts\/1460\/revisions\/1468"}],"wp:attachment":[{"href":"https:\/\/www.somethinkodd.com\/oddthinking\/wp-json\/wp\/v2\/media?parent=1460"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.somethinkodd.com\/oddthinking\/wp-json\/wp\/v2\/categories?post=1460"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.somethinkodd.com\/oddthinking\/wp-json\/wp\/v2\/tags?post=1460"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}