<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3898534372669113633</id><updated>2011-11-12T03:04:18.672-08:00</updated><category term='MDA'/><category term='Marshmallow'/><category term='TDD'/><category term='SICP'/><category term='Functional Programming'/><category term='Agile'/><category term='Certification'/><category term='C'/><category term='Scrum'/><category term='Clojure'/><category term='KandR'/><category term='podcasts'/><category term='Midje'/><category term='Design Patterns'/><category term='Transformation Priority Premise'/><category term='STUB'/><category term='visitor'/><title type='text'>The Clean Coder</title><subtitle type='html'>A notebook for software craftsmen and engineers.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>32</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-5853311456454867669</id><published>2011-02-04T07:56:00.000-08:00</published><updated>2011-02-04T07:56:30.610-08:00</updated><title type='text'>This Blog has Moved.</title><content type='html'>I won't be posting here anymore.&amp;nbsp; My new blog is at &lt;a href="http://cleancoder.posterous.com/"&gt;http://cleancoder.posterous.com/&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-5853311456454867669?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/5853311456454867669/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2011/02/this-blog-has-moved.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/5853311456454867669'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/5853311456454867669'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2011/02/this-blog-has-moved.html' title='This Blog has Moved.'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-1075192503119055527</id><published>2011-02-03T09:11:00.001-08:00</published><updated>2011-02-03T09:11:26.298-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Transformation Priority Premise'/><title type='text'>FLASH: TPP</title><content type='html'>&lt;div class='posterous_autopost'&gt;&lt;h1&gt;Flash Cards: T-P Premise&lt;/h1&gt;  &lt;p&gt;I read a nice &lt;a href="http://madcoderspeak.blogspot.com/2011/02/flash-cards-kata-and-transformation.html"&gt;blog&lt;/a&gt; today exploring the &lt;a href="http://cleancoder.posterous.com/the-transformation-priority-premise"&gt;Transformation Priority Premise&lt;/a&gt; using the flash card kata.  The author did it in both lisp and C#.  Let&amp;rsquo;s try it in Java.&lt;/p&gt;  &lt;p&gt;The flash card kata is pretty straightforward.  Given a set of questions and answers, ask the user each question and solicit an answer.  If the answer is correct, say so and count it.  If the answer is wrong show the correct answer and count the error.  At the end, print the number of right and wrong answers.&lt;/p&gt;  &lt;p&gt;The first test is wonderfully simple.  Given an empty list of questions and answers, end the game immediately with a summary showing nothing right and nothing wrong.&lt;/p&gt;  &lt;p&gt;We begin with an empty test which passes:&lt;/p&gt;  &lt;div class="CodeRay"&gt; &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;flashCardTest&lt;/span&gt; { &lt;span class="at"&gt;@Test&lt;/span&gt; &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;void&lt;/span&gt; degenerateGame() &lt;span class="di"&gt;throws&lt;/span&gt; &lt;span class="ex"&gt;Exception&lt;/span&gt; { } }&lt;/pre&gt;&lt;/div&gt; &lt;/div&gt;   &lt;p&gt;We get the test to fail by asserting the answer we want and by doing a couple of &lt;strong&gt;({}&amp;ndash;&gt;nil)&lt;/strong&gt; transforms.  (In this case -1 is the integer equivalent of nil, e.g. a degenerate value)&lt;/p&gt;  &lt;div class="CodeRay"&gt; &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;FlashCardTest&lt;/span&gt; { &lt;span class="at"&gt;@Test&lt;/span&gt; &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;void&lt;/span&gt; rightAndWrongShouldBeZeroIfGamePlayedWithNoCards() { &lt;span class="pt"&gt;List&lt;/span&gt; emptyList = &lt;span class="kw"&gt;new&lt;/span&gt; &lt;span class="pt"&gt;ArrayList&lt;/span&gt;(); playGame(emptyList); assertEquals(&lt;span class="i"&gt;0&lt;/span&gt;, rightAnswers()); assertEquals(&lt;span class="i"&gt;0&lt;/span&gt;, wrongAnswers()); }  &lt;span class="di"&gt;private&lt;/span&gt; &lt;span class="ty"&gt;int&lt;/span&gt; wrongAnswers() { &lt;span class="kw"&gt;return&lt;/span&gt; -&lt;span class="i"&gt;1&lt;/span&gt;; }  &lt;span class="di"&gt;private&lt;/span&gt; &lt;span class="ty"&gt;int&lt;/span&gt; rightAnswers() { &lt;span class="kw"&gt;return&lt;/span&gt; -&lt;span class="i"&gt;1&lt;/span&gt;; }  &lt;span class="di"&gt;private&lt;/span&gt; &lt;span class="ty"&gt;void&lt;/span&gt; playGame(&lt;span class="pt"&gt;List&lt;/span&gt; flashCards) { } }&lt;/pre&gt;&lt;/div&gt; &lt;/div&gt;   &lt;p&gt;To get this to pass just need to do some &lt;strong&gt;(nil-&gt;constant)&lt;/strong&gt; transforms.&lt;/p&gt;  &lt;div class="CodeRay"&gt; &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="di"&gt;private&lt;/span&gt; &lt;span class="ty"&gt;int&lt;/span&gt; wrongAnswers() { &lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="i"&gt;0&lt;/span&gt;; }  &lt;span class="di"&gt;private&lt;/span&gt; &lt;span class="ty"&gt;int&lt;/span&gt; rightAnswers() { &lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="i"&gt;0&lt;/span&gt;; }&lt;/pre&gt;&lt;/div&gt; &lt;/div&gt;   &lt;p&gt;This solution is a bit ugly since it couples the test and the solution.  So let&amp;rsquo;s refactor to create a class.&lt;/p&gt;  &lt;div class="CodeRay"&gt; &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;FlashCardTest&lt;/span&gt; { &lt;span class="at"&gt;@Test&lt;/span&gt; &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;void&lt;/span&gt; rightAndWrongShouldBeZeroIfGamePlayedWithNoCards() { FlashCardGame flashCardGame = &lt;span class="kw"&gt;new&lt;/span&gt; FlashCardGame(); &lt;span class="pt"&gt;List&lt;/span&gt; emptyList = &lt;span class="kw"&gt;new&lt;/span&gt; &lt;span class="pt"&gt;ArrayList&lt;/span&gt;();  flashCardGame.playGame(emptyList);  assertEquals(&lt;span class="i"&gt;0&lt;/span&gt;, flashCardGame.rightAnswers()); assertEquals(&lt;span class="i"&gt;0&lt;/span&gt;, flashCardGame.wrongAnswers()); } }&lt;/pre&gt;&lt;/div&gt; &lt;/div&gt;   &lt;hr /&gt;  &lt;div class="CodeRay"&gt; &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;FlashCardGame&lt;/span&gt; { &lt;span class="di"&gt;public&lt;/span&gt; FlashCardGame() { }  &lt;span class="ty"&gt;int&lt;/span&gt; wrongAnswers() { &lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="i"&gt;0&lt;/span&gt;; }  &lt;span class="ty"&gt;int&lt;/span&gt; rightAnswers() { &lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="i"&gt;0&lt;/span&gt;; }  &lt;span class="ty"&gt;void&lt;/span&gt; playGame(&lt;span class="pt"&gt;List&lt;/span&gt; flashCards) { } }&lt;/pre&gt;&lt;/div&gt; &lt;/div&gt;   &lt;p&gt;For the next test, lets try a game with a single flash card, that the user gets right.&lt;/p&gt;  &lt;div class="CodeRay"&gt; &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="at"&gt;@Test&lt;/span&gt; &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;void&lt;/span&gt; rightShouldBeOneIfOneRightAnswer() { FlashCard card = &lt;span class="kw"&gt;new&lt;/span&gt; FlashCard(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Q&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;); &lt;span class="pt"&gt;List&lt;/span&gt; cards = &lt;span class="kw"&gt;new&lt;/span&gt; &lt;span class="pt"&gt;ArrayList&lt;/span&gt;(); cards.add(card);  flashCardGame.playGame(cards); assertEquals(&lt;span class="i"&gt;1&lt;/span&gt;, flashCardGame.rightAnswers()); assertEquals(&lt;span class="i"&gt;0&lt;/span&gt;, flashCardGame.wrongAnswers()); }&lt;/pre&gt;&lt;/div&gt; &lt;/div&gt;   &lt;p&gt;This fails of course.  We can make it pass by simply incrementing the right count in &lt;code&gt;playGame&lt;/code&gt; if the list of cards is not zero.  This is a &lt;strong&gt;(unconditional-&gt;if)&lt;/strong&gt; transform. That, plus a little refactoring gives us:&lt;/p&gt;  &lt;div class="CodeRay"&gt; &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;FlashCardGame&lt;/span&gt; { &lt;span class="di"&gt;private&lt;/span&gt; &lt;span class="ty"&gt;int&lt;/span&gt; rightAnswers;  &lt;span class="di"&gt;public&lt;/span&gt; FlashCardGame() { }  &lt;span class="ty"&gt;int&lt;/span&gt; getWrongAnswers() { &lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="i"&gt;0&lt;/span&gt;; }  &lt;span class="ty"&gt;int&lt;/span&gt; getRightAnswers() { &lt;span class="kw"&gt;return&lt;/span&gt; rightAnswers; }  &lt;span class="ty"&gt;void&lt;/span&gt; playGame(&lt;span class="pt"&gt;List&lt;/span&gt; flashCards, FlashCardTest answerer) { &lt;span class="kw"&gt;if&lt;/span&gt; (flashCards.size() != &lt;span class="i"&gt;0&lt;/span&gt;) rightAnswers++; } }&lt;/pre&gt;&lt;/div&gt; &lt;/div&gt;   &lt;p&gt;OK, so let&amp;rsquo;s try a wrong answer.&lt;/p&gt;  &lt;div class="CodeRay"&gt; &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="at"&gt;@Test&lt;/span&gt; &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;void&lt;/span&gt; wrongShouldBeOneIfOneWrongAnswer() { FlashCard card = &lt;span class="kw"&gt;new&lt;/span&gt; FlashCard(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;QW&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;); &lt;span class="pt"&gt;List&lt;/span&gt; cards = &lt;span class="kw"&gt;new&lt;/span&gt; &lt;span class="pt"&gt;ArrayList&lt;/span&gt;(); cards.add(card);  flashCardGame.playGame(cards); assertEquals(&lt;span class="i"&gt;0&lt;/span&gt;, flashCardGame.getRightAnswers()); assertEquals(&lt;span class="i"&gt;1&lt;/span&gt;, flashCardGame.getWrongAnswers()); }  &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="pt"&gt;String&lt;/span&gt; answerQuestion(&lt;span class="pt"&gt;String&lt;/span&gt; question) { &lt;span class="kw"&gt;if&lt;/span&gt; (question.equals(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;QR&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)) &lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;; &lt;span class="kw"&gt;else&lt;/span&gt; &lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;W&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;; }&lt;/pre&gt;&lt;/div&gt; &lt;/div&gt;   &lt;p&gt;This forced us to create the &lt;code&gt;answerQuestion&lt;/code&gt; function that pretends to be a user answering questions.  If you pass in &amp;ldquo;QR&amp;rdquo; you get the right answer &amp;ldquo;A&amp;rdquo;.  If you pass in &amp;ldquo;QW&amp;rdquo; you get the wrong answer &amp;ldquo;W&amp;rdquo;.  To get this test to pass we&amp;rsquo;re going to have to get this function called by &lt;code&gt;playGame&lt;/code&gt;.  We can do this by passing the test along in an argument using the Change Signature refactoring.  Then we can use a &lt;strong&gt;(unconditional-&gt;if)&lt;/strong&gt; transform to check the value of our new function.&lt;/p&gt;  &lt;div class="CodeRay"&gt; &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;FlashCardGame&lt;/span&gt; { &lt;span class="di"&gt;private&lt;/span&gt; &lt;span class="ty"&gt;int&lt;/span&gt; rightAnswers; &lt;span class="di"&gt;private&lt;/span&gt; &lt;span class="ty"&gt;int&lt;/span&gt; wrongAnswers;  &lt;span class="di"&gt;public&lt;/span&gt; FlashCardGame() { }  &lt;span class="ty"&gt;int&lt;/span&gt; getWrongAnswers() { &lt;span class="kw"&gt;return&lt;/span&gt; wrongAnswers; }  &lt;span class="ty"&gt;int&lt;/span&gt; getRightAnswers() { &lt;span class="kw"&gt;return&lt;/span&gt; rightAnswers; }  &lt;span class="ty"&gt;void&lt;/span&gt; playGame(&lt;span class="pt"&gt;List&lt;/span&gt; flashCards, FlashCardTest answerer) { &lt;span class="kw"&gt;if&lt;/span&gt; (flashCards.size() != &lt;span class="i"&gt;0&lt;/span&gt;) { &lt;span class="pt"&gt;String&lt;/span&gt; question = flashCards.get(&lt;span class="i"&gt;0&lt;/span&gt;).getQuestion(); &lt;span class="kw"&gt;if&lt;/span&gt; (answerer.answerQuestion(question).equals(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)) rightAnswers++; &lt;span class="kw"&gt;else&lt;/span&gt; wrongAnswers++; } } }&lt;/pre&gt;&lt;/div&gt; &lt;/div&gt;   &lt;p&gt;Of course this is hideous, so we need to refactor alot.&lt;/p&gt;  &lt;div class="CodeRay"&gt; &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;interface&lt;/span&gt; &lt;span class="cl"&gt;User&lt;/span&gt; { &lt;span class="pt"&gt;String&lt;/span&gt; answerQuestion(&lt;span class="pt"&gt;String&lt;/span&gt; question); }  ----  &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;MockUser&lt;/span&gt; &lt;span class="di"&gt;implements&lt;/span&gt; User { &lt;span class="di"&gt;public&lt;/span&gt; MockUser() { }  &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="pt"&gt;String&lt;/span&gt; answerQuestion(&lt;span class="pt"&gt;String&lt;/span&gt; question) { &lt;span class="kw"&gt;if&lt;/span&gt; (question.equals(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;QR&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)) &lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;; &lt;span class="kw"&gt;else&lt;/span&gt; &lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;W&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;; } }  ----  &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;FlashCardGame&lt;/span&gt; { &lt;span class="di"&gt;private&lt;/span&gt; &lt;span class="ty"&gt;int&lt;/span&gt; rightAnswers; &lt;span class="di"&gt;private&lt;/span&gt; &lt;span class="ty"&gt;int&lt;/span&gt; wrongAnswers;  &lt;span class="di"&gt;public&lt;/span&gt; FlashCardGame() { }  &lt;span class="ty"&gt;int&lt;/span&gt; getWrongAnswers() { &lt;span class="kw"&gt;return&lt;/span&gt; wrongAnswers; }  &lt;span class="ty"&gt;int&lt;/span&gt; getRightAnswers() { &lt;span class="kw"&gt;return&lt;/span&gt; rightAnswers; }  &lt;span class="ty"&gt;void&lt;/span&gt; playGame(&lt;span class="pt"&gt;List&lt;/span&gt; flashCards, User user) { &lt;span class="kw"&gt;if&lt;/span&gt; (flashCards.size() != &lt;span class="i"&gt;0&lt;/span&gt;) { &lt;span class="pt"&gt;String&lt;/span&gt; question = flashCards.get(&lt;span class="i"&gt;0&lt;/span&gt;).getQuestion(); &lt;span class="pt"&gt;String&lt;/span&gt; answer = user.answerQuestion(question); &lt;span class="kw"&gt;if&lt;/span&gt; (answer.equals(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)) rightAnswers++; &lt;span class="kw"&gt;else&lt;/span&gt; wrongAnswers++; } } }  ----  &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;FlashCardTest&lt;/span&gt; { &lt;span class="di"&gt;private&lt;/span&gt; FlashCardGame flashCardGame; &lt;span class="di"&gt;private&lt;/span&gt; MockUser user = &lt;span class="kw"&gt;new&lt;/span&gt; MockUser();  &lt;span class="at"&gt;@Before&lt;/span&gt; &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;void&lt;/span&gt; setUp() &lt;span class="di"&gt;throws&lt;/span&gt; &lt;span class="ex"&gt;Exception&lt;/span&gt; { flashCardGame = &lt;span class="kw"&gt;new&lt;/span&gt; FlashCardGame(); user = &lt;span class="kw"&gt;new&lt;/span&gt; MockUser(); }  &lt;span class="at"&gt;@Test&lt;/span&gt; &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;void&lt;/span&gt; rightAndWrongShouldBeZeroIfGamePlayedWithNoCards() { &lt;span class="pt"&gt;List&lt;/span&gt; emptyList = &lt;span class="kw"&gt;new&lt;/span&gt; &lt;span class="pt"&gt;ArrayList&lt;/span&gt;();  flashCardGame.playGame(emptyList, user);  assertEquals(&lt;span class="i"&gt;0&lt;/span&gt;, flashCardGame.getRightAnswers()); assertEquals(&lt;span class="i"&gt;0&lt;/span&gt;, flashCardGame.getWrongAnswers()); }  &lt;span class="at"&gt;@Test&lt;/span&gt; &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;void&lt;/span&gt; rightShouldBeOneIfOneRightAnswer() { FlashCard card = &lt;span class="kw"&gt;new&lt;/span&gt; FlashCard(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;QR&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;); &lt;span class="pt"&gt;List&lt;/span&gt; cards = &lt;span class="kw"&gt;new&lt;/span&gt; &lt;span class="pt"&gt;ArrayList&lt;/span&gt;(); cards.add(card);  flashCardGame.playGame(cards, user); assertEquals(&lt;span class="i"&gt;1&lt;/span&gt;, flashCardGame.getRightAnswers()); assertEquals(&lt;span class="i"&gt;0&lt;/span&gt;, flashCardGame.getWrongAnswers()); }  &lt;span class="at"&gt;@Test&lt;/span&gt; &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;void&lt;/span&gt; wrongShouldBeOneIfOneWrongAnswer() { FlashCard card = &lt;span class="kw"&gt;new&lt;/span&gt; FlashCard(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;QW&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;); &lt;span class="pt"&gt;List&lt;/span&gt; cards = &lt;span class="kw"&gt;new&lt;/span&gt; &lt;span class="pt"&gt;ArrayList&lt;/span&gt;(); cards.add(card);  flashCardGame.playGame(cards, user); assertEquals(&lt;span class="i"&gt;0&lt;/span&gt;, flashCardGame.getRightAnswers()); assertEquals(&lt;span class="i"&gt;1&lt;/span&gt;, flashCardGame.getWrongAnswers()); } }&lt;/pre&gt;&lt;/div&gt; &lt;/div&gt;   &lt;p&gt;Now let&amp;rsquo;s do two questions, one right and one wrong.&lt;/p&gt;  &lt;div class="CodeRay"&gt; &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="at"&gt;@Test&lt;/span&gt; &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;void&lt;/span&gt; countBothOneRightAndOneWrong() { &lt;span class="pt"&gt;List&lt;/span&gt; cards = &lt;span class="kw"&gt;new&lt;/span&gt; &lt;span class="pt"&gt;ArrayList&lt;/span&gt;(); cards.add(&lt;span class="kw"&gt;new&lt;/span&gt; FlashCard(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;QW&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)); cards.add(&lt;span class="kw"&gt;new&lt;/span&gt; FlashCard(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;QR&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;));  flashCardGame.playGame(cards, user); assertEquals(&lt;span class="i"&gt;1&lt;/span&gt;, flashCardGame.getRightAnswers()); assertEquals(&lt;span class="i"&gt;1&lt;/span&gt;, flashCardGame.getWrongAnswers()); }&lt;/pre&gt;&lt;/div&gt; &lt;/div&gt;   &lt;p&gt;This fails, but we can make it pass with a &lt;strong&gt;(if-&gt;while)&lt;/strong&gt; transform.&lt;/p&gt;  &lt;div class="CodeRay"&gt; &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="ty"&gt;void&lt;/span&gt; playGame(&lt;span class="pt"&gt;List&lt;/span&gt; flashCards, User user) { &lt;span class="kw"&gt;for&lt;/span&gt; (FlashCard card : flashCards) { &lt;span class="pt"&gt;String&lt;/span&gt; question = card.getQuestion(); &lt;span class="pt"&gt;String&lt;/span&gt; answer = user.answerQuestion(question); &lt;span class="kw"&gt;if&lt;/span&gt; (answer.equals(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)) rightAnswers++; &lt;span class="kw"&gt;else&lt;/span&gt; wrongAnswers++; } }&lt;/pre&gt;&lt;/div&gt; &lt;/div&gt;   &lt;p&gt;One thing left.  We need to actually compare the answer in the flashcard to the response from the user.&lt;/p&gt;  &lt;div class="CodeRay"&gt; &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="at"&gt;@Test&lt;/span&gt; &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;void&lt;/span&gt; countThreeNewQuestionsTwoRightOneWrong() { &lt;span class="pt"&gt;List&lt;/span&gt; cards = &lt;span class="kw"&gt;new&lt;/span&gt; &lt;span class="pt"&gt;ArrayList&lt;/span&gt;(); cards.add(&lt;span class="kw"&gt;new&lt;/span&gt; FlashCard(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Q1&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;1&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)); cards.add(&lt;span class="kw"&gt;new&lt;/span&gt; FlashCard(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Q2&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;2&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)); cards.add(&lt;span class="kw"&gt;new&lt;/span&gt; FlashCard(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;Q3&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;, &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;wrong&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;));  flashCardGame.playGame(cards, user); assertEquals(&lt;span class="i"&gt;2&lt;/span&gt;, flashCardGame.getRightAnswers()); assertEquals(&lt;span class="i"&gt;1&lt;/span&gt;, flashCardGame.getWrongAnswers()); }&lt;/pre&gt;&lt;/div&gt; &lt;/div&gt;   &lt;p&gt;We need to make a small change to the Mock.&lt;/p&gt;  &lt;div class="CodeRay"&gt; &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;MockUser&lt;/span&gt; &lt;span class="di"&gt;implements&lt;/span&gt; User { &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="pt"&gt;String&lt;/span&gt; answerQuestion(&lt;span class="pt"&gt;String&lt;/span&gt; question) { &lt;span class="kw"&gt;if&lt;/span&gt; (question.equals(&lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;QR&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;)) &lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="s"&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;A&lt;/span&gt;&lt;span class="dl"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;; &lt;span class="kw"&gt;else&lt;/span&gt; { &lt;span class="kw"&gt;return&lt;/span&gt; question.substring(&lt;span class="i"&gt;1&lt;/span&gt;); } } }&lt;/pre&gt;&lt;/div&gt; &lt;/div&gt;   &lt;p&gt;And now we can make this pass with a simple &lt;strong&gt;(expression-&gt;function)&lt;/strong&gt; transform.&lt;/p&gt;  &lt;div class="CodeRay"&gt; &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="ty"&gt;void&lt;/span&gt; playGame(&lt;span class="pt"&gt;List&lt;/span&gt; flashCards, User user) { &lt;span class="kw"&gt;for&lt;/span&gt; (FlashCard card : flashCards) { &lt;span class="pt"&gt;String&lt;/span&gt; question = card.getQuestion(); &lt;span class="pt"&gt;String&lt;/span&gt; answer = user.answerQuestion(question); &lt;span class="kw"&gt;if&lt;/span&gt; (answer.equals(card.getAnswer())) rightAnswers++; &lt;span class="kw"&gt;else&lt;/span&gt; wrongAnswers++; } }&lt;/pre&gt;&lt;/div&gt; &lt;/div&gt;   &lt;p&gt;There&amp;rsquo;s more to do, of course, but the plumbing is all set up, and the algorithm looks right.  There were several cases where we &lt;em&gt;could&lt;/em&gt; have used a lower transform such as &lt;strong&gt;(variable-&gt;assignment)&lt;/strong&gt; but there was no need, and the algorithm came out nicely.&lt;/p&gt;  &lt;p&gt;There is just the slightest chance that the one use of &lt;strong&gt;(if-&gt;while)&lt;/strong&gt; could have been done with &lt;strong&gt;(statement-&gt;tail-recursion)&lt;/strong&gt;, but since this is Java, that&amp;rsquo;s probably not the best choice.&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-1075192503119055527?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/1075192503119055527/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2011/02/flash-tpp.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/1075192503119055527'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/1075192503119055527'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2011/02/flash-tpp.html' title='FLASH: TPP'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-8789706689010113680</id><published>2011-02-02T07:44:00.001-08:00</published><updated>2011-02-02T07:44:03.842-08:00</updated><title type='text'>Fib: The T-P Premise.</title><content type='html'>&lt;div class='posterous_autopost'&gt;&lt;p&gt;Guilherme Silveira wrote a lovely &lt;a href="http://blog.caelumobjects.com/2011/01/13/evolving-software-and-improving-algorithms/"&gt;blog&lt;/a&gt; exploring the &lt;a href="http://cleancoder.posterous.com/the-transformation-priority-premise"&gt;Transformation Priority Premise&lt;/a&gt; using the Fibonacci sequence.  He posed a suite of tests similar to these:&lt;/p&gt;  &lt;div class="CodeRay"&gt; &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="at"&gt;@Test&lt;/span&gt; &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;void&lt;/span&gt; fibTest() &lt;span class="di"&gt;throws&lt;/span&gt; &lt;span class="ex"&gt;Exception&lt;/span&gt; { assertEquals(&lt;span class="i"&gt;0&lt;/span&gt;, of(&lt;span class="i"&gt;0&lt;/span&gt;)); assertEquals(&lt;span class="i"&gt;1&lt;/span&gt;, of(&lt;span class="i"&gt;1&lt;/span&gt;)); assertEquals(&lt;span class="i"&gt;1&lt;/span&gt;, of(&lt;span class="i"&gt;2&lt;/span&gt;)); assertEquals(&lt;span class="i"&gt;2&lt;/span&gt;, of(&lt;span class="i"&gt;3&lt;/span&gt;)); assertEquals(&lt;span class="i"&gt;3&lt;/span&gt;, of(&lt;span class="i"&gt;4&lt;/span&gt;)); assertEquals(&lt;span class="i"&gt;5&lt;/span&gt;, of(&lt;span class="i"&gt;5&lt;/span&gt;)); assertEquals(&lt;span class="i"&gt;8&lt;/span&gt;, of(&lt;span class="i"&gt;6&lt;/span&gt;)); }&lt;/pre&gt;&lt;/div&gt; &lt;/div&gt;   &lt;p&gt;He found that the proposed list of transformations did not lead him to a good solution.  At first he found that the transformations led him to a solution like this:&lt;/p&gt;  &lt;div class="CodeRay"&gt; &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="kw"&gt;switch&lt;/span&gt;(n) { &lt;span class="kw"&gt;case&lt;/span&gt; &lt;span class="i"&gt;0&lt;/span&gt;: &lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="i"&gt;0&lt;/span&gt;; &lt;span class="kw"&gt;case&lt;/span&gt; &lt;span class="i"&gt;1&lt;/span&gt;: &lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="i"&gt;1&lt;/span&gt;; &lt;span class="kw"&gt;case&lt;/span&gt; &lt;span class="i"&gt;2&lt;/span&gt;: &lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="i"&gt;1&lt;/span&gt;; &lt;span class="kw"&gt;case&lt;/span&gt; &lt;span class="i"&gt;3&lt;/span&gt;: &lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="i"&gt;2&lt;/span&gt;; ... }&lt;/pre&gt;&lt;/div&gt; &lt;/div&gt;   &lt;p&gt;Obviously this is the wrong approach, but the priority list presented in my original article did not prevent it.  So I&amp;rsquo;ve added the &lt;strong&gt;(case)&lt;/strong&gt; transformation to the very bottom of the list.  &lt;em&gt;This means that using a switch/case or an &amp;lsquo;else if&amp;rsquo; is always the last option to choose.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;Guilherme went on to rightly ignore the switch/case solution to see if he could get a good solution for fib by following the other priorities.  I suggest you read his blog to see how that turned out.  Meanwhile, let&amp;rsquo;s try it here.&lt;/p&gt;  &lt;p&gt;The first test leads us to use the &lt;strong&gt;({}&amp;ndash;&gt;nil)&lt;/strong&gt; and then the &lt;strong&gt;(nil-&gt;constant)&lt;/strong&gt; transformations:&lt;/p&gt;  &lt;div class="CodeRay"&gt; &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Fibonacci&lt;/span&gt; { &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="di"&gt;static&lt;/span&gt; &lt;span class="ty"&gt;int&lt;/span&gt; of(&lt;span class="ty"&gt;int&lt;/span&gt; n) { &lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="i"&gt;0&lt;/span&gt;; } }&lt;/pre&gt;&lt;/div&gt; &lt;/div&gt;   &lt;p&gt;The second test forces an &lt;strong&gt;(unconditional-&gt;if)&lt;/strong&gt; transformation that we can refactor with a &lt;strong&gt;(constant-&gt;scalar)&lt;/strong&gt;.  This coincidentally makes the third test pass which is always nice.&lt;/p&gt;  &lt;div class="CodeRay"&gt; &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="di"&gt;static&lt;/span&gt; &lt;span class="ty"&gt;int&lt;/span&gt; of(&lt;span class="ty"&gt;int&lt;/span&gt; n) { &lt;span class="kw"&gt;if&lt;/span&gt; (n &amp;lt;=&lt;span class="i"&gt;1&lt;/span&gt;) &lt;span class="kw"&gt;return&lt;/span&gt; n; &lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="i"&gt;1&lt;/span&gt;; }&lt;/pre&gt;&lt;/div&gt; &lt;/div&gt;   &lt;p&gt;The fourth tests is tricky.  How can we transform that &amp;lsquo;1&amp;rsquo; into something that maps 1-&gt;1, 2-&gt;1, and 3-&gt;2.   We know that fib(n) = fib(n-1)+fib(n-2) so we could use recursion to solve the problem.  That&amp;rsquo;s the &lt;strong&gt;(statement-&gt;recursion)&lt;/strong&gt; transformation.&lt;/p&gt;  &lt;div class="CodeRay"&gt; &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="di"&gt;static&lt;/span&gt; &lt;span class="ty"&gt;int&lt;/span&gt; of(&lt;span class="ty"&gt;int&lt;/span&gt; n) { &lt;span class="kw"&gt;if&lt;/span&gt; (n &amp;lt;=&lt;span class="i"&gt;1&lt;/span&gt;) &lt;span class="kw"&gt;return&lt;/span&gt; n; &lt;span class="kw"&gt;return&lt;/span&gt; of(n-&lt;span class="i"&gt;1&lt;/span&gt;) + of(n-&lt;span class="i"&gt;2&lt;/span&gt;); }&lt;/pre&gt;&lt;/div&gt; &lt;/div&gt;   &lt;p&gt;This makes all the tests pass.  Hallelujah!  And look how simple that was!  What a pretty sight.&lt;/p&gt;  &lt;p&gt;Unfortunately there are three things wrong with this pretty solution.  First, that algorithm has a horrific runtime complexity of something like O(n&lt;sup&gt;2)&lt;/sup&gt; or worse.  Secondly, the algorithm does not use tail-recursion, and so uses a lot of stack space.  Thirdly, Java is not a great language for recursion anyway since the JVM simply &lt;em&gt;can&amp;rsquo;t&lt;/em&gt; optimize tail recursion (yet).&lt;/p&gt;  &lt;p&gt;It&amp;rsquo;s a great shame that such a simple expression has so many problems!  There are &lt;em&gt;ways&lt;/em&gt; to address that, but they are beyond the scope of this article. For now we&amp;rsquo;ll focus on the three problems mentioned above.&lt;/p&gt;  &lt;p&gt;Let&amp;rsquo;s tackle them one at a time.  Is there a transformation that will at least get us to tail recursion?  Of course there is, but it was missing from my original list.  So I&amp;rsquo;ve modified that list as follows:&lt;/p&gt;  &lt;ul&gt; &lt;li&gt;&lt;strong&gt;({}&amp;ndash;&gt;nil)&lt;/strong&gt; no code at all-&gt;code that employs nil&lt;/li&gt; &lt;li&gt;&lt;strong&gt;(nil-&gt;constant)&lt;/strong&gt;&lt;/li&gt; &lt;li&gt;&lt;strong&gt;(constant-&gt;constant+)&lt;/strong&gt; a simple constant to a more complex constant&lt;/li&gt; &lt;li&gt;&lt;strong&gt;(constant-&gt;scalar)&lt;/strong&gt; replacing a constant with a variable or an argument&lt;/li&gt; &lt;li&gt;&lt;strong&gt;(statement-&gt;statements)&lt;/strong&gt; adding more unconditional statements.&lt;/li&gt; &lt;li&gt;&lt;strong&gt;(unconditional-&gt;if)&lt;/strong&gt; splitting the execution path&lt;/li&gt; &lt;li&gt;&lt;strong&gt;(scalar-&gt;array)&lt;/strong&gt;&lt;/li&gt; &lt;li&gt;&lt;strong&gt;(array-&gt;container)&lt;/strong&gt;&lt;/li&gt; &lt;li&gt;&lt;strong&gt;(statement-&gt;tail-recursion)&lt;/strong&gt;&lt;/li&gt; &lt;li&gt;&lt;strong&gt;(if-&gt;while)&lt;/strong&gt;&lt;/li&gt; &lt;li&gt;&lt;strong&gt;(statement-&gt;recursion)&lt;/strong&gt;&lt;/li&gt; &lt;li&gt;&lt;strong&gt;(expression-&gt;function)&lt;/strong&gt; replacing an expression with a function or algorithm&lt;/li&gt; &lt;li&gt;&lt;strong&gt;(variable-&gt;assignment)&lt;/strong&gt; replacing the value of a variable.&lt;/li&gt; &lt;li&gt;&lt;strong&gt;(case)&lt;/strong&gt; adding a case (or else) to an existing switch or if&lt;/li&gt; &lt;/ul&gt;   &lt;p&gt;So tail recursion is preferred over arbitrary recursion.&lt;/p&gt;  &lt;p&gt;Now, can we use tail recursion to tranform this?&lt;/p&gt;  &lt;div class="CodeRay"&gt; &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="di"&gt;static&lt;/span&gt; &lt;span class="ty"&gt;int&lt;/span&gt; of(&lt;span class="ty"&gt;int&lt;/span&gt; n) { &lt;span class="kw"&gt;if&lt;/span&gt; (n &amp;lt;=&lt;span class="i"&gt;1&lt;/span&gt;) &lt;span class="kw"&gt;return&lt;/span&gt; n; &lt;span class="kw"&gt;return&lt;/span&gt; &lt;span class="i"&gt;1&lt;/span&gt;; }&lt;/pre&gt;&lt;/div&gt; &lt;/div&gt;   &lt;p&gt;Of course we can.  It&amp;rsquo;s not as pretty as the previous solution, but it captures the same semantics. And it&amp;rsquo;s not ugly by any means.&lt;/p&gt;  &lt;div class="CodeRay"&gt; &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Fibonacci&lt;/span&gt; { &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="di"&gt;static&lt;/span&gt; &lt;span class="ty"&gt;int&lt;/span&gt; of(&lt;span class="ty"&gt;int&lt;/span&gt; n) { &lt;span class="kw"&gt;if&lt;/span&gt; (n &amp;lt;=&lt;span class="i"&gt;1&lt;/span&gt;) &lt;span class="kw"&gt;return&lt;/span&gt; n; &lt;span class="kw"&gt;return&lt;/span&gt; of(&lt;span class="i"&gt;0&lt;/span&gt;,&lt;span class="i"&gt;1&lt;/span&gt;,n); }  &lt;span class="di"&gt;private&lt;/span&gt; &lt;span class="di"&gt;static&lt;/span&gt; &lt;span class="ty"&gt;int&lt;/span&gt; of(&lt;span class="ty"&gt;int&lt;/span&gt; a, &lt;span class="ty"&gt;int&lt;/span&gt; b, &lt;span class="ty"&gt;int&lt;/span&gt; n) { &lt;span class="kw"&gt;if&lt;/span&gt; (n == &lt;span class="i"&gt;0&lt;/span&gt;) &lt;span class="kw"&gt;return&lt;/span&gt; a; &lt;span class="kw"&gt;return&lt;/span&gt; of(b, a+b, n-&lt;span class="i"&gt;1&lt;/span&gt;); } }&lt;/pre&gt;&lt;/div&gt; &lt;/div&gt;   &lt;p&gt;Of course we can clean this up by removing the redundant &amp;lsquo;if&amp;rsquo;.&lt;/p&gt;  &lt;div class="CodeRay"&gt; &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Fibonacci&lt;/span&gt; { &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="di"&gt;static&lt;/span&gt; &lt;span class="ty"&gt;int&lt;/span&gt; of(&lt;span class="ty"&gt;int&lt;/span&gt; n) { &lt;span class="kw"&gt;return&lt;/span&gt; of(&lt;span class="i"&gt;0&lt;/span&gt;,&lt;span class="i"&gt;1&lt;/span&gt;,n); }  &lt;span class="di"&gt;private&lt;/span&gt; &lt;span class="di"&gt;static&lt;/span&gt; &lt;span class="ty"&gt;int&lt;/span&gt; of(&lt;span class="ty"&gt;int&lt;/span&gt; a, &lt;span class="ty"&gt;int&lt;/span&gt; b, &lt;span class="ty"&gt;int&lt;/span&gt; n) { &lt;span class="kw"&gt;if&lt;/span&gt; (n == &lt;span class="i"&gt;0&lt;/span&gt;) &lt;span class="kw"&gt;return&lt;/span&gt; a; &lt;span class="kw"&gt;return&lt;/span&gt; of(b, a+b, n-&lt;span class="i"&gt;1&lt;/span&gt;); } }&lt;/pre&gt;&lt;/div&gt; &lt;/div&gt;   &lt;p&gt;But now, how do we deal with the fact that Java doesn&amp;rsquo;t do well with recursion?  If we thought that n would always stay relatively small, we could just ignore it. But let&amp;rsquo;s assume that &amp;lsquo;n&amp;rsquo; will be large; forcing us to unwind the recursion and replace it with iteration.  This requires a &lt;strong&gt;(if-&gt;while)&lt;/strong&gt; and a few &lt;strong&gt;(variable-&gt;assignment)&lt;/strong&gt; transformations.&lt;/p&gt;  &lt;div class="CodeRay"&gt; &lt;div class="code"&gt;&lt;pre&gt;&lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="ty"&gt;class&lt;/span&gt; &lt;span class="cl"&gt;Fibonacci&lt;/span&gt; { &lt;span class="di"&gt;public&lt;/span&gt; &lt;span class="di"&gt;static&lt;/span&gt; &lt;span class="ty"&gt;int&lt;/span&gt; of(&lt;span class="ty"&gt;int&lt;/span&gt; n) { &lt;span class="kw"&gt;return&lt;/span&gt; of(&lt;span class="i"&gt;0&lt;/span&gt;,&lt;span class="i"&gt;1&lt;/span&gt;,n); }  &lt;span class="di"&gt;private&lt;/span&gt; &lt;span class="di"&gt;static&lt;/span&gt; &lt;span class="ty"&gt;int&lt;/span&gt; of(&lt;span class="ty"&gt;int&lt;/span&gt; a, &lt;span class="ty"&gt;int&lt;/span&gt; b, &lt;span class="ty"&gt;int&lt;/span&gt; n) { &lt;span class="kw"&gt;while&lt;/span&gt; (n != &lt;span class="i"&gt;0&lt;/span&gt;) { &lt;span class="ty"&gt;int&lt;/span&gt; s = a+b; a = b; b = s; n--; } &lt;span class="kw"&gt;return&lt;/span&gt; a; } }&lt;/pre&gt;&lt;/div&gt; &lt;/div&gt;   &lt;p&gt;The list of priorities prevents this from being the direct outcome of TDD because it prefers the recursive solution.  So my list of proposed priorities will necessarily create Java programs that are recursive, and therefore less than optimal for the language.&lt;/p&gt;  &lt;p&gt;That makes me think that the priority list is language specific.  In Java, for example, we might move &lt;strong&gt;(if-&gt;while)&lt;/strong&gt; and &lt;strong&gt;(variable-&gt;assignment)&lt;/strong&gt; &lt;em&gt;above&lt;/em&gt; &lt;strong&gt;(statement-&gt;tail-recursion)&lt;/strong&gt; so that iteration is always preferred above recursion, and assignment is preferred above parameter passing.&lt;/p&gt;  &lt;p&gt;This makes sense because Java is not a functional language, and strongly resists a functional style.  So any bias towards functional style will lead to suboptimal implementations.&lt;/p&gt;  &lt;p&gt;If the priority list is language specific, is it also application specific?  Do different problem domains require different priority lists?  I strongly doubt this.  We are working at a level of detail so far below the problem domain that it is hard for me to see how different problems would require different solution styles.&lt;/p&gt;  &lt;p&gt;What about teams?  Will teams tweak the priority list to match their styles?  I hope not; but I have to say that I think this is not improbable.&lt;/p&gt;  &lt;p&gt;I think what this shows us is that the transformations and their priorities are a way to encode a particular programming style.  So long as we have different languages and styles, we&amp;rsquo;ll likely need different transformations and priorities.&lt;/p&gt;  &lt;p&gt;On the other hand, if we compare the Java list with the Clojure list (say), the difference is subtle.  The recursive transformations would move &lt;em&gt;slightly&lt;/em&gt; lower in the list relative to the iterative and assignment transformations.  The effect is, of course, profound, but the difference in the lists is actually relatively small.  All the other transformations seem to hold their positions.&lt;/p&gt;  &lt;p&gt;So the good news is that, although there may be different styles based on language type, the vast majority of the low level coding decisions remain similar irrespective of those styles.&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-8789706689010113680?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/8789706689010113680/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2011/02/fib-t-p-premise.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/8789706689010113680'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/8789706689010113680'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2011/02/fib-t-p-premise.html' title='Fib: The T-P Premise.'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-3463572888767506906</id><published>2011-01-19T11:06:00.001-08:00</published><updated>2011-01-19T11:06:38.187-08:00</updated><title type='text'>Brining Balance to the Force</title><content type='html'>&lt;div class='posterous_autopost'&gt;&lt;p&gt;I read Martin Fowler's &lt;a href="http://martinfowler.com/bliki/CraftmanshipAndTheCrevasse.html"&gt;contribution&lt;/a&gt; to the craftsmanship thread with interest.&amp;nbsp; He spoke of the so-called "crevasse" between developers and customers.&amp;nbsp; He reiterated Dan North's fear that the craftsmanship movement could widen this crevasse.&lt;/p&gt;  &lt;p&gt;We are programmers.&amp;nbsp; We need to talk about programming from time to time. We need time and space to focus on our primary discipline: programming.&amp;nbsp; That discussion, and that focus, is a very positive thing.&amp;nbsp; It means we &lt;em&gt;care&lt;/em&gt; about what we do.&amp;nbsp; But have we gone too far?&amp;nbsp; Are we too technical?&amp;nbsp; Is the Software Craftsmanship movement a movement only about techical practice and details?&amp;nbsp; Have we forgotten the customer?&lt;/p&gt;  &lt;p&gt;&lt;a href="manifesto.softwarecraftsmanship.org"&gt;The Software Craftsmanship Manifesto's&lt;/a&gt; fourth statement: &lt;em&gt;"We value not only customer collaboration but also productive partnerships"&lt;/em&gt; should be enough to quell those fears. Software Craftsmanship is a movement dedicated to &lt;em&gt;partnering&lt;/em&gt; with customers.&amp;nbsp; That means taking on the customer's problems as our own.&amp;nbsp; That means putting ourselves in the position of our customers.&amp;nbsp; Their pain becomes our pain, their problems our problems, their victories, our victories.&amp;nbsp; &lt;em&gt;That's craftsmanship!&lt;/em&gt;&amp;nbsp; That's what we want.&amp;nbsp; We want to be able to do our job with professionalism and skill, and to partner with our customers to achieve the best possible outcomes.&lt;/p&gt;  &lt;p&gt;Software Craftsmanship is &lt;em&gt;not&lt;/em&gt;, as Martin said: "A place where programming can be front and central again."&amp;nbsp; It is not a movement that "underplays the vital role of customer communication".&amp;nbsp; After all, those of us in the Software Craftsmanship movement have not abandoned Agile.&amp;nbsp; We still read the Agile papers.&amp;nbsp; We still follow the Agile threads.&amp;nbsp; We still go to the Agile conferences.&amp;nbsp; We are still part of the Agile community.&amp;nbsp; So we are steeped in "the vial role of customer communication."&amp;nbsp; So much so that we amplified that role to one of &lt;em&gt;partnership&lt;/em&gt;.&amp;nbsp;&lt;/p&gt;  &lt;p&gt;No, the Software Craftmanship movement is not overplaying the technical role; rather it is trying to recapture the &lt;em&gt;balance&lt;/em&gt; that the Agile movement has lost.&amp;nbsp;&lt;/p&gt;  &lt;p&gt;Martin made an amazing point about this in his article.&amp;nbsp; He said that the craftsmanship movement was spawned as a reaction to the rise of non-programming topics within agile.&amp;nbsp; I completely agree.&amp;nbsp; Indeed, I made exactly that point just a week ago while attending an Agile Coach Camp in Norway.&amp;nbsp; I, for one, consider the agile movement to have been inundated by a vocal and enthusiastic cohort of project managers, waving their scrum-master certificates, or their Lean and Kanban books.&amp;nbsp; They have overwhelmed the original movement and changed it into something new.&amp;nbsp;&amp;nbsp; Agile is no longer about a balance between the technical and non-technical parts of development.&amp;nbsp; Rather it has become a discussion almost entirely dedicated to non-technical issues.&amp;nbsp; Agile is no longer about healing the divide, or closing the crevasse.&amp;nbsp; The agile movement now represents &lt;em&gt;one side of the crevasse&lt;/em&gt;.&amp;nbsp;&lt;/p&gt;  &lt;p&gt;The argument has been made that the technical issues are the &lt;em&gt;simple&lt;/em&gt; part.&amp;nbsp; That the real &lt;em&gt;hard&lt;/em&gt; parts of software development are the people issues. So therefore we should focus on the people issues, on the customers and employers, and keep quiet about the technical stuff.&amp;nbsp; If we talk too loudly about the technical stuff, then the customers may feel that we're not paying due attention to them.&lt;/p&gt;  &lt;p&gt;Bollocks!&amp;nbsp; Bollocks I say!&amp;nbsp; Yes, the people part is hard.&amp;nbsp; The people part is complicated.&amp;nbsp; The people part needs lots of work.&amp;nbsp; We should be talking a lot about the people part.&amp;nbsp; But anybody who thinks the technical stuff isn't just as hard, and just as &lt;em&gt;worthy of conversation&lt;/em&gt;, is misguided.&amp;nbsp; We need &lt;em&gt;both&lt;/em&gt;.&amp;nbsp; And we need both sides to listen to each other and to trust each other.&amp;nbsp; We need balance!&lt;em&gt;&amp;nbsp;&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;The imbalance&lt;em&gt; is the crevasse!&lt;/em&gt;&amp;nbsp; One side thinks &lt;em&gt;their&lt;/em&gt; issues are more important that the other's.&amp;nbsp; One side thinks &lt;em&gt;their&lt;/em&gt; issues should dominate.&amp;nbsp; And when the other side tries to talk about their issues, they are told to shush because they might alienate the other side and "widen the crevasse".&amp;nbsp;&lt;/p&gt;  &lt;p&gt;But neither side is more important than the other.&amp;nbsp; Neither side should dominate.&amp;nbsp; Neither side's issues should be toned down.&amp;nbsp; Neither side should be told to shush for fear of what the other side might say.&amp;nbsp; The only way to bring the crevasse together is to realize that both sides need each other, and need each other to be skilled and professional.&amp;nbsp; Each side should be &lt;em&gt;glad&lt;/em&gt; that the other is talking about their own issues.&amp;nbsp; And each side should be willing to listen to the other side's issues. Each side must respect the other side's desire to increase their skill and professionalism.&amp;nbsp; If we do that enough, maybe we'll realize that there's actually only one side.&amp;nbsp;&lt;/p&gt;  &lt;p&gt;So the next time you see some programmers talking about code retreats or koans or katas or TDD or some other deeply techincal topic, &lt;em&gt;congratulate them&lt;/em&gt; for giving due dilligence to their practice.&amp;nbsp; The next time you see an agile coach talking about Kanban, or Lean, or Iteration length, or story points,&lt;em&gt; congratulate them&lt;/em&gt; for their dedication to their discipline.&amp;nbsp; Remember, &lt;em&gt;these are your team-mates&lt;/em&gt;.&amp;nbsp; You want them to be able to play their positions with skill and professionalism.&amp;nbsp; You want them to be good at their jobs.&amp;nbsp; And, if you want them to repect your role,&amp;nbsp; you must first respect theirs.&lt;/p&gt;  &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-3463572888767506906?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/3463572888767506906/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2011/01/brining-balance-to-force.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/3463572888767506906'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/3463572888767506906'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2011/01/brining-balance-to-force.html' title='Brining Balance to the Force'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-4657682889870683464</id><published>2011-01-17T13:59:00.001-08:00</published><updated>2011-01-17T13:59:55.230-08:00</updated><title type='text'>Software Craftsmanship: What it's all about.</title><content type='html'>&lt;div class='posterous_autopost'&gt;&lt;p&gt;TL;DR&lt;a href='http://posterous.com/getfile/files.posterous.com/temp-2011-01-17/uEzpJoJJmtGBxuCuaiHFEtogGhHAofIHgiBffABEdxvffGCIsmHnEczihEvx/DSC04794.JPG.scaled1000.jpg'&gt;&lt;img src="http://posterous.com/getfile/files.posterous.com/temp-2011-01-17/uEzpJoJJmtGBxuCuaiHFEtogGhHAofIHgiBffABEdxvffGCIsmHnEczihEvx/DSC04794.JPG.scaled500.jpg" width="500" height="527"/&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;I've gone from &lt;a href="http://dannorth.net/2011/01/11/programming-is-not-a-craft/"&gt;Dan North's post&lt;/a&gt;, to &lt;a href="http://www.gilzilberfeld.com/2011/01/path-already-taken.html?utm_source=twitterfeed&amp;amp;utm_medium=twitter&amp;amp;utm_campaign=Feed%3A+gilzilberfeld+%28Geek+out+of+water%29"&gt;Gil Zilberfeld's&lt;/a&gt; to &lt;a href="http://michaelfeathers.typepad.com/michael_feathers_blog/2011/01/the-thing-of-software-development.html"&gt;Michael Feather's&lt;/a&gt; to &lt;a href="http://parlezuml.com/blog/?postid=992"&gt;Jason Gorman's&lt;/a&gt; and back. And I'm at a loss.&lt;/p&gt;  &lt;p&gt;Why is there a software craftsmanship movement?&amp;nbsp; What motivated it?&amp;nbsp; What drives it now?&amp;nbsp; &lt;em&gt;One&lt;/em&gt; thing; and &lt;em&gt;one thing only.&lt;/em&gt;&amp;nbsp;&lt;/p&gt;  &lt;p style="text-align: center;"&gt;&lt;em&gt;We are tired of writing crap.&lt;/em&gt;&lt;/p&gt;  &lt;p&gt;That's it.&amp;nbsp; The fat lady sang.&amp;nbsp; Good nite Gracy. Over and out.&amp;nbsp;&lt;/p&gt;  &lt;p&gt;We're tired of writing crap. We are tired of embarrassing ourselves and our employers by delivering lousy software.&amp;nbsp; We have had enough of telling our customers to reboot at midnight.&amp;nbsp; We don't want bug lists that are a thousand pages long.&amp;nbsp; We don't want code that grows more tangled and corrupt with every passing day.&amp;nbsp; We're tired of doing a bad job.&amp;nbsp; We want to start doing a good job.&amp;nbsp;&lt;/p&gt;  &lt;p&gt;That's ... what ... this ... is ... about.&amp;nbsp; Nothing else.&lt;/p&gt;  &lt;p&gt;What we are &lt;em&gt;not&lt;/em&gt; doing:&lt;/p&gt;  &lt;ul&gt;  &lt;li&gt;We are &lt;em&gt;not&lt;/em&gt; putting code at the center of everything.&lt;/li&gt;  &lt;li&gt;We are &lt;em&gt;not&lt;/em&gt; turning inward and ignoring the business and the customer.&lt;/li&gt;  &lt;li&gt;We are &lt;em&gt;not&lt;/em&gt; inspecting our navels.&lt;/li&gt;  &lt;li&gt;We are &lt;em&gt;not&lt;/em&gt; offering cheap certifications.&amp;nbsp;&lt;/li&gt;  &lt;li&gt;We are &lt;em&gt;not&lt;/em&gt; forgetting that our job is to delight our customers.&amp;nbsp;&lt;/li&gt;  &lt;/ul&gt;  &lt;p&gt;What we will &lt;em&gt;not do anymore&lt;/em&gt;:&lt;/p&gt;  &lt;ul&gt;  &lt;li&gt;We will &lt;em&gt;not&lt;/em&gt; make messes in order to meet a schedule.&lt;/li&gt;  &lt;li&gt;We will &lt;em&gt;not&lt;/em&gt; accept the stupid old lie about cleaning things up later.&amp;nbsp;&amp;nbsp;&lt;/li&gt;  &lt;li&gt;We will &lt;em&gt;not&lt;/em&gt; believe the claim that quick means dirty.&lt;/li&gt;  &lt;li&gt;We will &lt;em&gt;not&lt;/em&gt; accept the option to do it wrong.&lt;/li&gt;  &lt;li&gt;We will &lt;em&gt;not&lt;/em&gt; allow &lt;em&gt;anyone&lt;/em&gt; to force us to behave unprofessionally.&amp;nbsp; &lt;/li&gt;  &lt;/ul&gt;  &lt;p&gt;What we &lt;em&gt;will&lt;/em&gt; do from now on:&lt;/p&gt;  &lt;ul&gt;  &lt;li&gt;We &lt;em&gt;will&lt;/em&gt; meet our schedules by knowing that the only way to go fast is to go well. &lt;/li&gt;  &lt;li&gt;We &lt;em&gt;will&lt;/em&gt; delight our customers by writing the best code we can.&lt;/li&gt;  &lt;li&gt;We &lt;em&gt;will&lt;/em&gt; honor our employers by creating the best designs we can.&lt;/li&gt;  &lt;li&gt;We &lt;em&gt;will&lt;/em&gt; honor our team by testing everything that can be tested.&lt;/li&gt;  &lt;li&gt;We &lt;em&gt;will&lt;/em&gt; be humble enough to write those tests first.&lt;/li&gt;  &lt;li&gt;We &lt;em&gt;will&lt;/em&gt; practice so that we become better at our &lt;em&gt;craft&lt;/em&gt;.&amp;nbsp;&amp;nbsp;&lt;/li&gt;  &lt;/ul&gt;  &lt;p&gt;We will remember what our grandmothers and grandfathers told us:&lt;/p&gt;  &lt;ul&gt;  &lt;li&gt;Anything worth doing is worth doing well.&lt;/li&gt;  &lt;li&gt;Slow and steady wins the race.&lt;/li&gt;  &lt;li&gt;Measure twice cut once.&lt;/li&gt;  &lt;li&gt;Practice, Practice, Practice.&lt;/li&gt;  &lt;/ul&gt;  &lt;p&gt;I suppose that some people might look askance at our code katas and our code retreats, and our practice sessions.&amp;nbsp; They might think that we're turning inwards and abandoning our customers.&amp;nbsp; They might think that we've given up on the real world and have yielded to the temptation to entertain ourselves.&amp;nbsp; I can see how someone might come to that conclusion.&lt;/p&gt;  &lt;p&gt;But they are as wrong as the day is long.&amp;nbsp; We are doing this &lt;em&gt;because&lt;/em&gt; we care about the customer.&amp;nbsp; We are dedicating time and effort to being the &lt;em&gt;best that we can be&lt;/em&gt; so that our employers will get the best possible value out of us.&amp;nbsp;&lt;/p&gt;  &lt;p&gt;Do you think the only time musicians play their instruments is when they are on stage?&amp;nbsp; Do you think the only time that batters hit balls is during games?&amp;nbsp; Do you think the only time lawyers give a closing is at trial?&amp;nbsp; Of course not.&amp;nbsp; These people are professionals; &lt;em&gt;and professionals practice&lt;/em&gt;!&amp;nbsp; Professionals study the minutia of their disciplines.&amp;nbsp; Professionals know all the little tricks and quirks.&amp;nbsp; They know the history, the theories, the anecdotes.&amp;nbsp; They know techniques and methods.&amp;nbsp; They know good options and bad options and how to tell them apart.&amp;nbsp; And they know all this stuff because they &lt;em&gt;practice, practice practice&lt;/em&gt;.&lt;/p&gt;  &lt;p&gt;So when you see someone wearing a green wrist-band that says "Clean Code" or "Test First" or "Test Obsessed", it's not because they've joined a movement, or signed a manifesto, or that they somehow feel superior to everyone else.&amp;nbsp; They aren't participants in a holy war.&amp;nbsp; They aren't trying to join a tribe and huddle around a campfire.&amp;nbsp; The green band is a &lt;em&gt;personal&lt;/em&gt; thing.&amp;nbsp; It's a promise made to one's self:&amp;nbsp; "I will do a good job.&amp;nbsp; I will not rush.&amp;nbsp; I will write tests.&amp;nbsp; I will go fast by going well.&amp;nbsp; &lt;em&gt;I will not write crap&lt;/em&gt;. And I will &lt;em&gt;practice, practice practice&lt;/em&gt; so that I can be a professional."&lt;/p&gt;  &lt;p&gt;&amp;nbsp;&lt;/p&gt;  &lt;p&gt;&amp;nbsp;&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-4657682889870683464?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/4657682889870683464/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2011/01/software-craftsmanship-what-it-all.html#comment-form' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/4657682889870683464'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/4657682889870683464'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2011/01/software-craftsmanship-what-it-all.html' title='Software Craftsmanship: What it&amp;#39;s all about.'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-3804782479376936786</id><published>2011-01-17T12:34:00.001-08:00</published><updated>2011-01-17T12:34:19.003-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Midje'/><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='STUB'/><category scheme='http://www.blogger.com/atom/ns#' term='Clojure'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>STUB5: Prolog, Midje, and Test Specifications.</title><content type='html'>&lt;div class='posterous_autopost'&gt;&lt;p&gt;       &lt;div style='padding: 5px 5px 10px 5px; margin-top: 5px; border: 1px solid #ddd; background-color: #fff;line-height: 16px;'&gt;       &lt;div style="float: left; margin-right: 5px; overflow: visible;"&gt;&lt;a href='http://posterous.com/getfile/files.posterous.com/cleancoder/odkwsxJetdjwhGwnrrwIrGmrtxBlrcBAoiChBywanuBsbuuCltHypsDqGIHm/p93.mov' style='color: #bc7134;'&gt;&lt;img src='http://posterous.com/images/filetypes/mov.png' style='border: none;'/&gt;&lt;/a&gt;&lt;/div&gt;       &lt;div style="font-size: 10px; color: #424037;line-height: 16px;"&gt;Download now or &lt;a href="http://cleancoder.posterous.com/stub5-prolog-midje-and-test-specifications" style="color: #bc7134"&gt;watch on posterous&lt;/a&gt;&lt;/div&gt;       &lt;b&gt;&lt;a href='http://posterous.com/getfile/files.posterous.com/cleancoder/odkwsxJetdjwhGwnrrwIrGmrtxBlrcBAoiChBywanuBsbuuCltHypsDqGIHm/p93.mov' style='color: #bc7134;'&gt;p93.mov&lt;/a&gt;&lt;/b&gt; &lt;span style="font-size: 10px; color: #424037;"&gt;(85043 KB)&lt;/span&gt;       &lt;br style="clear: both;"/&gt;&lt;/div&gt;      &lt;/p&gt;Fascinating equivalence of Midje and Prolog.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-3804782479376936786?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/3804782479376936786/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2011/01/stub5-prolog-midje-and-test.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/3804782479376936786'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/3804782479376936786'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2011/01/stub5-prolog-midje-and-test.html' title='STUB5: Prolog, Midje, and Test Specifications.'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-8727879524192990700</id><published>2011-01-05T13:08:00.001-08:00</published><updated>2011-01-05T13:08:48.189-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MDA'/><category scheme='http://www.blogger.com/atom/ns#' term='STUB'/><title type='text'>STUB4: MDA: A forlorn hope.</title><content type='html'>&lt;div class='posterous_autopost'&gt;&lt;p&gt;       &lt;div style='padding: 5px 5px 10px 5px; margin-top: 5px; border: 1px solid #ddd; background-color: #fff;line-height: 16px;'&gt;       &lt;div style="float: left; margin-right: 5px; overflow: visible;"&gt;&lt;a href='http://posterous.com/getfile/files.posterous.com/cleancoder/jbpivtxemjuAAxqyEIGevCAusBnjgAzihmqGCcnumpmyfsdhewoBHFjuCfaC/p80.mov' style='color: #bc7134;'&gt;&lt;img src='http://posterous.com/images/filetypes/mov.png' style='border: none;'/&gt;&lt;/a&gt;&lt;/div&gt;       &lt;div style="font-size: 10px; color: #424037;line-height: 16px;"&gt;Download now or &lt;a href="http://cleancoder.posterous.com/stub4-mda-a-forlorn-hope" style="color: #bc7134"&gt;watch on posterous&lt;/a&gt;&lt;/div&gt;       &lt;b&gt;&lt;a href='http://posterous.com/getfile/files.posterous.com/cleancoder/jbpivtxemjuAAxqyEIGevCAusBnjgAzihmqGCcnumpmyfsdhewoBHFjuCfaC/p80.mov' style='color: #bc7134;'&gt;p80.mov&lt;/a&gt;&lt;/b&gt; &lt;span style="font-size: 10px; color: #424037;"&gt;(60319 KB)&lt;/span&gt;       &lt;br style="clear: both;"/&gt;&lt;/div&gt;      &lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-8727879524192990700?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/8727879524192990700/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2011/01/stub4-mda-forlorn-hope.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/8727879524192990700'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/8727879524192990700'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2011/01/stub4-mda-forlorn-hope.html' title='STUB4: MDA: A forlorn hope.'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-7405324644898883845</id><published>2011-01-01T12:25:00.001-08:00</published><updated>2011-01-01T12:25:09.552-08:00</updated><title type='text'>Transformation Priority and Sorting</title><content type='html'>&lt;div class='posterous_autopost'&gt;&lt;div&gt;  &lt;div style="margin: 0px;"&gt;&lt;span style="font-family: Helvetica; font-size: small;"&gt;Comic created with Comic Life from plasq - &lt;a href="http://plasq.com"&gt;http://plasq.com&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;  &lt;/div&gt;  &lt;p&gt;&lt;a href='http://posterous.com/getfile/files.posterous.com/cleancoder/jPotr6Yd92j7O4SkEJcll5TpBMkNlrz7GPk2z4AS7zmSZ5Gb3C0TX7Y1ae1T/Page_1.jpg'&gt;&lt;img src="http://posterous.com/getfile/files.posterous.com/cleancoder/TxB6hfoSKIkP9d6HuIkY1SYbXrGndkQM8djGzOsA33PhEMV0Xvbz06uNz1pA/Page_1.jpg.scaled.500.jpg" width="500" height="647"/&gt;&lt;/a&gt; &lt;a href='http://posterous.com/getfile/files.posterous.com/cleancoder/7Mugz99HfA4yQS6ZGncG7Ek6KEga58FbVUPexXEG8goN0Q6aoSPrsfJFVLAd/Page_2.jpg'&gt;&lt;img src="http://posterous.com/getfile/files.posterous.com/cleancoder/bJwywnUP9th9FtB9yliDxQrvtxVeZzZ1m7dj2szSlYiFaoBdlpNNwcqXyZRK/Page_2.jpg.scaled.500.jpg" width="500" height="647"/&gt;&lt;/a&gt; &lt;a href='http://posterous.com/getfile/files.posterous.com/cleancoder/IykNJX6EepLgDEqoxebcB2neuYC40KLJ2SjC6Jc6UDHHILQq8CCQ5iBOM7R2/Page_3.jpg'&gt;&lt;img src="http://posterous.com/getfile/files.posterous.com/cleancoder/LBOWwS2T2tSnKhhHm0noq8EkZbhHhUqxtMnFnnrVlanW8qqoQZuDKoH1cqZZ/Page_3.jpg.scaled.500.jpg" width="500" height="647"/&gt;&lt;/a&gt; &lt;a href='http://posterous.com/getfile/files.posterous.com/cleancoder/RGXCMYn8meNaGUbWedBoAEI7uHG1QZv7JYxCZ7cWKUSObNRRUEAHzgV5BwZT/Page_4.jpg'&gt;&lt;img src="http://posterous.com/getfile/files.posterous.com/cleancoder/edsJZpu2HjOAkIoMxiwmykDbsGrnTYSz0EiuGcRWpoNf4DdgtXJg8fsgfv8c/Page_4.jpg.scaled.500.jpg" width="500" height="647"/&gt;&lt;/a&gt; &lt;a href='http://posterous.com/getfile/files.posterous.com/cleancoder/ZQNGN2NyjWabUUOwrQ6nzLWpMhlxahiIlAchK5OJBMxSfwuswGnU3Mt4last/Page_5.jpg'&gt;&lt;img src="http://posterous.com/getfile/files.posterous.com/cleancoder/g1859NxzQmL7T0NyL2NHdP2XWZhFCUCYab8XoaZi1um1yaP9RncBJxwm9oEJ/Page_5.jpg.scaled.500.jpg" width="500" height="647"/&gt;&lt;/a&gt; &lt;a href='http://posterous.com/getfile/files.posterous.com/cleancoder/7zBNs7VxRcZPxflkMHXwuZzP4ff1UcxDF8I2wxlgdFTOo6FULOc4M9K0OCpE/Page_6.jpg'&gt;&lt;img src="http://posterous.com/getfile/files.posterous.com/cleancoder/7ChJZky7iXWDI64Fwc6jq2ZZ7NvHS1xnPoF4IaUOxoTpw2GyxwGyZ8GfNb2R/Page_6.jpg.scaled.500.jpg" width="500" height="647"/&gt;&lt;/a&gt; &lt;a href='http://posterous.com/getfile/files.posterous.com/cleancoder/VEmOeFln9QdSsaikkO4cmPFlUCZ4jarUjpY7PLwzDxADSofnSUdbTMgtqr1T/Page_7.jpg'&gt;&lt;img src="http://posterous.com/getfile/files.posterous.com/cleancoder/l2ayJZ1FzJypzYoP7agBCbqm5wLVQpX1NHa70tU0xR10a94uafj4lDvNAxM3/Page_7.jpg.scaled.500.jpg" width="500" height="647"/&gt;&lt;/a&gt; &lt;div&gt;&lt;a href='http://cleancoder.posterous.com/transformation-priority-and-sorting'&gt;See and download the full gallery on posterous&lt;/a&gt;&lt;/div&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-7405324644898883845?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/7405324644898883845/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2011/01/transformation-priority-and-sorting.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/7405324644898883845'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/7405324644898883845'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2011/01/transformation-priority-and-sorting.html' title='Transformation Priority and Sorting'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-9186205715079023496</id><published>2010-12-29T14:32:00.001-08:00</published><updated>2010-12-29T14:32:13.482-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Design Patterns'/><category scheme='http://www.blogger.com/atom/ns#' term='STUB'/><category scheme='http://www.blogger.com/atom/ns#' term='visitor'/><title type='text'>STUB3: Validating the Visitor</title><content type='html'>&lt;div class='posterous_autopost'&gt;&lt;p&gt;       &lt;div style='padding: 5px 5px 10px 5px; margin-top: 5px; border: 1px solid #ddd; background-color: #fff;line-height: 16px;'&gt;       &lt;div style="float: left; margin-right: 5px; overflow: visible;"&gt;&lt;a href='http://posterous.com/getfile/files.posterous.com/cleancoder/hxChGepoCwnazblrDGJychrbpCjIrjfwxFojwumkhrAnDcoIyjfjysHCssbn/p68.mov' style='color: #bc7134;'&gt;&lt;img src='http://posterous.com/images/filetypes/mov.png' style='border: none;'/&gt;&lt;/a&gt;&lt;/div&gt;       &lt;div style="font-size: 10px; color: #424037;line-height: 16px;"&gt;Download now or &lt;a href="http://cleancoder.posterous.com/validating-the-visitor" style="color: #bc7134"&gt;watch on posterous&lt;/a&gt;&lt;/div&gt;       &lt;b&gt;&lt;a href='http://posterous.com/getfile/files.posterous.com/cleancoder/hxChGepoCwnazblrDGJychrbpCjIrjfwxFojwumkhrAnDcoIyjfjysHCssbn/p68.mov' style='color: #bc7134;'&gt;p68.mov&lt;/a&gt;&lt;/b&gt; &lt;span style="font-size: 10px; color: #424037;"&gt;(36856 KB)&lt;/span&gt;       &lt;br style="clear: both;"/&gt;&lt;/div&gt;      &lt;/p&gt;  &lt;p&gt;Why I like the much maligned visitor pattern.&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-9186205715079023496?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/9186205715079023496/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2010/12/stub3-validating-visitor.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/9186205715079023496'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/9186205715079023496'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2010/12/stub3-validating-visitor.html' title='STUB3: Validating the Visitor'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-7258838747974567643</id><published>2010-12-27T06:35:00.001-08:00</published><updated>2010-12-27T06:35:30.234-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C'/><category scheme='http://www.blogger.com/atom/ns#' term='Marshmallow'/><category scheme='http://www.blogger.com/atom/ns#' term='KandR'/><category scheme='http://www.blogger.com/atom/ns#' term='STUB'/><title type='text'>STUB2: K&amp;R around the Campfire</title><content type='html'>&lt;div class='posterous_autopost'&gt;&lt;p&gt;       &lt;div style='padding: 5px 5px 10px 5px; margin-top: 5px; border: 1px solid #ddd; background-color: #fff;line-height: 16px;'&gt;       &lt;div style="float: left; margin-right: 5px; overflow: visible;"&gt;&lt;a href='http://posterous.com/getfile/files.posterous.com/cleancoder/xCGJjrwdirzoEpgfuGulitgHfhpvaFosmchEjrwrFCxgBjAkHptxJkkAwjkv/p56.mov' style='color: #bc7134;'&gt;&lt;img src='http://posterous.com/images/filetypes/mov.png' style='border: none;'/&gt;&lt;/a&gt;&lt;/div&gt;       &lt;div style="font-size: 10px; color: #424037;line-height: 16px;"&gt;Download now or &lt;a href="http://cleancoder.posterous.com/stub2-kr-around-the-campfire" style="color: #bc7134"&gt;watch on posterous&lt;/a&gt;&lt;/div&gt;       &lt;b&gt;&lt;a href='http://posterous.com/getfile/files.posterous.com/cleancoder/xCGJjrwdirzoEpgfuGulitgHfhpvaFosmchEjrwrFCxgBjAkHptxJkkAwjkv/p56.mov' style='color: #bc7134;'&gt;p56.mov&lt;/a&gt;&lt;/b&gt; &lt;span style="font-size: 10px; color: #424037;"&gt;(40711 KB)&lt;/span&gt;       &lt;br style="clear: both;"/&gt;&lt;/div&gt;      &lt;/p&gt;Fond memories of learning C.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-7258838747974567643?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/7258838747974567643/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2010/12/stub2-k-around-campfire.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/7258838747974567643'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/7258838747974567643'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2010/12/stub2-k-around-campfire.html' title='STUB2: K&amp;amp;R around the Campfire'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-7825923292690634140</id><published>2010-12-24T04:53:00.001-08:00</published><updated>2010-12-24T04:53:14.252-08:00</updated><title type='text'>Clean Code mug and luggage tag</title><content type='html'>&lt;div class='posterous_autopost'&gt;&lt;p&gt;&lt;a href='http://posterous.com/getfile/files.posterous.com/cleancoder/lEkpeBECdfGBdudoiCwiucnEIrDjwhttAcgHuzujlsJwJyzxAxrIeikayHks/p50.jpg.scaled1000.jpg'&gt;&lt;img src="http://posterous.com/getfile/files.posterous.com/cleancoder/lEkpeBECdfGBdudoiCwiucnEIrDjwhttAcgHuzujlsJwJyzxAxrIeikayHks/p50.jpg.scaled500.jpg" width="500" height="373"/&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Watch for them on cleancodeproject.com&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-7825923292690634140?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/7825923292690634140/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2010/12/clean-code-mug-and-luggage-tag.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/7825923292690634140'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/7825923292690634140'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2010/12/clean-code-mug-and-luggage-tag.html' title='Clean Code mug and luggage tag'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-8598624265184855895</id><published>2010-12-23T07:05:00.001-08:00</published><updated>2010-12-23T07:05:58.673-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='SICP'/><category scheme='http://www.blogger.com/atom/ns#' term='STUB'/><title type='text'>STUB 1: SICP &amp; Assignment</title><content type='html'>&lt;div class='posterous_autopost'&gt;&lt;p&gt;&lt;a href='http://posterous.com/getfile/files.posterous.com/cleancoder/lgyIvmdhrgplCbHIcatyEyrpfHflIdfcrozhDmFGhqbocpyHzsigaGdumFdf/p36.jpg.scaled1000.jpg'&gt;&lt;img src="http://posterous.com/getfile/files.posterous.com/cleancoder/lgyIvmdhrgplCbHIcatyEyrpfHflIdfcrozhDmFGhqbocpyHzsigaGdumFdf/p36.jpg.scaled500.jpg" width="500" height="669"/&gt;&lt;/a&gt; &lt;/p&gt;&lt;p&gt;       &lt;div style='padding: 5px 5px 10px 5px; margin-top: 5px; border: 1px solid #ddd; background-color: #fff;line-height: 16px;'&gt;       &lt;div style="float: left; margin-right: 5px; overflow: visible;"&gt;&lt;a href='http://posterous.com/getfile/files.posterous.com/cleancoder/ukFIDtwvljJxvlGnuIbqoJspaxCxqlnafbJjBDlEdGbsjvtzlovcnzEFBpDo/p39.mov' style='color: #bc7134;'&gt;&lt;img src='http://posterous.com/images/filetypes/mov.png' style='border: none;'/&gt;&lt;/a&gt;&lt;/div&gt;       &lt;div style="font-size: 10px; color: #424037;line-height: 16px;"&gt;Download now or &lt;a href="http://cleancoder.posterous.com/stub-1-sicp-assignment" style="color: #bc7134"&gt;watch on posterous&lt;/a&gt;&lt;/div&gt;       &lt;b&gt;&lt;a href='http://posterous.com/getfile/files.posterous.com/cleancoder/ukFIDtwvljJxvlGnuIbqoJspaxCxqlnafbJjBDlEdGbsjvtzlovcnzEFBpDo/p39.mov' style='color: #bc7134;'&gt;p39.mov&lt;/a&gt;&lt;/b&gt; &lt;span style="font-size: 10px; color: #424037;"&gt;(64778 KB)&lt;/span&gt;       &lt;br style="clear: both;"/&gt;&lt;/div&gt;      &lt;/p&gt;A very brief sojourn through Abelson's and Sussman's landmark book: "Structure and Interpetation of Computer Programs".&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-8598624265184855895?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/8598624265184855895/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2010/12/stub-1-sicp-assignment.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/8598624265184855895'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/8598624265184855895'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2010/12/stub-1-sicp-assignment.html' title='STUB 1: SICP &amp;amp; Assignment'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-8577281389078485614</id><published>2010-12-20T04:28:00.001-08:00</published><updated>2010-12-20T04:28:05.098-08:00</updated><title type='text'>Snow and Pandemonium</title><content type='html'>&lt;div class='posterous_autopost'&gt;These pictures are from Heathrow on Monday morning, 20 December after a light dusting of snow paralyzed flights on Friday night and Saturday morning. Though most people were cheerful in a "what can you do about it" way; there was also anger, frustration, and tears of desperation as people struggled to gain some modicum of control over their fate. &lt;p /&gt; I understand that there are times when events are beyond reasonable control. But this was just a little snow. I can even understand that Heathrow and the airlines had not planned properly for unexpected cold weather. What I can not understand is the breathtaking incompetence that has left thousands upon thousands of travelers without any kind of information. &lt;p /&gt; The British Air website was inaccessible until earlier today. The phone lines were so jammed that when she got through on her 41st call, my daughter was actually told by an automated attendant that the hold time would be 594 minutes. (That's 10 hours). How has this once great airline fallen so far that they are reduced to having mumbling women, with bull-horns that don't work, walk through a crowd of people telling them that their best option is to somehow get to customer service desk (an obviously hopeless task). I think it may be time to consider reducing Heathrow and British-air to third-world status. I would expect this kind of treatment in Central America.&lt;p&gt;&lt;img src="http://posterous.com/getfile/files.posterous.com/cleancoder/ocOvokLTxiYjVvziaEdleMO4BzmrkOOmM2lgFEHj01eQJSYgEykQVnqyWDxg/IMG_0311.jpeg" width="320" height="240"/&gt; &lt;img src="http://posterous.com/getfile/files.posterous.com/cleancoder/NOVdwWXrJqIZScAEgiKAgmB4M2G0EzzaQslzlgDGDpOwyoCr89DCHplQwcAE/IMG_0314.jpeg" width="320" height="240"/&gt; &lt;img src="http://posterous.com/getfile/files.posterous.com/cleancoder/LzSojkLIEmbVJRXrefmtuMIG0BPe7q7s2yD9f67vUo43SpTAQN7XbZToPCnT/IMG_0317.jpeg" width="320" height="240"/&gt; &lt;img src="http://posterous.com/getfile/files.posterous.com/cleancoder/8fQPwaqe3fYkIkuADoBFCTKFyMfbDrKmLRMrozRsZXscnBGBewBRxzCxHGbI/IMG_0312.jpeg" width="320" height="240"/&gt; &lt;div&gt;&lt;a href='http://cleancoder.posterous.com/snow-and-pandemonium'&gt;See and download the full gallery on posterous&lt;/a&gt;&lt;/div&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-8577281389078485614?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/8577281389078485614/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2010/12/snow-and-pandemonium.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/8577281389078485614'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/8577281389078485614'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2010/12/snow-and-pandemonium.html' title='Snow and Pandemonium'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-7044088052436137153</id><published>2010-12-19T07:17:00.001-08:00</published><updated>2010-12-30T10:03:36.612-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>The Transformation Priority Premise</title><content type='html'>&lt;a href="http://cleancoder.posterous.com/the-transformation-priority-premise"&gt;See this blog on Posterous, it doesn't render well here.&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-7044088052436137153?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/7044088052436137153/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2010/12/transformation-priority-premise.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/7044088052436137153'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/7044088052436137153'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2010/12/transformation-priority-premise.html' title='The Transformation Priority Premise'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-6891890564367316544</id><published>2010-12-17T12:24:00.001-08:00</published><updated>2010-12-17T12:24:39.087-08:00</updated><title type='text'>Clean Code Course in Dallas.</title><content type='html'>&lt;div class='posterous_autopost'&gt;I'll be teaching a three-day Clean Code course in Dallas on the 15th-17th of February. Come one, come all! &lt;br /&gt;You can sigh up here: &lt;a href="http://www.eventbrite.com/event/1019973769"&gt;http://www.eventbrite.com/event/1019973769&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-6891890564367316544?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/6891890564367316544/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2010/12/clean-code-course-in-dallas.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/6891890564367316544'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/6891890564367316544'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2010/12/clean-code-course-in-dallas.html' title='Clean Code Course in Dallas.'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-1507940806032707279</id><published>2010-12-16T03:30:00.001-08:00</published><updated>2010-12-16T03:30:28.253-08:00</updated><title type='text'>test</title><content type='html'>&lt;div class='posterous_autopost'&gt;&lt;i&gt;&lt;span style="font-size: 14px;"&gt;italic&lt;/span&gt;&lt;/i&gt;&lt;span style="font-size: 14px;"&gt; &lt;/span&gt;&lt;b&gt;&lt;span style="font-size: 14px;"&gt;bold&lt;/span&gt;&lt;/b&gt;&lt;span style="font-size: 14px;"&gt; &lt;/span&gt;&lt;span style="font-size: 14px;"&gt;monospaced&lt;/span&gt;&lt;span style="font-size: 14px;"&gt;.&lt;/span&gt;&lt;p /&gt;&lt;div&gt;This is two. &amp;nbsp;&lt;br /&gt;&lt;div&gt; &lt;span style=""&gt;----&lt;br /&gt;Robert C. Martin (Uncle Bob) | &lt;a href="mailto:unclebob@cleancoder.com"&gt;unclebob@cleancoder.com&lt;/a&gt;&lt;br /&gt;Uncle Bob Consulting LLC. &amp;nbsp; &amp;nbsp;| @unclebobmartin&lt;br /&gt;847.922.0563 &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; | web: &lt;a href="http://objectmentor.com"&gt;objectmentor.com&lt;/a&gt;&lt;p /&gt;&lt;p /&gt;&lt;/span&gt; &lt;/div&gt; &lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-1507940806032707279?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/1507940806032707279/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2010/12/test.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/1507940806032707279'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/1507940806032707279'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2010/12/test.html' title='test'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-1583482136925969319</id><published>2010-12-14T01:50:00.001-08:00</published><updated>2010-12-14T01:50:17.371-08:00</updated><title type='text'>Too Lazy to "Type".</title><content type='html'>&lt;div class='posterous_autopost'&gt;Loren Segal (@Islegal) in his blog (&lt;a href="http://gnuu.org/2010/12/13/too-lazy-to-type/)"&gt;http://gnuu.org/2010/12/13/too-lazy-to-type/)&lt;/a&gt; makes the interesting point that most dynamic programs are, in fact, not particularly dynamic. Even duck-typed ruby programs would require very little change to make them static. He includes a Rack example showing this transformation. &lt;p /&gt; class MyMiddleware &lt;br /&gt; def call(app) ... end &lt;br /&gt;end &lt;p /&gt; To: &lt;p /&gt; class MyMiddleware &lt;br /&gt; include Callable &lt;br /&gt; def call(app) ... end &lt;br /&gt;end &lt;p /&gt; He asks, in the end: "how often do you write Ruby code that can really not have some kind of class based inheritance type system? For me, I can’t think of many cases. How often do you pass arbitrary types to methods without at least having a well-defined set of types that can be accepted by the method?" &lt;p /&gt; He's quite correct that many (if not most) programs written in dynamic languages do not need to be dynamic. That with a very few simple changes we could add the hints that would make them static. And this would allow the compilers to optimize the programs in ways that are impossible for dynamic programs. However, there is a cost -- and the cost is not simply typing (and by that I mean keystrokes or LoC). &lt;p /&gt; The cost is _dependencies_. The simple "include" in Segal's example above is a _coupling_. That coupling adds complexity to the design of the application. It might not seem that such a simple statement would be very confounding, but the problem is not one simple statement. The problem is that nearly all our classes would suddenly require instrumentation with appropriate includes or extends statements. &lt;br /&gt;Even that might not seem all that bad, but the problem is that the requirements for interfaces change. We often want to add new methods to existing interfaces. When we do, we must add those methods to all classes that implement those interfaces, whether they need it or not. If some of our derivatives don't need those methods we might be tempted to split the interface into one that has the new methods, and one that does not; but that forces us to find all the classes that implement that interface and decide, in each case, which interface it should now derive from. &lt;p /&gt; And of course interfaces depend on other interfaces which depend on other interfaces. And so the tangle grows. If you haven't been programming in a static language for awhile, it is easy to forget the complexities that these couplings lead to. But in the end, we like dynamic language not because we are too lazy to "Type". We like dynamic languages because we are tired of untangling couplings. &lt;p /&gt; ---- &lt;br /&gt;Robert C. Martin (Uncle Bob) | &lt;a href="mailto:unclebob@cleancoder.com"&gt;unclebob@cleancoder.com&lt;/a&gt; &lt;br /&gt;Uncle Bob Consulting LLC. | @unclebobmartin &lt;br /&gt;847.922.0563 | web: objectmentor.com&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-1583482136925969319?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/1583482136925969319/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2010/12/too-lazy-to.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/1583482136925969319'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/1583482136925969319'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2010/12/too-lazy-to.html' title='Too Lazy to &amp;quot;Type&amp;quot;.'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-462008774780496094</id><published>2010-11-28T16:14:00.001-08:00</published><updated>2010-11-28T16:14:46.718-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='podcasts'/><title type='text'>Mentoring &amp; Apprenticeship (A reading from: "The Clean Coder")</title><content type='html'>&lt;div class='posterous_autopost'&gt;       &lt;div style='padding: 5px 5px 10px 5px; margin-top: 5px; border: 1px solid #ddd; background-color: #fff;line-height: 16px;'&gt;       &lt;div style="float: left; margin-right: 5px; overflow: visible;"&gt;&lt;a href='http://posterous.com/getfile/files.posterous.com/cleancoder/omANhadhZYd5xw0xDaYoFc3ZOIm5DkrPG8TM2cS1mCmPbjxZlLsiex487DdP/mentoring.mp3' style='color: #bc7134;'&gt;&lt;img src='http://posterous.com/images/filetypes/mp3.png' style='border: none;'/&gt;&lt;/a&gt;&lt;/div&gt;       &lt;div style="font-size: 10px; color: #424037;line-height: 16px;"&gt;&lt;b&gt;Mentoring&lt;/b&gt; by Robert C Martin&amp;nbsp;&amp;nbsp;&lt;br/&gt;Download now or &lt;a href='http://cleancoder.posterous.com/mentoring-apprenticeship-a-reading-from-the-c' style='color: #bc7134;'&gt;listen on posterous&lt;/a&gt;&lt;/div&gt;       &lt;b&gt;&lt;a href='http://posterous.com/getfile/files.posterous.com/cleancoder/omANhadhZYd5xw0xDaYoFc3ZOIm5DkrPG8TM2cS1mCmPbjxZlLsiex487DdP/mentoring.mp3' style='color: #bc7134;'&gt;mentoring.mp3&lt;/a&gt;&lt;/b&gt; &lt;span style="font-size: 10px; color: #424037;"&gt;(17930 KB)&lt;/span&gt;       &lt;br style="clear: both;"/&gt;&lt;/div&gt;      &lt;p&gt;---- &lt;br /&gt;Robert C. Martin (Uncle Bob) | &lt;a href="mailto:unclebob@cleancoder.com"&gt;unclebob@cleancoder.com&lt;/a&gt; &lt;br /&gt;Uncle Bob Consulting LLC. | @unclebobmartin &lt;br /&gt;847.922.0563 | web: objectmentor.com&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-462008774780496094?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/462008774780496094/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2010/11/mentoring-apprenticeship-reading-from_28.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/462008774780496094'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/462008774780496094'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2010/11/mentoring-apprenticeship-reading-from_28.html' title='Mentoring &amp;amp; Apprenticeship (A reading from: &amp;quot;The Clean Coder&amp;quot;)'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-7220112569298080864</id><published>2010-11-27T09:00:00.001-08:00</published><updated>2010-11-27T09:00:04.630-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='podcasts'/><title type='text'>Mentoring &amp; Apprenticeship (A reading from: "The Clean Coder")</title><content type='html'>&lt;div class='posterous_autopost'&gt;       &lt;div style='padding: 5px 5px 10px 5px; margin-top: 5px; border: 1px solid #ddd; background-color: #fff;line-height: 16px;'&gt;       &lt;div style="float: left; margin-right: 5px; overflow: visible;"&gt;&lt;a href='http://posterous.com/getfile/files.posterous.com/cleancoder/omANhadhZYd5xw0xDaYoFc3ZOIm5DkrPG8TM2cS1mCmPbjxZlLsiex487DdP/mentoring.mp3' style='color: #bc7134;'&gt;&lt;img src='http://posterous.com/images/filetypes/mp3.png' style='border: none;'/&gt;&lt;/a&gt;&lt;/div&gt;       &lt;div style="font-size: 10px; color: #424037;line-height: 16px;"&gt;&lt;b&gt;Mentoring&lt;/b&gt; by Robert C Martin&amp;nbsp;&amp;nbsp;&lt;br/&gt;Download now or &lt;a href='http://cleancoder.posterous.com/mentoring-apprenticeship-a-reading-from-the-c' style='color: #bc7134;'&gt;listen on posterous&lt;/a&gt;&lt;/div&gt;       &lt;b&gt;&lt;a href='http://posterous.com/getfile/files.posterous.com/cleancoder/omANhadhZYd5xw0xDaYoFc3ZOIm5DkrPG8TM2cS1mCmPbjxZlLsiex487DdP/mentoring.mp3' style='color: #bc7134;'&gt;mentoring.mp3&lt;/a&gt;&lt;/b&gt; &lt;span style="font-size: 10px; color: #424037;"&gt;(17930 KB)&lt;/span&gt;       &lt;br style="clear: both;"/&gt;&lt;/div&gt;      &lt;p&gt;---- &lt;br /&gt;Robert C. Martin (Uncle Bob) | &lt;a href="mailto:unclebob@cleancoder.com"&gt;unclebob@cleancoder.com&lt;/a&gt; &lt;br /&gt;Uncle Bob Consulting LLC. | @unclebobmartin &lt;br /&gt;847.922.0563 | web: objectmentor.com&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-7220112569298080864?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/7220112569298080864/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2010/11/mentoring-apprenticeship-reading-from.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/7220112569298080864'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/7220112569298080864'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2010/11/mentoring-apprenticeship-reading-from.html' title='Mentoring &amp;amp; Apprenticeship (A reading from: &amp;quot;The Clean Coder&amp;quot;)'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-3165588492545714935</id><published>2010-11-23T10:15:00.001-08:00</published><updated>2010-11-23T10:15:35.969-08:00</updated><title type='text'>A Certification Worth Having.</title><content type='html'>&lt;div class='posterous_autopost'&gt;&lt;ul&gt; &lt;li&gt;If you spend months studying and working just for the &lt;em&gt;chance&lt;/em&gt; of getting it; then it&amp;rsquo;s worth having.&lt;/li&gt; &lt;li&gt;If other people know that you had to work your ass off to get that piece of paper, then the piece of paper is worth showing.&lt;/li&gt; &lt;li&gt;If well-recognized masters scrutinize and examine you after your study and effort, and then &lt;em&gt;sign their name&lt;/em&gt;, then that piece of paper is &lt;em&gt;golden&lt;/em&gt;.&lt;/li&gt; &lt;li&gt;If only half the people who make the attempt achieve the goal, then that piece of paper is a competitive advantage.&lt;/li&gt; &lt;/ul&gt;   &lt;p&gt;That&amp;rsquo;s the long and short of it.  A certification worth having is one that you have to work your ass off just to get a chance of receiving.&lt;/p&gt;  &lt;ul&gt; &lt;li&gt;It should take months or years.&lt;/li&gt; &lt;li&gt;It should cost a lot, just to make the attempt.&lt;/li&gt; &lt;li&gt;It should be backed by experts whose reputations are on the line.&lt;/li&gt; &lt;li&gt;A sizable fraction should fail or drop-out.&lt;/li&gt; &lt;/ul&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-3165588492545714935?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/3165588492545714935/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2010/11/certification-worth-having.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/3165588492545714935'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/3165588492545714935'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2010/11/certification-worth-having.html' title='A Certification Worth Having.'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-1409545820236781864</id><published>2010-11-22T14:15:00.001-08:00</published><updated>2010-11-22T14:15:32.725-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scrum'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Certification'/><title type='text'>What Killed Waterfall Could Kill Agile.</title><content type='html'>&lt;div class='posterous_autopost'&gt;       &lt;div style='padding: 5px 5px 10px 5px; margin-top: 5px; border: 1px solid #ddd; background-color: #fff;line-height: 16px;'&gt;       &lt;div style="float: left; margin-right: 5px; overflow: visible;"&gt;&lt;a href='http://posterous.com/getfile/files.posterous.com/cleancoder/VsYK3gN8nEusY9lyM9DuNkXFlWoeDJTBBEzztb8TyJZUxKJGrdBdoA5J2wet/What_Killed_Waterfall_could_Ki.docx' style='color: #bc7134;'&gt;&lt;img src='http://posterous.com/images/filetypes/doc.png' style='border: none;'/&gt;&lt;/a&gt;&lt;/div&gt;       &lt;div style="font-size: 10px; color: #424037;line-height: 16px;"&gt;Download now or &lt;a href='http://cleancoder.posterous.com/what-killed-waterfall-could-kill-agile' style='color: #bc7134;'&gt;preview on posterous&lt;/a&gt;&lt;/div&gt;       &lt;b&gt;&lt;a href='http://posterous.com/getfile/files.posterous.com/cleancoder/VsYK3gN8nEusY9lyM9DuNkXFlWoeDJTBBEzztb8TyJZUxKJGrdBdoA5J2wet/What_Killed_Waterfall_could_Ki.docx' style='color: #bc7134;'&gt;What Killed Waterfall could Kill Agile.docx&lt;/a&gt;&lt;/b&gt; &lt;span style="font-size: 10px; color: #424037;"&gt;(153 KB)&lt;/span&gt;       &lt;br style="clear: both;"/&gt;&lt;/div&gt;      &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-1409545820236781864?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/1409545820236781864/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2010/11/what-killed-waterfall-could-kill-agile.html#comment-form' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/1409545820236781864'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/1409545820236781864'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2010/11/what-killed-waterfall-could-kill-agile.html' title='What Killed Waterfall Could Kill Agile.'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-8267922758054681776</id><published>2010-11-09T12:44:00.000-08:00</published><updated>2010-11-09T12:44:34.651-08:00</updated><title type='text'>Craftsman 63: Specifics and Generics.</title><content type='html'>&lt;style&gt;@font-face {  font-family: "Courier New";}@font-face {  font-family: "Wingdings";}@font-face {  font-family: "Verdana";}@font-face {  font-family: "Tahoma";}p.MsoNormal, li.MsoNormal, div.MsoNormal { margin: 0in 0in 0.0001pt; font-size: 12pt; font-family: "Times New Roman"; }h3 { margin-right: 0in; margin-left: 0in; font-size: 13.5pt; font-family: "Times New Roman"; }p.MsoFootnoteText, li.MsoFootnoteText, div.MsoFootnoteText { margin: 0in 0in 0.0001pt; font-size: 10pt; font-family: "Times New Roman"; }p.MsoCommentText, li.MsoCommentText, div.MsoCommentText { margin: 0in 0in 0.0001pt; font-size: 10pt; font-family: "Times New Roman"; }span.MsoFootnoteReference { vertical-align: super; }span.MsoCommentReference {  }p.MsoBodyTextIndent, li.MsoBodyTextIndent, div.MsoBodyTextIndent { margin: 0in 0in 6pt 0.25in; font-size: 12pt; font-family: "Times New Roman"; }p.MsoBodyTextFirstIndent2, li.MsoBodyTextFirstIndent2, div.MsoBodyTextFirstIndent2 { margin: 0in 0in 6pt 0.25in; text-indent: 10.5pt; font-size: 12pt; font-family: "Times New Roman"; }p.MsoBodyText3, li.MsoBodyText3, div.MsoBodyText3 { margin: 0in 0in 6pt; font-size: 8pt; font-family: "Times New Roman"; }a:link, span.MsoHyperlink { color: blue; text-decoration: underline; }a:visited, span.MsoHyperlinkFollowed { color: purple; text-decoration: underline; }em {  }pre { margin: 0in 0in 0.0001pt; font-size: 10pt; font-family: "Courier New"; }p.MsoAcetate, li.MsoAcetate, div.MsoAcetate { margin: 0in 0in 0.0001pt; font-size: 8pt; font-family: Tahoma; }span.Heading3Char { font-weight: bold; }p.BODY3, li.BODY3, div.BODY3 { margin: 3pt 0in 0.0001pt; text-align: justify; text-indent: 0.25in; font-size: 10pt; font-family: "Times New Roman"; color: black; }p.CHAPTITLE, li.CHAPTITLE, div.CHAPTITLE { margin: 0in 0in 0.0001pt; text-align: right; font-size: 24pt; font-family: "Times New Roman"; color: black; font-weight: bold; }p.QUOTES, li.QUOTES, div.QUOTES { margin: 0in 0in 0.0001pt; text-align: right; font-size: 10pt; font-family: "Times New Roman"; color: black; font-style: italic; }p.Code, li.Code, div.Code { margin: 0in 0in 0.0001pt; font-size: 9pt; font-family: "Courier New"; color: black; }span.CommentTextChar {  }p.ModCode, li.ModCode, div.ModCode { margin: 0in 0in 0.0001pt; font-size: 9pt; font-family: "Courier New"; color: red; font-weight: bold; }span.FootnoteTextChar {  }span.BalloonTextChar { font-family: Tahoma; }span.HTMLPreformattedChar { font-family: "Courier New"; }span.BODY3Char { color: black; }span.CodeChar { font-family: "Courier New"; color: black; }span.ModCodeChar { font-family: "Courier New"; color: red; font-weight: bold; }span.meta {  }span.fitlabel { font-family: Verdana; }span.StylefitlabelVerdana9ptItalicGray-80 { font-family: "Times New Roman"; color: gray; font-style: italic; }p.Pattern, li.Pattern, div.Pattern { margin: 3pt 0in 0.0001pt; text-align: justify; text-indent: 0.25in; font-size: 10pt; font-family: "Times New Roman"; font-variant: small-caps; color: black; }span.PatternChar { font-variant: small-caps; color: black; }span.fitgrey {  }span.body {  }span.pagetitle {  }span.BodyTextIndentChar {  }span.BodyTextFirstIndent2Char {  }span.BodyText3Char {  }div.Section1 { page: Section1; }ol { margin-bottom: 0in; }ul { margin-bottom: 0in; }&lt;/style&gt;     &lt;div class="CHAPTITLE" style="margin: 34pt 0in;"&gt;&lt;span&gt;The Craftsman: 63&lt;br /&gt;Specifics and Generics&lt;/span&gt;&lt;/div&gt;&lt;div class="QUOTES"&gt;&lt;span style="font-style: normal;"&gt;Robert C. Martin&lt;/span&gt;&lt;/div&gt;&lt;div class="QUOTES"&gt;&lt;span style="font-style: normal;"&gt;8 Nov, 2010&lt;/span&gt;&lt;/div&gt;&lt;div class="QUOTES"&gt;&lt;span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="text-indent: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="BODY3"&gt;&lt;i&gt;Sat, 18 Mar 2002, 13:00&lt;/i&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin: 3pt 0.5in 0.0001pt; text-indent: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="BODY3"&gt;&lt;span class="body"&gt;I was sitting in the observation deck practicing some code katas when I saw Avery walk by.&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3"&gt;&lt;span class="body"&gt;“Avery, come take a look at this.”&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3"&gt;&lt;span class="body"&gt;Aver stopped and looked over my shoulder.&lt;span&gt;&amp;nbsp; &lt;/span&gt;“Ah, you’re doing the &lt;i&gt;Stack&lt;/i&gt; kata.”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3"&gt;&lt;span class="body"&gt;“Yes, this is the third time I’ve done it this morning, and I’ve noticed something interesting.&lt;span&gt;&amp;nbsp; &lt;/span&gt;Do you have a few minutes?”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3"&gt;&lt;span class="body"&gt;Avery sat down next to me and chortled:&lt;span&gt;&amp;nbsp; &lt;/span&gt;“Most certainly and without the slightest hesitation.”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3"&gt;&lt;span class="body"&gt;I didn’t want to get into the formal banter game that we often played, so I just said: “Do you remember one of Mr. C’s rules about TDD?&lt;span&gt;&amp;nbsp; &lt;/span&gt;The one about tests being specific and code being generic?”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3"&gt;&lt;span class="body"&gt;“Indeed I do, Alphonse.&lt;span&gt;&amp;nbsp; &lt;/span&gt;Indeed I do.&lt;span&gt;&amp;nbsp; &lt;/span&gt;Let’s see. (Ahem): ‘&lt;i&gt;As the tests get more specific, the code get’s more generic&lt;/i&gt;.’ Is that the one?”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3"&gt;&lt;span class="body"&gt;“Yes, that’s the one.&lt;span&gt;&amp;nbsp; &lt;/span&gt;I always thought I knew what it meant, but this morning something kind of hit me.”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3"&gt;&lt;span class="body"&gt;“And what was it that caught your attention, if I may ask?”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3"&gt;&lt;span class="body"&gt;“Let’s walk through the &lt;i&gt;Stack&lt;/i&gt; kata, and I’ll show you.”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3"&gt;&lt;span class="body"&gt;“Very well, Alphonse, Shall I endeavor to write the first test?”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3"&gt;&lt;span class="body"&gt;“Please do.”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3"&gt;&lt;span class="body"&gt;And so Avery wrote the first test of the &lt;i&gt;Stack&lt;/i&gt; kata:&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;public class StackTest {&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;@Test&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;public void newStackShouldBeEmpty() &lt;span&gt;&amp;nbsp;&lt;/span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;Stack stack = new Stack();&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;assertThat(stack.size(), equalTo(0));&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="BODY3"&gt;&lt;span class="body"&gt;I responded with the standard ritual.&lt;span&gt;&amp;nbsp; &lt;/span&gt;“OK, now I can make that fail with this…”&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;public class Stack {&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;public int size() {&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;return -1;&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="BODY3"&gt;&lt;span class="body"&gt;“…and I can make it pass with this.”&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;public int size() {&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;return 0;&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="text-indent: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="BODY3"&gt;&lt;span class="body"&gt;“Excellent, Alphonse. Nicely done!&lt;span&gt;&amp;nbsp; &lt;/span&gt;Now for the next test, we’ll ensure that the size, after a push, is one.”&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;@Test&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;public void sizeAfterPushShouldBeOne() &lt;span&gt;&amp;nbsp;&lt;/span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;Stack stack = new Stack();&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;stack.push(0);&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;assertThat(stack.size(), equalTo(1));&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“OK, and I can make that pass with a simple increment.”&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;public class Stack {&lt;/span&gt;&lt;/div&gt;&lt;div class="ModCode"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;private int size;&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;public int size() {&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;return &lt;/span&gt;&lt;span class="ModCodeChar"&gt;size&lt;/span&gt;&lt;span class="body"&gt;;&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="ModCode"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;public void push(int element) {&lt;/span&gt;&lt;/div&gt;&lt;div class="ModCode"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;size++;&lt;/span&gt;&lt;/div&gt;&lt;div class="ModCode"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“Oh, well done, well done, Avery old chap…”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;I interrupted him.&lt;span&gt;&amp;nbsp; &lt;/span&gt;“OK, Avery, this is what I wanted to show you.&lt;span&gt;&amp;nbsp; &lt;/span&gt;Notice that I changed the &lt;/span&gt;&lt;span class="CodeChar"&gt;&lt;span style="font-size: 9pt;"&gt;size&lt;/span&gt;&lt;/span&gt;&lt;span class="body"&gt; method to return a variable instead of a constant?” &lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“Indeed!”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“Right, so that’s taking something very specific and making it more general.”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“Indeed.&lt;span&gt;&amp;nbsp; &lt;/span&gt;Indeed.&lt;span&gt;&amp;nbsp; &lt;/span&gt;What could be more specific than a constant? And certainly a variable, by its very nature, is more general than a constant.&lt;span&gt;&amp;nbsp; &lt;/span&gt;After all a constant has only one value, whereas a variable can have many different values.&lt;span&gt;&amp;nbsp; &lt;/span&gt;An astute observation that!”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“But now,” he continued,&lt;span&gt;&amp;nbsp; &lt;/span&gt;“I must insist that after a pop, the size should be zero once again.”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;Had he really understood my point?&lt;span&gt;&amp;nbsp; &lt;/span&gt;If not, I had more to show him.&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“Right.” I said.&lt;span&gt;&amp;nbsp; &lt;/span&gt;“And don’t forget to refactor the tests to eliminate the duplication.”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“Oh, I shan’t forget, Alphonse.&lt;span&gt;&amp;nbsp; &lt;/span&gt;I shan’t forget.”&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;public class StackTest {&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;private Stack stack;&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;@Before&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;public void setUp() &lt;span&gt;&amp;nbsp;&lt;/span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;stack = new Stack();&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;…&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;@Test&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;public void sizeAfterPushAndPopShouldBeZero() &lt;span&gt;&amp;nbsp;&lt;/span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;stack.push(0);&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;stack.pop();&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;assertThat(stack.size(), equalTo(0));&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“OK, and now I can make this pass with a simple decrement.”&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;public int pop() {&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;size--;&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;return -1;&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“Capital, old sport!&lt;span&gt;&amp;nbsp; &lt;/span&gt;Capital!&lt;span&gt;&amp;nbsp; &lt;/span&gt;But now, I’m afraid that it’s quite necessary to prevent you from popping an empty stack.&lt;span&gt;&amp;nbsp; &lt;/span&gt;I do hope that doesn’t inconvenience you too much.”&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;@Test(expected=Stack.Underflow.class)&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;public void shouldThrowUnderflowWhenEmptyStackIsPopped() &lt;span&gt;&amp;nbsp;&lt;/span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;stack.pop();&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“Good.” I said, still ignoring his patois, “Now I can make that pass by checking for zero.”&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;public int pop() {&lt;/span&gt;&lt;/div&gt;&lt;div class="ModCode"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;if (size == 0)&lt;/span&gt;&lt;/div&gt;&lt;div class="ModCode"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;throw new Underflow();&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;size--;&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;return -1;&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;…&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="ModCode"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;public class Underflow extends RuntimeException {&lt;/span&gt;&lt;/div&gt;&lt;div class="ModCode"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“Outstanding!&lt;span&gt;&amp;nbsp; &lt;/span&gt;Simply outstanding!&lt;span&gt;&amp;nbsp; &lt;/span&gt;You clearly have mastery over your medium.&lt;span&gt;&amp;nbsp; &lt;/span&gt;But now, alas, I must further impose upon you.&lt;span&gt;&amp;nbsp; &lt;/span&gt;You see, you must not allow the stack to exceed the specified size.”&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;@Before&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;public void setUp() &lt;span&gt;&amp;nbsp;&lt;/span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;stack = new Stack(&lt;/span&gt;&lt;span class="ModCodeChar"&gt;2&lt;/span&gt;&lt;span class="body"&gt;);&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;…&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;@Test(expected=Stack.Overflow.class)&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;public void shouldThrowOverflowWhenFullStackIsPushed() &lt;span&gt;&amp;nbsp;&lt;/span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;stack.push(1);&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;stack.push(2);&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;stack.push(3);&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“Good.&lt;span&gt;&amp;nbsp; &lt;/span&gt;Now I can make that pass by creating the constructor and then comparing the size against the capacity in the &lt;/span&gt;&lt;span class="CodeChar"&gt;&lt;span style="font-size: 9pt;"&gt;push&lt;/span&gt;&lt;/span&gt;&lt;span class="body"&gt; method.&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;public class Stack {&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;private int size;&lt;/span&gt;&lt;/div&gt;&lt;div class="ModCode"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;private int capacity;&lt;/span&gt;&lt;/div&gt;&lt;div class="ModCode"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="ModCode"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;public Stack(int capacity) {&lt;/span&gt;&lt;/div&gt;&lt;div class="ModCode"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;this.capacity = capacity;&lt;/span&gt;&lt;/div&gt;&lt;div class="ModCode"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;…&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;public void push(int element) {&lt;/span&gt;&lt;/div&gt;&lt;div class="ModCode"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;if (size == capacity)&lt;/span&gt;&lt;/div&gt;&lt;div class="ModCode"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;throw new Overflow();&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;size++;&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;…&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;public class Underflow extends RuntimeException {&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="ModCode"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;public class Overflow extends RuntimeException {&lt;/span&gt;&lt;/div&gt;&lt;div class="ModCode"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“Sheer brilliance, old sport, old coot, old sod!&lt;span&gt;&amp;nbsp; &lt;/span&gt;But enough of these mundane machinations.&lt;span&gt;&amp;nbsp; &lt;/span&gt;It’s time to make this sad excuse of a program begin to act like a stack.&lt;span&gt;&amp;nbsp; &lt;/span&gt;So when you push an element, I must require that you pop that self-same element!”&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;@Test&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;public void shouldPopZeroWhenZeroIsPushed() &lt;span&gt;&amp;nbsp;&lt;/span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;stack.push(0);&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;assertThat(stack.pop(), equalTo(0));&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“I’m afraid, dear Avery, that I can make that pass rather trivially.”&lt;span&gt;&amp;nbsp; &lt;/span&gt;I cursed myself under my breath for succumbing to his banter.&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;public int pop() {&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;if (size == 0)&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;throw new Underflow();&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;--size;&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;return &lt;/span&gt;&lt;span class="ModCodeChar"&gt;0&lt;/span&gt;&lt;span class="body"&gt;;&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“Devilishly clever my boy!&lt;span&gt;&amp;nbsp; &lt;/span&gt;You parried my thrust with just a flick of your wrist!&lt;span&gt;&amp;nbsp; &lt;/span&gt;But can you flick this away just as casually?”&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;@Test&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;public void shouldPopOneWhenOneIsPushed() &lt;span&gt;&amp;nbsp;&lt;/span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;stack.push(1);&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;assertThat(stack.pop(), equalTo(1));&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;I forced myself to avoid the banter.&lt;span&gt;&amp;nbsp; &lt;/span&gt;“This one is going to require a variable. And once again, notice that we are replacing something specific, with something more general.”&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;public class Stack {&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;…&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;private int element;&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;…&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;public void push(int element) {&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;if (size == capacity)&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;throw new Overflow();&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;size++;&lt;/span&gt;&lt;/div&gt;&lt;div class="ModCode"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;this.element = element;&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;public int pop() {&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;if (size == 0)&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;throw new Underflow();&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;--size;&lt;/span&gt;&lt;/div&gt;&lt;div class="ModCode"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;return element;&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;…&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“Oh, ho!&lt;span&gt;&amp;nbsp; &lt;/span&gt;Yes, again, the constant is replaced with a variable.&lt;span&gt;&amp;nbsp; &lt;/span&gt;Specifics become generics.&lt;span&gt;&amp;nbsp; &lt;/span&gt;Well done, Alphonse!&lt;span&gt;&amp;nbsp; &lt;/span&gt;Well done!&lt;span&gt;&amp;nbsp; &lt;/span&gt;But as yet this beast behaveth not as ought a stack.&lt;span&gt;&amp;nbsp; &lt;/span&gt;Therefore shall I maketh you to perform a true FIFO operation!”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;Why did he add that old-english twist?&lt;span&gt;&amp;nbsp; &lt;/span&gt;Was I distracting him?&lt;span&gt;&amp;nbsp; &lt;/span&gt;Was he looking ahead to the end-game and losing concentration?&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;@Test&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;public void PushedElementsArePoppedInReverseOrder() &lt;span&gt;&amp;nbsp;&lt;/span&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;stack.push(1);&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;stack.push(2);&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;assertThat(stack.pop(), equalTo(2));&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;assertThat(stack.pop(), equalTo(1));&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“OK, Avery, now watch this carefully.”&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;public class Stack {&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;…&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;private int elements&lt;/span&gt;&lt;span class="ModCodeChar"&gt;[]&lt;/span&gt;&lt;span class="body"&gt;;&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;public Stack(int capacity) {&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;this.capacity = capacity;&lt;/span&gt;&lt;/div&gt;&lt;div class="ModCode"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;elements = new int[capacity];&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;public void push(int element) {&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;if (size == capacity)&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;throw new Overflow();&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;element&lt;/span&gt;&lt;span class="ModCodeChar"&gt;s[&lt;/span&gt;size++&lt;span class="ModCodeChar"&gt;]&lt;/span&gt;&lt;span class="body"&gt; = element;&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;public int pop() {&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;if (size == 0)&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;throw new Underflow();&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;return element&lt;/span&gt;&lt;span class="ModCodeChar"&gt;s[&lt;/span&gt;--size&lt;span class="ModCodeChar"&gt;]&lt;/span&gt;&lt;span class="body"&gt;;&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;&lt;span&gt;&amp;nbsp; &lt;/span&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;…&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;span class="body"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;div class="Code"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“Do you see what happened Avery?&lt;span&gt;&amp;nbsp; &lt;/span&gt;We transformed that &lt;/span&gt;&lt;span class="CodeChar"&gt;&lt;span style="font-size: 9pt;"&gt;element&lt;/span&gt;&lt;/span&gt;&lt;span class="body"&gt; variable into something more general than a variable.&lt;span&gt;&amp;nbsp; &lt;/span&gt;We transformed it into an array.”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;Avery just looked at the code with his brows knitted together. &lt;span&gt;&amp;nbsp;&lt;/span&gt;His normally bulging eyes bulged even further.&lt;span&gt;&amp;nbsp; &lt;/span&gt;I could see the wheels turning in his head.&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“Alphonse, do you realize that you didn’t delete that &lt;/span&gt;&lt;span class="CodeChar"&gt;&lt;span style="font-size: 9pt;"&gt;size&lt;/span&gt;&lt;/span&gt;&lt;span class="body"&gt; code?&lt;span&gt;&amp;nbsp; &lt;/span&gt;You just moved it around.”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“What do you mean?”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“I mean that all that silly code that we wrote at first, the code for the &lt;/span&gt;&lt;span class="CodeChar"&gt;&lt;span style="font-size: 9pt;"&gt;size&lt;/span&gt;&lt;/span&gt;&lt;span class="body"&gt; variable in order to pass the initial tests.&lt;span&gt;&amp;nbsp; &lt;/span&gt;I usually think of that as throwaway code – just something to do to get the early tests to pass.&lt;span&gt;&amp;nbsp; &lt;/span&gt;But we didn’t delete that code; we &lt;i&gt;moved&lt;/i&gt; it.&lt;span&gt;&amp;nbsp; &lt;/span&gt;We moved the &lt;/span&gt;&lt;span class="CodeChar"&gt;&lt;span style="font-size: 9pt;"&gt;size++&lt;/span&gt;&lt;/span&gt;&lt;span class="body"&gt; and &lt;/span&gt;&lt;span class="CodeChar"&gt;&lt;span style="font-size: 9pt;"&gt;--size &lt;/span&gt;&lt;/span&gt;&lt;span class="body"&gt;into array subscripts.”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“Yeah.” I said. “Maybe that code wasn’t so silly after all.&lt;span&gt;&amp;nbsp; &lt;/span&gt;It certainly wasn’t throwaway.&lt;span&gt;&amp;nbsp; &lt;/span&gt;But did you notice the &lt;i&gt;transformations&lt;/i&gt;, Avery?&lt;span&gt;&amp;nbsp; &lt;/span&gt;We transformed specific code like constants, into generic code like variables and arrays.” &lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“Yeah, I &lt;i&gt;did&lt;/i&gt; notice that Alphonse, and that means that from one test to the next we were generalizing and moving code.”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“We also &lt;i&gt;added&lt;/i&gt; code like the constants, and the &lt;/span&gt;&lt;span class="CodeChar"&gt;&lt;span style="font-size: 9pt;"&gt;if&lt;/span&gt;&lt;/span&gt;&lt;span class="body"&gt; statements for the exceptions, and the increments and decrements.”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“Yeah!&lt;span&gt;&amp;nbsp; &lt;/span&gt;So the process of changing the production code from test to test is not one of rewriting so much as it is of adding, moving, and generalizing.”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“That’s cool!” I said. “It means that none of the code we write to pass the early tests is wasted code; it’s just code that’s incomplete, not properly placed, or not general enough.&lt;span&gt;&amp;nbsp; &lt;/span&gt;It’s not that the code is wrong, it’s just – what’s the word?”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“Degenerate!” Avery said.&lt;span&gt;&amp;nbsp; &lt;/span&gt;“The early code is degenerate.&lt;span&gt;&amp;nbsp; &lt;/span&gt;It’s not silly or wasted; it just young!&lt;span&gt;&amp;nbsp; &lt;/span&gt;It needs to evolve.&lt;span&gt;&amp;nbsp; &lt;/span&gt;That earlier code is the &lt;i&gt;progenitor&lt;/i&gt; of the latter code.”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“I wonder.”&lt;span&gt;&amp;nbsp; &lt;/span&gt;I said.&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“What?”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“I wonder if this is &lt;i&gt;always&lt;/i&gt; true.&lt;span&gt;&amp;nbsp; &lt;/span&gt;Can you always evolve code, from test to test, by adding, moving, or generalizing it?&lt;span&gt;&amp;nbsp; &lt;/span&gt;Is the process of TDD really just a set of successive generalizations constrained by tests?”&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in;"&gt;&lt;span class="body"&gt;“I don’t know.&lt;span&gt;&amp;nbsp; &lt;/span&gt;Let’s try the Prime Factors kata…”&lt;span&gt;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="BODY3" style="margin-right: 0.5in; text-indent: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-8267922758054681776?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/8267922758054681776/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2010/11/craftsman-63-specifics-and-generics.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/8267922758054681776'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/8267922758054681776'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2010/11/craftsman-63-specifics-and-generics.html' title='Craftsman 63: Specifics and Generics.'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-3659132717813435853</id><published>2010-10-21T10:58:00.000-07:00</published><updated>2010-10-21T10:58:48.149-07:00</updated><title type='text'>Danger! Software Craftsmen at Work.</title><content type='html'>On October 12, 2010 at QCon &lt;a href="http://www.teamsandtechnology.com/dh/"&gt;David Harvey&lt;/a&gt; gave a talk entitled &lt;a href="http://www.infoq.com/presentations/Danger-Software-Craftsmen-at-Work"&gt;Danger! Software Craftsmen at Work&lt;/a&gt;.&amp;nbsp; This talk was nicely summarized and expanded upon by &lt;span class="author"&gt;&lt;a href="http://www.sharpcrafters.com/blog/author/Gael-Fraiteur.aspx"&gt;Gael Fraiteur&lt;/a&gt; in his blog: &lt;a href="http://www.sharpcrafters.com/blog/post/Why-Should-We-Care-About-Software-Craftsmanship-Part-2.aspx"&gt;Why Should We Care About Software Craftsmanship?&amp;nbsp; Part 2&lt;/a&gt;.&amp;nbsp; But I have a few things to add.&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;br /&gt;&lt;span class="author"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="author"&gt;Harvey makes the following points (as described by Fraiteur):&lt;/span&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;The Manifesto for Software Craftsmanship is empty of content  because it is not refutable, i.e. it is not possible for a reasonable  person to disagree.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The opposition of software  craftsmanship to software engineering is pointless and may even give  permission to software developers to ignore the lessons of software  engineering.      &lt;br /&gt;&lt;/li&gt;&lt;li&gt;Metaphors, and the language we are  using to describe ourselves and our activity, do matter. The people  around us think of a craftsman as someone producing leather bags, not  items you can rely on. Although software developers have their own  definition of craftsmanship, what eventually matters is the perception  of our customers. By choosing inappropriate metaphors, we are increasing  the gap between those who build software, and those who use it.&amp;nbsp;&lt;/li&gt;&lt;/ol&gt;&lt;b&gt;&lt;span style="font-size: small;"&gt;The Empty Manifesto&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;Is the Manifesto for Software Craftsmanship empty because it is irrefutable?&amp;nbsp; I think the notion is absurd.&amp;nbsp; That's like saying that the Hippocratic Oath, or the Golden Rule are empty because they are irrefutable.&amp;nbsp; The Manifesto is not a scientific hypothesis that requires experimental verification.&amp;nbsp; Rather the Manifesto is a statement of beliefs and values that the signatories adhere to and promote.&amp;nbsp; The Manifesto contains articles of &lt;i&gt;belief&lt;/i&gt;, not statements of measurable fact,  and is therefore not required to be falsifiable.&lt;br /&gt;&lt;br /&gt;Is the Manifesto irrefutable?&amp;nbsp; Would that it were so!&amp;nbsp; Unfortunately the Manifesto is regularly refuted in both word and deed.&amp;nbsp; For example, the first article of the Manifesto states that we value well-crafted software over working software; yet there continues a significant debate on the topic of "good-enough software".&amp;nbsp; There is a large cohort of software developers who contend that well-crafted code is antithetical to time-to-market.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;The second article of the Manifesto is more interesting still.&amp;nbsp; It promotes the steady addition of value over simply responding to change.&amp;nbsp; What value does this refer to?&amp;nbsp; It refers both to the value of the software's function, and the value of it's structure.&amp;nbsp; That is, we as craftsman, will continue to steadily improve both the structure and function of the software, rather than simply responding to change.&amp;nbsp; This kind of responsible behavior is refuted daily by the actions of developers who release changes that damage both structure and function.&amp;nbsp; If you doubt that this happens, consider &lt;a href="http://vimeo.com/9981123"&gt;this&lt;/a&gt; video of bad code that I posted a few months ago.&amp;nbsp; Believe it or not, this is deployed production code.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Engineering vs. Craftsmanship.&lt;/b&gt;&lt;br /&gt;Is craftsmanship antithetical to engineering?&amp;nbsp; Harvey suggests this possibility based on some of the statements in &lt;a href="http://www.mcbreen.ab.ca/"&gt;Pete McBreen&lt;/a&gt;'s classic book &lt;a href="http://www.amazon.com/exec/obidos/ASIN/0201733862/mcbreenconsul-20/nosim"&gt;Software Craftsmanship&lt;/a&gt; in which he derides some of the more egregious, high-ceremony and high-documentation practices associated with Software Engineering.&amp;nbsp; Harvey suggests that this may give "permission" to budding software craftsmen to ignore the good software engineering work that has been done over the decades.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;I agree that this would be a bad thing.&amp;nbsp; We don't want anyone in the Software Craftsmanship community to dismiss Software Engineering out of hand.&amp;nbsp; The problem I have with Harvey's&amp;nbsp; suggestion, however,&amp;nbsp; is that none of the leaders in the Software Craftsmanship movement espouse the view that the history of Software Engineering is worthless.&amp;nbsp; Indeed, quite the opposite is true.&amp;nbsp; Software Craftsmen see themselves &lt;i&gt;as&lt;/i&gt; &lt;i&gt;Software Engineers&lt;/i&gt;.&amp;nbsp; That does not mean we accept all of the Software Engineering dogma that has accumulated over the decades.&amp;nbsp; It also doesn't mean that we reject it.&amp;nbsp; It &lt;i&gt;does&lt;/i&gt; mean that we &lt;i&gt;learn&lt;/i&gt; it.&lt;br /&gt;&lt;br /&gt;The Software Craftsmanship community is deeply committed to learning the lessons of the past.&amp;nbsp; That means studying the things we did right, &lt;i&gt;and&lt;/i&gt; the things we did wrong.&amp;nbsp; Software Craftsmen &lt;i&gt;immerse&lt;/i&gt; themselves in their craft.&amp;nbsp; We continue to read the old books by DeMarco, Yourdon, Parnas, Dijkstra, Hoare, Weinberg, and their brethren.&amp;nbsp; We study at the feet of the old masters so that we can learn how to be the next masters.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;It is true that we have currently tabled some of the older practices that have been associated with Software Engineering; &lt;i&gt;but we do not disrespect&lt;/i&gt; those practices, nor the people who at one time proposed and adopted them.&amp;nbsp; They were pioneers who led the way and who, in some cases, showed us the paths to avoid.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;The Craftsman Connotation&lt;/b&gt;&lt;br /&gt;Harvey advises us to take care with the metaphors we choose.&amp;nbsp; He makes the point that terms like craft, dojo, kata, apprentice, master etc., can have negative connotations.&amp;nbsp; The word "craft" for example, may bring to mind the kind of quality one experiences at a flea-market or a craft fair.&amp;nbsp; The martial-arts terms that are sometimes common in craftsmanship circles may bring to mind the notion of the "omnipotent loner" like Bruce Lee, or Neo.&amp;nbsp; The terms "Master", "Journeyman", and "Apprentice" may bring to mind the secretive guilds of the middle ages with all their ritual, mysticism, and intrigue.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;I think this is a legitimate concern.&amp;nbsp; I also think it's easily dealt with.&amp;nbsp; The strategy I've been using is "guilt by association".&amp;nbsp; When I talk about Software Craftsmanship, I also talk about Software Professionalism.&amp;nbsp; I use the terms interchangeably in order to enforce the association in my listeners' (and readers') minds.&amp;nbsp; When I talk about dojo's and kata's, it is always in the connotation of "practice'.&amp;nbsp; I use the terms together so that there is no doubt about what the terms actually mean.&lt;br /&gt;&lt;br /&gt;Harvey is right in that we don't want to create a "secret language".&amp;nbsp; There is nothing wrong with the memes we've chosen to communicate amongst ourselves; but we have to be careful to make sure we associate those memes with concepts like &lt;i&gt;professionalism&lt;/i&gt;, &lt;i&gt;practice&lt;/i&gt;, and &lt;i&gt;seniority&lt;/i&gt; that our customers and employers understand and appreciate.&amp;nbsp;&amp;nbsp; We want these people's support.&amp;nbsp; We want them to believe and trust in the values that we espouse.&amp;nbsp; We will not accomplish that by disrespecting the metaphors that they depend upon.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="author"&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-3659132717813435853?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/3659132717813435853/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2010/10/danger-software-craftsmen-at-work.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/3659132717813435853'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/3659132717813435853'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2010/10/danger-software-craftsmen-at-work.html' title='Danger! Software Craftsmen at Work.'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-1196862138370407456</id><published>2010-10-17T10:59:00.000-07:00</published><updated>2010-10-17T10:59:40.067-07:00</updated><title type='text'>The Cost of Code?</title><content type='html'>In a panel at #scna yesterday, @chadfowler asked the question: "How many projects fail because of the code?"&amp;nbsp; I think the point he was trying to make was that the primary causes of project failure are business issues, not technical issues.&lt;br /&gt;&lt;br /&gt;I posed this question on twitter earlier today.&amp;nbsp; The responses came quickly, and virtually all of them agreed that business issues are the more significant causes of project failure. &lt;br /&gt;&lt;br /&gt;It's certainly true that projects fail because of cost, requirements, schedule, management. etc.&amp;nbsp; It's also true that we seldom trace the cause of failure back to something as mundane as code.&amp;nbsp; So Chad's point, if that's what it was, certainly has merit.&lt;br /&gt;&lt;br /&gt;The conclusion that we might make from this is that code just isn't very important in the long run, and the the craftsmanship movement might just be a load of Yak Shaving.&amp;nbsp; Indeed, Chad asked us to consider just that in his talk at #scna.&amp;nbsp; If we follow that reasoning, then we should decrease our emphasis on technological prowess and skill, and increase our emphasis on business, requirements, budgets, schedules, and management.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;Before I counter this argument, let me say that I &lt;i&gt;do&lt;/i&gt; know of projects that have failed because of the code.&amp;nbsp; Indeed, I know of &lt;i&gt;companies&lt;/i&gt; that have failed because of the code.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;This isn't actually very difficult to believe or understand.&amp;nbsp; We all know that when the code is a mess, it becomes more and more costly to maintain and improve.&amp;nbsp; If that cost exceeds what the project can afford, the project fails.&amp;nbsp; If that cost exceeds what the company can afford, the company fails.&amp;nbsp; In the cases that I am aware of, this is precisely what happened.&amp;nbsp; The code was simply too costly for the business model to support.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;So let's try a simple thought experiment.&amp;nbsp; What fraction of projects would fail if the code was &lt;i&gt;infinitely&lt;/i&gt; expensive to produce and maintain? Clearly &lt;i&gt;all&lt;/i&gt; projects would fail because the code would be too expensive for any finite business model to support.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;OK, so what if the code cost &lt;i&gt;nothing&lt;/i&gt; to produce and maintain?&amp;nbsp; What fraction of those projects would fail because of the code?&amp;nbsp; Again, the answer is clear.&amp;nbsp; No project would fail because of the code, if the code costs nothing to make.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;What does it mean to cost nothing to make?&amp;nbsp; It means that you would have the code you needed the instant you needed it.&amp;nbsp; The code would simply be there, instantly, fully functional,&amp;nbsp; free of defects.&amp;nbsp; Any time you needed a change, the change would instantly be in effect, fully deployed, fully operational.&lt;br /&gt;&lt;br /&gt;So let's say you are thrown into a cave&amp;nbsp; by some thieves.&amp;nbsp; In that cave you find a old beat-up PC jr, complete with the IR chicklet keyboard.&amp;nbsp; You pick up that keyboard and rub a smudge off the enter key.&amp;nbsp; Wooosh!&amp;nbsp; a genie appears on the screen and grants you the ability to have zero cost code for the rest of your life!&amp;nbsp; Would any of your projects ever fail from that point on?&lt;br /&gt;&lt;br /&gt;Remember, nobody else has your ability.&amp;nbsp; Nobody else can produce the code they want, instantly, and without defect.&amp;nbsp; Nobody else can make and deploy changes in zero time.&amp;nbsp; So you have a tremendous competitive advantage.&amp;nbsp; Is there any way you could fail?&amp;nbsp; I think my dog Petunia might fail, but anyone smarter than that should become a multi-trillionaire.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_McaZb7v3tS4/TLslFMtIPBI/AAAAAAAAABg/nD0wMjJ1wC8/s1600/petunia.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="239" src="http://1.bp.blogspot.com/_McaZb7v3tS4/TLslFMtIPBI/AAAAAAAAABg/nD0wMjJ1wC8/s320/petunia.JPG" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;If we had that magic PC jr, there wouldn't be any schedule or budget issues.&amp;nbsp; The cost of mismanagement and/or bad requirements would be close to zero.&amp;nbsp; So all those things that cause projects to fail would become irrelevant. &amp;nbsp;&lt;br /&gt;&lt;br /&gt;But we don't have that magic PC jr.&amp;nbsp; Code &lt;i&gt;does&lt;/i&gt; cost money to produce and maintain.&amp;nbsp; But if I, as a craftsman, can&amp;nbsp; invoke a fraction of the power of that Genie to reduce the cost of producing and maintaining code, then I simultaneously reduce the cost and risk of mismanagement, of bad requirements, of tight schedules, and of tight budgets.&amp;nbsp; By reducing the cost of the thing that's being managed, we reduce the cost of error and increase the chances of success!&lt;br /&gt;&lt;br /&gt;Why is it that projects fail due to bad requirements, bad management, bad schedules, and bad budgets?&amp;nbsp; They fail because the cost of error is &lt;i&gt;huge&lt;/i&gt;.&amp;nbsp; Why is the cost of error huge?&amp;nbsp; Because the cost of the code is so horribly large.&amp;nbsp; If code cost nothing to produce, the cost of error would be close to zero.&lt;br /&gt;&lt;br /&gt;This realization has not been lost on the business community.&amp;nbsp; They tried to solve it by reducing the hourly rate of programmers.&amp;nbsp; They set up horrifically expensive and risky mechanisms in order to hire programmers who lived half a world away in a wildly different culture.&amp;nbsp; They faced the issues of time zones and languages, and cultural mismatch in order to reduce the cost of code.&amp;nbsp; They did this because they understood that the it is &lt;i&gt;that cost &lt;/i&gt;that drives the cost of management error.&amp;nbsp; They did this because it is &lt;i&gt;that cost&lt;/i&gt; that makes projects fail. &lt;br /&gt;&lt;br /&gt;Unfortunately this strategy didn't work as well had been hoped.&amp;nbsp; Some folks have made it work; more or less.&amp;nbsp; But the majority of the off-shoring efforts have been disappointing.&amp;nbsp; And so the cost of code remains high, and therefore the risk of error is also high.&lt;br /&gt;&lt;br /&gt;And that brings us back to the question at hand.&amp;nbsp; How many projects fail because of the code?&amp;nbsp; The argument above suggests that &lt;i&gt;all&lt;/i&gt; failures are a direct result of the cost of code.&amp;nbsp; How many projects fail because of code?&amp;nbsp; &lt;i&gt;All of them!&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;More importantly, what is the single most effective way to increase the chances of project success?&amp;nbsp; Is it improving requirements?&amp;nbsp; Management?&amp;nbsp; Schedules and budgets?&amp;nbsp; All those things would help, but they are all secondary to the thing that truly drives project failure:&amp;nbsp; The cost of the code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-1196862138370407456?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/1196862138370407456/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2010/10/cost-of-code.html#comment-form' title='23 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/1196862138370407456'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/1196862138370407456'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2010/10/cost-of-code.html' title='The Cost of Code?'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_McaZb7v3tS4/TLslFMtIPBI/AAAAAAAAABg/nD0wMjJ1wC8/s72-c/petunia.JPG' height='72' width='72'/><thr:total>23</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-2219591269934409701</id><published>2010-10-17T07:12:00.000-07:00</published><updated>2010-10-17T07:12:59.074-07:00</updated><title type='text'>Be a good one.  #scna 2010</title><content type='html'>I didn't expect it, but something profound happened at #scna this week.&amp;nbsp; I expected the conference to be good.&amp;nbsp; I expected it to be fun.&amp;nbsp; I expected to see many old and new faces and have stimulating conversations.&amp;nbsp; And in all these things my expectations were met.&amp;nbsp; What I didn't expect was the &lt;i&gt;gelling&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;There was a meme at this conference that pervaded every talk and every session.&amp;nbsp; Doug Bradbury (&lt;strong&gt;&lt;a class="screen-name screen-name-dougbradbury pill" href="http://twitter.com/#%21/dougbradbury"&gt;&lt;strong&gt;@dougbradbury&lt;/strong&gt;&lt;/a&gt;)&lt;/strong&gt; coined it in the title of his talk: &lt;i&gt;Made to Make&lt;/i&gt;.&amp;nbsp; His point was that we are &lt;i&gt;makers&lt;/i&gt;.&amp;nbsp; We love to &lt;i&gt;make&lt;/i&gt;.&amp;nbsp; There is something within us drives us to create. &amp;nbsp; Doug opened his talk with a story from his childhood.&amp;nbsp; He was eight, hanging out with his grandfather in the workshop.&amp;nbsp; His grandfather saw him leaning over his child-sized workbench and asked him what he was doing.&amp;nbsp; "&lt;i&gt;I'm making stuff.&lt;/i&gt;" was his reply.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_TVhFMT7oEd0/TLmDuaQ0BdI/AAAAAAAAJ_0/_-Z5dM4ZI8I/0072.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="213" src="http://1.bp.blogspot.com/_TVhFMT7oEd0/TLmDuaQ0BdI/AAAAAAAAJ_0/_-Z5dM4ZI8I/0072.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Keavy McMinn (&lt;a class="screen-name screen-name-keavy pill" href="http://twitter.com/#%21/keavy"&gt;&lt;strong&gt;@keavy&lt;/strong&gt;&lt;/a&gt;), in her talk &lt;i&gt;Artist to Programmer&lt;/i&gt;, reiterated this meme more directly when she quoted one of her friend's tweets: "&lt;i&gt;I just want to make stuff, I don't really care if its Flash or objective-C or &lt;span class="query-token"&gt;fuzzy&lt;/span&gt; felt&lt;/i&gt;" and again later: "&lt;i&gt;The future belongs to the few of us still willing to get our hands dirty&lt;/i&gt;".&amp;nbsp; One of the most moving moments in Keayv's presentation was her description of daily refactoring a one-ton tower or bricks during an art show.&amp;nbsp; She showed pictures of this tower from day to day.&amp;nbsp; Each different.&amp;nbsp; Each telling a different story.&amp;nbsp; Each lovingly built.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://scna.softwarecraftsmanship.org/assets/42/keavy_bio_pic_86x100_thumbnail.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://scna.softwarecraftsmanship.org/assets/42/keavy_bio_pic_86x100_thumbnail.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Michael Norton (&lt;a class="screen-name screen-name-DocOnDev pill" href="http://twitter.com/#%21/DocOnDev"&gt;&lt;strong&gt;@DocOnDev&lt;/strong&gt;&lt;/a&gt;) talked about the history of medicine, medical education, and medical certification.&amp;nbsp; He placed it all on a time line and showed how medicine transitioned through phases of empirical observation, to the canonization of an initial body of knowledge, to rapid theoretical and technological development, to the intensely supervised and collaborative learning model of today.&amp;nbsp; And throughout this long history and transition, medicine began as, and remains, a craft developed by people who &lt;i&gt;love what they do&lt;/i&gt;.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_TVhFMT7oEd0/TLmCzCkFNLI/AAAAAAAAJ6k/CF63DQpFqIo/0160.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="213" src="http://3.bp.blogspot.com/_TVhFMT7oEd0/TLmCzCkFNLI/AAAAAAAAJ6k/CF63DQpFqIo/0160.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;I (&lt;strong&gt;&lt;a class="screen-name screen-name-unclebobmartin pill" href="http://twitter.com/#%21/unclebobmartin"&gt;&lt;strong&gt;@unclebobmartin&lt;/strong&gt;&lt;/a&gt;&lt;/strong&gt;) and Michael Feathers (&lt;a class="screen-name screen-name-mfeathers pill" href="http://twitter.com/#%21/mfeathers"&gt;&lt;strong&gt;@mfeathers&lt;/strong&gt;&lt;/a&gt;) both gave talks about functional programming, showing us new (old) ways to make our stuff.&amp;nbsp;&amp;nbsp; &lt;span class="query-token"&gt;Enrique&lt;/span&gt; Comba Riepenhausen (&lt;strong&gt;&lt;a class="screen-name screen-name-ecomba pill" href="http://twitter.com/#%21/ecomba"&gt;&lt;strong&gt;@ecomba&lt;/strong&gt;&lt;/a&gt;)&lt;/strong&gt; gave an impassioned talk about fostering partnerships with our customers, reiterating the pleas and advice from both Ken Auer and Chad Fowler (&lt;a class="screen-name screen-name-chadfowler pill" href="http://twitter.com/#%21/chadfowler"&gt;&lt;strong&gt;@chadfowler&lt;/strong&gt;&lt;/a&gt;) reminding us that: &lt;i&gt;We make things for others&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;There were lots of open-space sessions about all kinds of things.&amp;nbsp; Laptops were always open, Code was never far away.&amp;nbsp; There were "randori" coding sessions on stage.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_TVhFMT7oEd0/TLlOlhSjteI/AAAAAAAAJhw/1GjGgF0IY5s/0539.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="213" src="http://4.bp.blogspot.com/_TVhFMT7oEd0/TLlOlhSjteI/AAAAAAAAJhw/1GjGgF0IY5s/0539.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_TVhFMT7oEd0/TLlOrB5mwUI/AAAAAAAAJiU/SiMO391EQ0c/0531.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="213" src="http://4.bp.blogspot.com/_TVhFMT7oEd0/TLlOrB5mwUI/AAAAAAAAJiU/SiMO391EQ0c/0531.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_TVhFMT7oEd0/TLlN_M5-UII/AAAAAAAAJeM/VshUpAEnA0w/0592.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="213" src="http://4.bp.blogspot.com/_TVhFMT7oEd0/TLlN_M5-UII/AAAAAAAAJeM/VshUpAEnA0w/0592.jpg" width="320" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-size: xx-small;"&gt;&amp;nbsp; Me exhorting Adewale Oshineye (&lt;strong&gt;&lt;a class="screen-name screen-name-ade_oshineye pill" href="http://twitter.com/#%21/ade_oshineye"&gt;&lt;strong&gt;@ade_oshineye&lt;/strong&gt;&lt;/a&gt;&lt;/strong&gt;) to "Write a Test".&lt;/span&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;There were impromptu coding sessions and lessons and discussions.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_TVhFMT7oEd0/TLmCVHigtpI/AAAAAAAAJ30/5I72WjMkQf4/0202.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="213" src="http://2.bp.blogspot.com/_TVhFMT7oEd0/TLmCVHigtpI/AAAAAAAAJ30/5I72WjMkQf4/0202.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;img border="0" height="240" src="http://yfrog.com/4c1zkbj.th.jpg" style="margin-left: auto; margin-right: auto;" width="320" /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Improptu Clojure Coding Session&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://yfrog.com/4c1zkbj.th.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_TVhFMT7oEd0/TLmCB1abZvI/AAAAAAAAJ2E/QwCEpERROk4/0228.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="213" src="http://2.bp.blogspot.com/_TVhFMT7oEd0/TLmCB1abZvI/AAAAAAAAJ2E/QwCEpERROk4/0228.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_TVhFMT7oEd0/TLlQGEcxOpI/AAAAAAAAJrU/lmDTSfw00SU/0393.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="213" src="http://3.bp.blogspot.com/_TVhFMT7oEd0/TLlQGEcxOpI/AAAAAAAAJrU/lmDTSfw00SU/0393.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;Corey Haines (&lt;a class="screen-name screen-name-coreyhaines pill" href="http://twitter.com/#%21/coreyhaines"&gt;&lt;strong&gt;@coreyhaines&lt;/strong&gt;&lt;/a&gt;) gave the closing talk, and it summarized the tone perfectly.&amp;nbsp; The message, set amongst stories of cats, and cows, and redwoods, was simple: &lt;i&gt;We are makers&lt;/i&gt;.&amp;nbsp; We love what we do.&amp;nbsp; We are happiest doing what we do.&amp;nbsp; So we need to do the things that make us happiest.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_TVhFMT7oEd0/TLmEe_mwZhI/AAAAAAAAKEE/zGIIb6ReVVo/0014.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="213" src="http://4.bp.blogspot.com/_TVhFMT7oEd0/TLmEe_mwZhI/AAAAAAAAKEE/zGIIb6ReVVo/0014.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Yes, there was a &lt;i&gt;gelling&lt;/i&gt; at #scna 2010.&amp;nbsp; It was a gelling around a meme.&amp;nbsp; It was the consolidation of an idea.&amp;nbsp; It was a group of people who found themselves to be in violent agreement over a central organizing notion.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;Abraham Lincoln said it over 100 years ago.&amp;nbsp; Had he been at #scna 2010 he might have gotten up on stage after Corey's talk and sent us home with the following exhortation:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.sonofthesouth.net/slavery/abraham-lincoln/pictures/lincoln-sitting.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://www.sonofthesouth.net/slavery/abraham-lincoln/pictures/lincoln-sitting.jpg" width="237" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="color: #6aa84f; text-align: center;"&gt;&lt;i&gt;&lt;span style="font-size: x-large;"&gt;"Whatever you are, be a good one."&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="text-align: right;"&gt;&lt;span style="font-size: x-small;"&gt;(Thanks to &lt;/span&gt;&lt;span style="font-size: x-small;"&gt;Monty Ksycki for taking all those great pictures!)&lt;/span&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-2219591269934409701?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/2219591269934409701/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2010/10/be-good-one-scna-2010.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/2219591269934409701'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/2219591269934409701'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2010/10/be-good-one-scna-2010.html' title='Be a good one.  #scna 2010'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_TVhFMT7oEd0/TLmDuaQ0BdI/AAAAAAAAJ_0/_-Z5dM4ZI8I/s72-c/0072.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-5613365131790119222</id><published>2010-10-03T14:35:00.000-07:00</published><updated>2010-10-03T14:35:36.628-07:00</updated><title type='text'>The Craftsman 62, The Dark Path.</title><content type='html'>&lt;div class="BODY3"&gt;&lt;i&gt;Fri, 17 Mar 2002, 14:00&lt;/i&gt;&lt;/div&gt;&lt;div class="BODY3"&gt;&lt;br /&gt;&lt;/div&gt;"Hey Alphonse," Jerry called as I walked by, "let's do a bit of practice.&amp;nbsp; I've got a kata I'd like to show you."&lt;br /&gt;&lt;br /&gt;I felt I could use the break so I walked over and sat next to Jerry. &lt;br /&gt;&lt;br /&gt;"Sure, Jerry, what's a Kata?"&lt;br /&gt;&lt;br /&gt;Jerry rolled his eyes.&amp;nbsp; "You've never done a &lt;i&gt;kata&lt;/i&gt;?"&lt;br /&gt;&lt;br /&gt;I could feel my guard going up, but I tried to relax.&amp;nbsp; "No, can't say I have."&lt;br /&gt;&lt;br /&gt;Jerry smirked and then called over to Jasmine: "Hay Jaz, do you want to tell Alphonse what a kata is?"&lt;br /&gt;&lt;br /&gt;Jasmine's long dark hair swished playfully as she turned her head to face me.&amp;nbsp; She nailed me with those sparkling green eyes as she answered: "What, the hotshot's never done a kata?"&lt;br /&gt;&lt;br /&gt;"He says not.&amp;nbsp; Can you believe it?"&lt;br /&gt;&lt;br /&gt;"Jeez, what do they teach these kids nowadays?"&lt;br /&gt;&lt;br /&gt;"Oh come on!" I said, starting to get annoyed.&amp;nbsp; "You guys are only a couple of years older than me, school hasn't changed that much."&lt;br /&gt;&lt;br /&gt;Jasmine smiled at me, and I felt my annoyance evaporate.&amp;nbsp; That smile...&amp;nbsp; "Relax Alphonse, we're just poking fun at you.&amp;nbsp; A kata is just a simple program that you write over and over again as a way to practice.&amp;nbsp; We do them all the time.&amp;nbsp; It's part of our normal discipline."&lt;br /&gt;&lt;br /&gt;"You write the same code over and over?"&amp;nbsp; This was new to me, and it didn't make a lot of sense.&lt;br /&gt;&lt;br /&gt;Jerry nodded and explained: "Yeah.&amp;nbsp; Sometimes we'll do a kata two are three times in a row, exactly the same each time.&amp;nbsp; It's a good way to practice your hot-keys."&lt;br /&gt;&lt;br /&gt;"And sometimes," Jasmine added, "we solve them in different ways, using different techniques as a way to learn different approaches and reinforce our disciplines."&lt;br /&gt;&lt;br /&gt;"And sometimes we just do them for fun." Jerry concluded.&lt;br /&gt;&lt;br /&gt;"Which one are you going to show him?" Jasmine asked.&lt;br /&gt;&lt;br /&gt;"I was thinking about doing 'Word Wrap'."&lt;br /&gt;&lt;br /&gt;"Oh, that's a &lt;i&gt;good&lt;/i&gt; one.&amp;nbsp; You're going to like this Alphonse.&amp;nbsp; You guys have fun." And with that she turned back to her work.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;I turned to Jerry and asked: "Word Wrap?"&lt;br /&gt;&lt;br /&gt;"Yeah, it's a simple problem to understand, but it's oddly difficult to solve.&amp;nbsp; The basic premise is really simple.&amp;nbsp; You write a class called &lt;b&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Wrapper&lt;/span&gt;&lt;/b&gt;, that has a single static function named &lt;b&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;wrap&lt;/span&gt;&lt;/b&gt; that takes two arguments, a string, and a column number.&amp;nbsp; The function returns the string, but with line breaks inserted at just the right places to make sure that no line is longer than the column number.&amp;nbsp; You try to break lines at word boundaries."&lt;br /&gt;&lt;br /&gt;I thought about this for a moment and then said: "You mean like a word processor, right?&amp;nbsp; You break the line by replacing the last space in a line with a newline."&lt;br /&gt;&lt;br /&gt;Jerry nodded.&amp;nbsp; "Yeah that's the idea.&amp;nbsp; Pretty simple huh?"&lt;br /&gt;&lt;br /&gt;I shrugged.&amp;nbsp; "Sounds simple, yes."&lt;br /&gt;&lt;br /&gt;Jerry pushed the keyboard in my direction.&amp;nbsp; "OK, then why don't you start."&lt;br /&gt;&lt;br /&gt;I knew this was a trap of some kind, but I couldn't see how.&amp;nbsp; So I said: "I suppose we should begin with simple degenerate tests."&amp;nbsp; I took the keyboard and began to type. I got the first few tests passing as Jerry watched.&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/608794.js"&gt;&lt;/script&gt;&lt;br /&gt;Jerry got real interested as I wrote this.&amp;nbsp; When I got the second test working he said: "What's all that &lt;b&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@RunWith&lt;/span&gt;&lt;/b&gt; and &lt;b&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;@Suite&lt;/span&gt;&lt;/b&gt; stuff you are typing?"&amp;nbsp; &lt;br /&gt;&lt;br /&gt;I smiled.&amp;nbsp; Apparently I was about to teach Jerry something.&amp;nbsp; "Oh, yeah." I said nonchalantly.&amp;nbsp; "That's the &lt;i&gt;TestNest&lt;/i&gt; pattern.&amp;nbsp; I learned it from Justin a few days ago.&amp;nbsp; It lets you put more than one test class in a file.&amp;nbsp; Each test class can have it's own setups and teardowns."&lt;br /&gt;&lt;br /&gt;"Yeah, that's kind of slick.&amp;nbsp; But who's this Justin dude?"&lt;br /&gt;&lt;br /&gt;I pointed and counted ceiling lights.&amp;nbsp; "He works just down the hall, beneath the 8th light."?&lt;br /&gt;&lt;br /&gt;"You mean by those guys who are always walking on treadmills while they code?"&lt;br /&gt;&lt;br /&gt;I nodded and kept on coding while Jerry stared back down the hall and recounted the lights.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/608806.js"&gt;&lt;/script&gt;&lt;br /&gt;Jerry looked back just in time to see that last test pass.&amp;nbsp;&amp;nbsp; He looked over the code and nodded.&amp;nbsp; "Yes, that's just about exactly how I solved it the first time.&amp;nbsp; That &lt;b&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;replaceAll&lt;/span&gt;&lt;/b&gt; is a bit of a hack isn't&amp;nbsp; it."&lt;br /&gt;&lt;br /&gt;"Yes, but it gets the test to pass.&amp;nbsp; 'First make it work, then make it right.'"&lt;br /&gt;&lt;br /&gt;Jerry nodded.&lt;br /&gt;&lt;br /&gt;"Anyway, it's pretty straightforward so far." I said.&amp;nbsp; And so I went on to write the next test.&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/608811.js"&gt;&lt;/script&gt;&lt;br /&gt;Jerry nodded sagely.&amp;nbsp; "Yes, that's the obvious next test."&lt;br /&gt;&lt;br /&gt;"Yes, and with the obvious failure." I agreed.&amp;nbsp; So then I looked back at the code.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;I stared at it for a long time.&amp;nbsp; But there did not seem to be any simple thing that I could do to make the test pass.&lt;br /&gt;&lt;br /&gt;After a few minutes, Jerry said: "What's the matter Alphonse?&amp;nbsp; Stuck?"&lt;br /&gt;&lt;br /&gt;"No, this should be simple.&amp;nbsp; I just..."&amp;nbsp; In frustration I took the keyboard and began to type.&amp;nbsp; I typed for quite a while, adding and erasing code.&amp;nbsp; Jerry nodded knowingly, and sometimes grunted.&amp;nbsp; After about five minutes Jerry stopped me.&amp;nbsp; The code looked like this:&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/608834.js"&gt; &lt;/script&gt;&lt;br /&gt;"Are you sure you're on the right track, Alphonse?"&lt;br /&gt;&lt;br /&gt;I looked at the code and realized that I had been coding blindly.&amp;nbsp; I ran the tests in desperation, but they just hung in an infinite loop.&amp;nbsp; I could &lt;i&gt;kind of feel&lt;/i&gt; what needed to be done, but it wasn't at all clear how I should proceed.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;"Give me another shot at this." I said, as I erased all the code and started over.&amp;nbsp; Jerry just smiled and watched as I flailed around for another five minutes or so.&amp;nbsp; Finally, with lots of tests failing he stopped me again.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/608842.js"&gt; &lt;/script&gt;&lt;br /&gt;"What are you doing wrong, Alphonse?"&lt;br /&gt;&lt;br /&gt;I stared at the screen for a minute.  Then I said: "I &lt;i&gt;know&lt;/i&gt; I can get this working,&amp;nbsp; give me another shot."&lt;br /&gt;&lt;br /&gt;"Alphonse, I &lt;i&gt;know&lt;/i&gt; you can get it working too; but that's not the point. Stop for a minute and tell me what you are doing wrong."&lt;br /&gt;&lt;br /&gt;I could hear Jasmine stifling a giggle.&amp;nbsp; I looked over at her, but she didn't meet my eye.&amp;nbsp; Then I took my fingers off the keyboard and hung my head.&amp;nbsp; "I can't seem to get this test to pass without writing a lot of untested code." I said.&lt;br /&gt;&lt;br /&gt;"That's true." Said Jerry, but it's not quite the answer I was looking for.&amp;nbsp; You were doing something wrong.&amp;nbsp; Something &lt;i&gt;really&lt;/i&gt; wrong.&amp;nbsp; Do you know what it was?&lt;br /&gt;&lt;br /&gt;I thought about it for awhile.&amp;nbsp; I had been trying to figure out the algorithm.&amp;nbsp; I had tried lots of different approaches.&amp;nbsp; But all my guesses turned out wrong.&amp;nbsp; --&amp;nbsp;&amp;nbsp; Oh!&lt;br /&gt;&lt;br /&gt;I looked Jerry square in the eye and said:&amp;nbsp; "I was guessing."&lt;br /&gt;&lt;br /&gt;"Right!" Jerry beamed.&amp;nbsp; "And why were you guessing?"&lt;br /&gt;&lt;br /&gt;"Because the test was failing and I couldn't figure out how to get it to pass."&lt;br /&gt;&lt;br /&gt;Now Jerry narrowed his gaze, almost like he was looking &lt;i&gt;through&lt;/i&gt; me.&amp;nbsp; "And what does that tell you?"&lt;br /&gt;&lt;br /&gt;"That the problem is hard?"&amp;nbsp; I guessed.&lt;br /&gt;&lt;br /&gt;"No, Alphonse, the problem is &lt;i&gt;not&lt;/i&gt; hard.&amp;nbsp; When you see the solution, you're going to be very angry at yourself.&amp;nbsp; The reason you could not figure out how to pass that test, Alphonse, is that you were trying to pass the &lt;i&gt;wrong&lt;/i&gt; test."&lt;br /&gt;&lt;br /&gt;I looked at the tests again.&amp;nbsp; They seemed perfectly logical.&amp;nbsp; So I asked Jerry: "How could these be the wrong tests?"&lt;br /&gt;&lt;br /&gt;Jerry smiled with a grin that rivaled Jasper's.&amp;nbsp; "They are the wrong tests, Alphonse, because you could not figure out how to pass them."&lt;br /&gt;&lt;br /&gt;I gave Jerry a stern look.&amp;nbsp; "You're being circular, Jerry."&lt;br /&gt;&lt;br /&gt;"Perhaps I am.&amp;nbsp; Look at it this way.&amp;nbsp; The test you are trying to pass is forcing you to solve a very large part of the problem.&amp;nbsp; Indeed, it might just be the &lt;i&gt;whole&lt;/i&gt; problem.&amp;nbsp; In any case, the bite you are taking is too big."&lt;br /&gt;&lt;br /&gt;"Yeah, but..." &lt;br /&gt;&lt;br /&gt;Jerry stopped me and said: "Did you ever read &lt;i&gt;The Moon is a Harsh Mistress&lt;/i&gt; Alphonse?"&lt;br /&gt;&lt;br /&gt;"Uh... Heinlein, wasn't it?&amp;nbsp; Yes, I read it a few years back.&amp;nbsp; It was a great story."&lt;br /&gt;&lt;br /&gt;"Indeed it was.&amp;nbsp; Do you remember this quotation?"&lt;br /&gt;&lt;blockquote style="color: purple;"&gt;&lt;div style="font-family: inherit;"&gt;&lt;span style="font-size: small;"&gt;&lt;span lang="en-AM"&gt;"[W]hen faced with a problem you do not understand, do any part of it you do understand, then look at it again."&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;"As a matter of fact, I do.&amp;nbsp; I thought it was very profound."&lt;br /&gt;&lt;br /&gt;"OK then Alphonse, apply that here.&amp;nbsp; Find some part of this problem that you &lt;i&gt;do&lt;/i&gt; understand."&lt;br /&gt;&lt;br /&gt;"I understand the problem..."&lt;br /&gt;&lt;br /&gt;"No,&amp;nbsp; you &lt;i&gt;think&lt;/i&gt; you understand the problem, but clearly you don't.&amp;nbsp; If you understood it, you'd be able to solve it.&amp;nbsp; Find some simpler tests to pass."&lt;br /&gt;&lt;br /&gt;I thought about this for a few seconds.&amp;nbsp; What was so hard about this problem?&amp;nbsp; The thing I'd been struggling with was how to deal with breaking the lines at spaces?&amp;nbsp; Each of my "solutions" was tangled up with hunting for just the right space to replace with a line end.&lt;br /&gt;&lt;br /&gt;I looked at Jerry and said: "What if I solved the part of this problem that did not deal with spaces?&amp;nbsp; Lines that have no spaces only need to be broken once they've hit the column limit."&lt;br /&gt;&lt;br /&gt;Jerry pointed at the keyboard, and I started again.&amp;nbsp; I wrote the same degenerate tests.&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/608884.js"&gt; &lt;/script&gt;&lt;br /&gt;But then I changed tack and wrote a test that wrapped a line without spaces.  That test was trivially easy to pass.&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/608887.js"&gt; &lt;/script&gt;&lt;br /&gt;The next test was pretty obvious.  It should continue to wrap a string without spaces, creating lines that are no longer than the column limit.  &lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/608891.js"&gt; &lt;/script&gt;&lt;br /&gt;Jerry looked at the test and nodded.  "How will you solve that, Alphonse?"&lt;br /&gt;&lt;br /&gt;"I just need to put a loop into the wrap function." I said.&lt;br /&gt;&lt;br /&gt;"I think there's an easier way." He said.  &lt;br /&gt;&lt;br /&gt;I looked at the code for a bit, and then said: "Oh! Sure, I could recurse."&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/608894.js"&gt; &lt;/script&gt;&lt;br /&gt;The tests passed, and Jerry nodded approvingly.  "That looks like a framework you could build upon.  What's next?"&lt;br /&gt;&lt;br /&gt;"Now that I can wrap lines &lt;i&gt;without&lt;/i&gt; spaces, it ought to be easier to wrap lines &lt;i&gt;with&lt;/i&gt; spaces!"&lt;br /&gt;&lt;br /&gt;"Give it a shot." He said.&amp;nbsp; So I wrote the simplest test I could.&amp;nbsp; A space right at the column limit. &lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/608897.js"&gt; &lt;/script&gt;&lt;br /&gt;"Do you remember how you made that test pass last time?" Jerry asked.&lt;br /&gt;&lt;br /&gt;"Yeah." I grimaced.  "I use the &lt;b&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;replaceAll&lt;/span&gt;&lt;/b&gt; hack."&lt;br /&gt;&lt;br /&gt;"Is that how you're going to solve it now?"&lt;br /&gt;&lt;br /&gt;I looked at the code, and the answer was obvious.&amp;nbsp; "Of course not!" I exclaimed. "All I need to do is check to see if the character at the column limit is a space!"&amp;nbsp; and I wrote the following code.&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/608903.js"&gt; &lt;/script&gt;&lt;br /&gt;"Why'd you put that wrap call in there?"&amp;nbsp; Jerry asked. "You're getting a little ahead of yourself, aren't you?"&lt;br /&gt;&lt;br /&gt;"I guess, but it's kind of &lt;i&gt;obvious&lt;/i&gt; that it belongs there.&amp;nbsp; Just look at the symmetry!"&lt;br /&gt;&lt;br /&gt;"I agree." Jerry said smiling.&amp;nbsp; "Continue on."&lt;br /&gt;&lt;br /&gt;The next test was just as obvious.&amp;nbsp; The space should be &lt;i&gt;before&lt;/i&gt; the column limit.&amp;nbsp; So I typed the following:&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/608912.js"&gt; &lt;/script&gt;&lt;br /&gt;"Passing this one is going to be tricky." I said under my breath.&lt;br /&gt;&lt;br /&gt;"Is it?" Jerry queried.&lt;br /&gt;&lt;br /&gt;I looked again, and it hit me.&amp;nbsp; "Oh, no, it's just a small change!"&amp;nbsp; And I typed the following.&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/608918.js"&gt; &lt;/script&gt;&lt;br /&gt;The tests passed, and I was getting excited.&amp;nbsp; "This is so strange, the whole algorithm is just falling into place!"&lt;br /&gt;&lt;br /&gt;"When you choose the right tests, Alphonse, they usually do."&lt;br /&gt;&lt;br /&gt;"OK, so now let's make the column boundary really small so that it has to chop the string up into lots of little lines."&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/608922.js"&gt; &lt;/script&gt;&lt;br /&gt;"That one passes right away!" I said.&amp;nbsp; Wow, I think we're done.&lt;br /&gt;&lt;br /&gt;"Not quite." Jerry said.&amp;nbsp; "There's another case."&lt;br /&gt;&lt;br /&gt;I studied the tests.&amp;nbsp; "Oh, there's the case where the character &lt;i&gt;after&lt;/i&gt; the column limit is a space."  I wrote the tests, and it was trivial to pass.&lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/608930.js"&gt; &lt;/script&gt;&lt;br /&gt;Jerry smiled as the tests passed.  "That's the algorithm all right. But I bet you could clean this up a bit."&lt;br /&gt;&lt;br /&gt;"Yeah, there &lt;i&gt;is&lt;/i&gt; a lot of duplication in there."  So I cleaned up my work with the following result.  &lt;br /&gt;&lt;br /&gt;&lt;script src="http://gist.github.com/608933.js"&gt; &lt;/script&gt;&lt;br /&gt;I looked at the code in some astonishment.  This really was a very simple algorithm!  Why couldn't I see it before?&lt;br /&gt;&lt;br /&gt;"You were right." I said to Jerry.  "Now that I see this algorithm for what it is, it's kind of obvious.  I guess choosing the right tests is pretty important."&lt;br /&gt;&lt;br /&gt;"It's not so much choosing the &lt;i&gt;right&lt;/i&gt; tests, Alphonse; it's about realizing that you are trying to solve the &lt;i&gt;wrong&lt;/i&gt; test."&lt;br /&gt;&lt;br /&gt;"Yeah, the next time I get stuck like that, and start guessing and flailing, I'm going to re-evaluate the tests.&amp;nbsp; Perhaps there'll be simpler tests that will give me a clue about the real solution."&lt;br /&gt;&lt;br /&gt;And then I stopped myself and asked: "Is that true, Jerry? Is there always a simpler test that'll get me unstuck?"&lt;br /&gt;&lt;br /&gt;Jerry was about to answer when a spitwad hit him in the side of the face.&amp;nbsp; Jasmine was laughing and running down the hall.&amp;nbsp; Jerry lept out of his seat to chase after her.&lt;br /&gt;&lt;br /&gt;I just shook my head and wondered.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-5613365131790119222?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/5613365131790119222/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2010/10/craftsman-62-dark-path.html#comment-form' title='17 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/5613365131790119222'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/5613365131790119222'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2010/10/craftsman-62-dark-path.html' title='The Craftsman 62, The Dark Path.'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>17</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-3146268592848129826</id><published>2010-09-24T04:50:00.000-07:00</published><updated>2010-09-24T04:50:07.561-07:00</updated><title type='text'>The Hacker, The Novice, The Artist, and The Craftsman.</title><content type='html'>In my last blog&amp;nbsp; "&lt;a href="http://thecleancoder.blogspot.com/2010/09/too-small-to-refactor.html"&gt;Too Small to Refactor&lt;/a&gt;", I made the statement:&lt;br /&gt;&lt;blockquote&gt;"Clean code &lt;i&gt;has always been about money&lt;/i&gt;, and has never been about art."&amp;nbsp;&amp;nbsp;&lt;/blockquote&gt;Apparently this took a few people by surprise.&amp;nbsp; One person comented:&lt;br /&gt;&lt;blockquote&gt;"...I thought we were talking about craft, and the cost-cutting as a subproduct..."&lt;/blockquote&gt;So what is the difference between a craftsman and an artist?&amp;nbsp; And just to add some spice, how do they differ from a hacker and a novice?&lt;br /&gt;&lt;br /&gt;I realize that I am making a Myers-Briggs type error.&amp;nbsp; People cannot truly be classified using binary attributes.&amp;nbsp; A person classified by MBTI as an introvert, certainly has some extrovert characteristics.&amp;nbsp; By the same token a programmer who shows some attributes of a hacker, probably also shows some attributes of a craftsman.&lt;br /&gt;&lt;br /&gt;Still, I think the definitions of these terms can be useful as a way to classify programmer behaviors.&lt;br /&gt;&lt;br /&gt;What is the difference between the Hacker, the Novice, the Artist, and the Craftsman?&amp;nbsp; It's all about their personal definition of "&lt;i&gt;Done&lt;/i&gt;". &lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;&lt;b&gt;The Artist&lt;/b&gt; is done when the structure and behavior of the artist's code has achieved perfection in the artist's eyes.&amp;nbsp; There is no consideration of money spent, or money to be earned.&amp;nbsp; The artist does not care about ROI.&amp;nbsp; The artist does not care how long it takes.&amp;nbsp; The artist cares &lt;i&gt;only&lt;/i&gt; about the final result.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;An artist will spend hours, days, even weeks, on a single line of code.&amp;nbsp; An artist will throw away whole functions and modules because they somehow don't feel right.&amp;nbsp; An artist polishes, and polishes, and polishes in pursuit of some elusive goal of perfection. &amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;&lt;b&gt;The Hacker&lt;/b&gt; is done when the &lt;i&gt;behavior&lt;/i&gt; of the code achieves some personal goal.&amp;nbsp; The Hacker is not concerned with ROI.&amp;nbsp; The Hacker does not care about the code at all.&amp;nbsp; The Hacker does not care about how much, or how little, is spent creating the code.&amp;nbsp; The Hacker does not care if anyone else ever uses the code.&amp;nbsp; The Hacker only cares about making it work -- once.&amp;nbsp; After that, the Hacker loses interest.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;&lt;b&gt;The Novice&lt;/b&gt; is done as soon as the code works "well enough".&amp;nbsp; The Novice strives to minimize initial coding time. &amp;nbsp; The Novice is not concerned about ROI.&amp;nbsp; The future cost of the code is of no concern to the Novice.&amp;nbsp; Nor does the Novice care about the number of hidden and/or subtle defects left in the code.&amp;nbsp; The Novice simply wants to get to the next task as soon as possible.&amp;nbsp; The Novice is driven by schedule; or rather, the Novice is driven by pleasing managers who are driven by schedule.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;&lt;b&gt;The Craftsman&lt;/b&gt; is done when ROI has been maximized.&amp;nbsp; The Craftsman strives to be a good steward of the monies being spent.&amp;nbsp; The Craftsman want to make sure that every dollar goes as far as it can, and earns as much as it can in return.&amp;nbsp; Therefore the Craftsman makes sure the code works, and can be kept working with minimum extra cost.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;The Craftsman understands that most defects in behavior and structure will be very expensive to repair later and very inexpensive to eliminate now.&amp;nbsp; So the Craftsman pushes towards a very clean implementation.&amp;nbsp; But the Craftsman also recognizes that some rare defects in behavior and structure are going to cost more to eliminate than to tolerate; and so the Craftsman uses judgment, acquired over years, to maximize ROI.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-3146268592848129826?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/3146268592848129826/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2010/09/hacker-novice-artist-and-craftsman.html#comment-form' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/3146268592848129826'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/3146268592848129826'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2010/09/hacker-novice-artist-and-craftsman.html' title='The Hacker, The Novice, The Artist, and The Craftsman.'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-6747170558088703282</id><published>2010-09-18T06:56:00.000-07:00</published><updated>2010-09-18T06:56:59.968-07:00</updated><title type='text'>The Uncertainty Principle, and the Quantum Discontinuity.</title><content type='html'>What is the uncertainty principle?&amp;nbsp; Some people think of it as the "Observer Effect", the fact that any time you measure an object, you change something about it.&amp;nbsp; For example, to see where an object is you have to bounce photons of light off of it, and those photons change the object.&lt;br /&gt;&lt;br /&gt;But that's not what the uncertainty principle really is.&amp;nbsp; The Heisenberg Uncertainty Principle (HUP) is defined as follows:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="border: medium none white;"&gt;&lt;a href="http://2.bp.blogspot.com/_McaZb7v3tS4/TJS8rz1ky8I/AAAAAAAAAAk/Kc68jRw10kg/s1600/hup.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/_McaZb7v3tS4/TJS8rz1ky8I/AAAAAAAAAAk/Kc68jRw10kg/s320/hup.gif" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;That is, the uncertainty in position times the uncertainty in momentum is greater than or equal to Plank's constant over two.&amp;nbsp; Plank's constant being &lt;span style="white-space: nowrap;"&gt;1.054&lt;span style="margin-left: 0.25em;"&gt;5&lt;/span&gt;71&lt;span style="margin-left: 0.25em;"&gt;6&lt;/span&gt;28(53)&lt;span style="margin-left: 0.25em; margin-right: 0.15em; white-space: nowrap;"&gt;×&lt;/span&gt;10&lt;sup&gt;−34&lt;/sup&gt;&lt;/span&gt; &lt;a href="http://en.wikipedia.org/wiki/Joule" title="Joule"&gt;J&lt;/a&gt;·&lt;a href="http://en.wikipedia.org/wiki/Second" title="Second"&gt;s&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;What this means is that you cannot know &lt;i&gt;both&lt;/i&gt; the position and momentum of something.&amp;nbsp; To the extent you know one, the other is uncertain.&amp;nbsp; Of course Plank's constant is a very small number, so most of the time the uncertainty of our knowledge does not matter.&amp;nbsp; It only becomes significant over very short distances and very small changes in momentum.&lt;br /&gt;&lt;br /&gt;To understand where this uncertainty comes from, we need to understand that all matter and all energy is composed of waves.&amp;nbsp; I know this is difficult to envision, but take it on faith for the moment because once you accept this fact the uncertainty principle suddenly makes a great deal of sense.&lt;br /&gt;&lt;br /&gt;Imagine a circular pond of very still water.&amp;nbsp; The surface is like a mirror in all directions.&amp;nbsp; Hold a stick in your hand, and insert the tip into the water.&amp;nbsp; Move the stick up and down at a fixed frequency.&amp;nbsp; Waves will ripple away from the stick in all directions, completely filling the pond.&amp;nbsp; The waves have no certain position.&amp;nbsp; They are everywhere on the surface of the lake.&amp;nbsp; However, because the frequency is fixed, the waves have a very well defined energy (momentum).&amp;nbsp; That's the first half of the HUP, we know the energy but we cannot determine any position.&lt;br /&gt;&lt;br /&gt;Now change the way you move the stick.&amp;nbsp; Shake it up and down randomly -- perfectly randomly!&amp;nbsp; Make sure you incorporate &lt;i&gt;every&lt;/i&gt; frequency into your motion.&amp;nbsp; The surface of the lake will return to it's mirror sheen because all frequencies will integrate out. You will know where all the energy is, it's in the stick, but you won't know how much energy there is because it's all random.&amp;nbsp; And that's the second half of the HUP.&amp;nbsp; You know the position of the energy, but the quantity is purely random.&lt;br /&gt;&lt;br /&gt;That's how photons work.&amp;nbsp; Photons are "particles" of light.&amp;nbsp; But does light really move as a spray of particles?&amp;nbsp; It sometimes seems to.&amp;nbsp; However, it also seems to move in waves like the waves of a pond.&lt;br /&gt;&lt;br /&gt;Plank showed that the energy of a photon is equal to Plank's constant times the wavelength of the photon's frequency: &lt;br /&gt;&lt;dl&gt;&lt;dd&gt;&lt;/dd&gt;&lt;dd&gt;&lt;/dd&gt;&lt;dd&gt;&lt;/dd&gt;&lt;dd&gt;&lt;/dd&gt;&lt;dd&gt;&lt;div class="separator"&gt;&lt;a href="http://1.bp.blogspot.com/_McaZb7v3tS4/TJS9rZhh8fI/AAAAAAAAAAs/86usXCIqT3E/s1600/plank.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_McaZb7v3tS4/TJS9rZhh8fI/AAAAAAAAAAs/86usXCIqT3E/s320/plank.gif" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/dd&gt;&lt;/dl&gt;What this means is that we cannot measure energies that are not integral multiples of this quantity.&amp;nbsp; Indeed, no interaction between two particles can take place unless there is an exchange of an integral multiple of that quantity.&amp;nbsp; For example, an interaction that would require half that energy simply could not occur.&lt;br /&gt;&lt;br /&gt;So now, imagine a light source that emits light at a fixed frequency at a rate exactly equal to one photon per second.&amp;nbsp; Is this light source emitting one photon per second?&amp;nbsp; Or is it filling the space around it with light waves.&amp;nbsp; The answer is both.&amp;nbsp; The space around the light source is filled with a field of waves.&amp;nbsp; However, those waves cannot interact with any other matter more than once per second.&amp;nbsp; And the position of that interaction is, by the Uncertainty Principle, random.&amp;nbsp; So if you set up a screen around the light source, you'd see tiny little sparks of light in random positions at roughly one second intervals.&lt;br /&gt;&lt;br /&gt;The waves are all there, filling space like the waves on the pond, but the energy of those waves can only be deposited in fixed quantities, and the position of each one of those deposits is random.&amp;nbsp;&amp;nbsp; If you put such a light source in the center of a room, it would "illuminate" that room.&amp;nbsp; However, your eyes would only register the photons that managed to randomly deposit their energy on your retina via a pathway that passed through your pupil after reflecting off the objects in the room.&amp;nbsp; And that would happen at a rate much less than once per second because most of the photons emitted by the light source would deposit their energy somewhere other than in your eye.&lt;br /&gt;&lt;br /&gt;What is bouncing off the furniture in the room?&amp;nbsp; Photons?&amp;nbsp; No, it is the waves that are reflecting off the objects in the room and that are passing through your pupil, refracting through your cornea and lense, and "striking" your retina.&amp;nbsp; And then those waves deposit their energies as photons at uncertain locations.  The waves determine the &lt;i&gt;probability&lt;/i&gt; that the energy will be deposited at one uncertain place or another.&amp;nbsp; So in some very real sense the waves are waves of probability.&amp;nbsp; If an area of the room is in shadow, no waves will be present in that part of the room, and so the probability that the waves will deposit their energy as photons in that area is zero.&lt;br /&gt;&lt;br /&gt;If you put a camera in the room and left the shutter open for a very long time, the camera would record a perfectly normal image of an illuminated room.&amp;nbsp; Over time the field of waves would deposit some of it's energy as photons in the camera's receptor.&amp;nbsp; The probability information carried by those waves would cause those photons to build up an image of the room.&lt;br /&gt;&lt;br /&gt;Indeed, that's what's going on right now as you are looking at these words.&amp;nbsp; The field of waves leaving your computer screen carries probability information to your retina, causing photon's to be randomly deposited there.&amp;nbsp; It's just that the flux of photons is so huge, that we do not notice their randomness.&lt;br /&gt;&lt;br /&gt;What does this have to do with software?&lt;br /&gt;&lt;br /&gt;Nothing directly.&amp;nbsp;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-6747170558088703282?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/6747170558088703282/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2010/09/uncertainty-principle-and-quantum.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/6747170558088703282'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/6747170558088703282'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2010/09/uncertainty-principle-and-quantum.html' title='The Uncertainty Principle, and the Quantum Discontinuity.'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_McaZb7v3tS4/TJS8rz1ky8I/AAAAAAAAAAk/Kc68jRw10kg/s72-c/hup.gif' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-759905827869301338</id><published>2010-09-17T10:32:00.000-07:00</published><updated>2010-09-17T10:32:52.578-07:00</updated><title type='text'>Too Small to Refactor?</title><content type='html'>In John MacIntyre's &lt;a href="http://whileicompile.wordpress.com/2010/09/14/what-is-too-simple-and-small-to-refactor-as-clean-code/"&gt;second blog&lt;/a&gt; about Clean Code he presented a very simple little payroll calculator, refactored it, and then asked whether it was truly worth refactoring in an ROI sense.&amp;nbsp; His conclusion was that he would probably &lt;i&gt;not &lt;/i&gt;refactor it in a "real" project, but probably &lt;i&gt;would&lt;/i&gt; refactor it if it were his own project. His reasoning was that the refactoring was worth doing for artistic reasons, but not for financial reasons.&lt;br /&gt;&lt;br /&gt;This argument suggests that Clean Code is about art rather than money.&amp;nbsp; This is a fundamental flaw in logic.&amp;nbsp; Clean code &lt;i&gt;has always been about money&lt;/i&gt;, and has never been about art. Craftsmen keep their code clean because they know that clean code costs less.&amp;nbsp; They know that cleaning code has a one-time cost, but that leaving it unclean has a long-term repeating chronic cost that increases with time.&amp;nbsp; Craftsmen understand that the best way to reduce cost and increase ROI is to keep their code very clean.&lt;br /&gt;&lt;br /&gt;Here was the code that John began with (I've translated it from C# to Java for my own sanity.) &lt;script src="http://gist.github.com/584443.js"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;If we are going to refactor this, we're going to need some tests.&amp;nbsp; So the first thing I did was to write enough tests to cover the code.&amp;nbsp; &lt;br /&gt;&lt;script src="http://gist.github.com/584490.js?file=PayCalculatorTest.java"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;The algorithm was a little bit wordy, so I shorted it up a bit and made the two sections of the if statement independent of each other.&lt;br /&gt;&lt;script src="http://gist.github.com/584517.js?file=PayCalculator.java"&gt;&lt;/script&gt;  &lt;br /&gt;&lt;br /&gt;Next I got rid of that boolean argument.  Boolean arguments are always troublesome beasts. Some poor schmuck is bound to call it with the wrong value, and all the poor people reading this code will wonder whether they should look up the argument to see what it means.  Boolean arguments loudly declare that this function does two things instead of one thing.  &lt;script src="http://gist.github.com/584547.js"&gt; &lt;/script&gt;&lt;br /&gt;&lt;br /&gt;This had a profound effect on the tests.  The tests look almost like they are using two derivatives rather than two instances of the same class.  Indeed, we should probably continue pushing the refactoring in that direction.  Creating two derivatives is simple enough.  First I changed the tests to create instances of the derivatives, and then I wrote the derivaties themselves.  &lt;script src="http://gist.github.com/584555.js"&gt; &lt;/script&gt;&lt;br /&gt;&lt;br /&gt;That sets things up nicely.  Now I just need to push the calculate method down into the two derivatives.&lt;script src="http://gist.github.com/584566.js"&gt; &lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Nice!  Now all I need to do is refactor the two derivatives. &lt;script src="http://gist.github.com/584581.js"&gt; &lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Now that's nice!&amp;nbsp; Nearly the same number of lines of code as the original,&amp;nbsp; and &lt;i&gt;so&lt;/i&gt; much cleaner!  But was it worth it? &lt;br /&gt;&lt;br /&gt;Of course it was!&amp;nbsp; The two business rules have completely decoupled from each other.&amp;nbsp; They are in totally different files, and know nothing about each other.&amp;nbsp; If someone adds a new kind of pay calculation, like a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;SalariedCalculator&lt;/span&gt;, none of these files will need to change!&amp;nbsp; (We call that the Open Closed Principle by the way.)&amp;nbsp; Think about what we'd have had to do with the old implementation!&amp;nbsp; Boolean's don't split into three very well.&lt;br /&gt;&lt;br /&gt;Yes, this was worth it.&amp;nbsp; It was worth it because we've all been impeded by bad code before.&amp;nbsp; We all know that bad code slows down everyone who reads it, every time they read it!&amp;nbsp; Bad code is like Herpes.&amp;nbsp; It's the gift that keeps on giving.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-759905827869301338?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/759905827869301338/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2010/09/too-small-to-refactor.html#comment-form' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/759905827869301338'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/759905827869301338'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2010/09/too-small-to-refactor.html' title='Too Small to Refactor?'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-2292924539589399008</id><published>2010-09-09T17:18:00.000-07:00</published><updated>2010-09-09T17:18:31.950-07:00</updated><title type='text'>John MacIntyre's Clean Code Experience #1.</title><content type='html'>John MacIntyre has written a lovely &lt;a href="http://whileicompile.wordpress.com/2010/08/24/my-clean-code-experience-no-1/"&gt;blog&lt;/a&gt; about his first experience with "Clean Code".&amp;nbsp;&amp;nbsp; The change in the structure of his code, and in his attitude about code, is dramatic.&amp;nbsp; As an author, there is little that can be more gratifying and inspiring than to see this kind of direct result.&amp;nbsp; So, thank you John!&amp;nbsp; &lt;br /&gt;&lt;br /&gt;On twitter a few weeks ago, John suggested that I review the code that he wrote.&amp;nbsp; I was happy to agree to do this.&amp;nbsp; There's little I like better than reading other people's code. I learn much more from other people's code than I learn by writing my own.&amp;nbsp; So again, thank you John for letting me pick a few nits.&lt;br /&gt;&lt;br /&gt;The first thing I did was to download the zip file from his blog and load up all the source files in to TextMate.&amp;nbsp; I didn't want to compile or run anything just yet, I simply wanted to look at the difference between the two batches of code.&amp;nbsp; John had organized it very nicely into two folders named, appropriately enough, &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;DirtyDal&lt;/span&gt; and &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;CleanDal&lt;/span&gt;.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;The &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;DirtyDal&lt;/span&gt; consisted of a single 300 line class that implemented all the CRUD methods for a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Comment&lt;/span&gt; table.&amp;nbsp;&amp;nbsp; The code was simple enough, but was laced with lots of distracting comments and was laden with considerable duplication.&amp;nbsp; It was the typical kind of CRUD class that built up SQL commands from arguments, executed those commands, and then extracted the results.&amp;nbsp; Code like this often has a repeating structure since every command follows the same basic form.&amp;nbsp; 1. Construct SQL.&amp;nbsp; 2. Execute SQL.&amp;nbsp; 3. Process results.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;The &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;CleanDal&lt;/span&gt; consisted of many very small classes arranged in an pleasant inheritance hierarchy that eliminated much of the duplication.&amp;nbsp; The base classes provided the basic framework for a SQL operation, and the derivatives implemented them simply and directly.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;So my overall impression was that this was a significant improvement in structure and cleanliness.&amp;nbsp; John made the point in his blog that this new structure took more lines of code, and was more complicated.&amp;nbsp; While it's true that more lines are used, most of those lines are boilerplate required by the statically typed nature of C#.&amp;nbsp; There are fewer actual executable lines, and that's the important measure.&amp;nbsp; As to whether the new code is more complicated, it certainly has a more complex structure.&amp;nbsp; But the code within that structure is much simpler.&amp;nbsp; The structure is visible, and it's contents are simple.&amp;nbsp; To me, that's a rather significant improvement.&lt;br /&gt;&lt;br /&gt;So then I loaded the solution into VS.&amp;nbsp; Everything came up nicely, and the project built without trouble.&amp;nbsp; Good!&amp;nbsp; I hate compile and path errors in downloaded software.&lt;br /&gt;&lt;br /&gt;Next, I ran the tests.&amp;nbsp; John was good enough to include tests!&amp;nbsp; Indeed, it was from reading those tests that I learned how he intended his inheritance hierarchy to work.&amp;nbsp; So, well done John!&amp;nbsp;&lt;br /&gt;&lt;br /&gt;Unfortunately the tests did not run.&amp;nbsp; They failed because they tried to connect to a database that did not exist on my computer.&amp;nbsp; Why do I need to create a dabase just to run these tests?&amp;nbsp; The database is irrelevant to the tests!&lt;br /&gt;&lt;br /&gt;"Wait!" you say.&amp;nbsp; "This is a CRUD application, how could the database be irrelevant to the tests?"&amp;nbsp; Simple.&amp;nbsp; I &lt;i&gt;believe&lt;/i&gt; the database works, so there's no need to test &lt;i&gt;it&lt;/i&gt;.&amp;nbsp; All I care about is the code that John wrote. I just want to be sure that the SQL commands care created properly, and that the returned data is processed appropriately.&amp;nbsp;&amp;nbsp; The database is a complication that I'd rather not deal with.&lt;br /&gt;&lt;br /&gt;My next complaint is that John did not use one of the standard test frameworks, like NUnit.&amp;nbsp; Instead he just wrote his own little main program that called his functions and made sure they worked.&amp;nbsp; Worse, those tests were written at a fairly high level.&amp;nbsp; For example, he tested that &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;InsertComment&lt;/span&gt; worked by calling &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;InsertComment&lt;/span&gt;, and then by calling &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;SelectComment&lt;/span&gt; to make sure the data was inserted.&amp;nbsp; For my money this test touches way too much code!&amp;nbsp; It does not prove to me that the SQL is generated properly in each situation, and I am not convinced that complementary bugs in &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Insert&lt;/span&gt; and &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Select&lt;/span&gt; aren't canceling each other out and generating false positives. &lt;br /&gt;&lt;br /&gt;To fix these tests I tried to create a mock derivative of &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;SqlConnection&lt;/span&gt; but, of course, it was sealed &lt;i&gt;(grumble)&lt;/i&gt;.&amp;nbsp; I thought about wrapping &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;SqlConnection&lt;/span&gt; in an &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;IConnection&lt;/span&gt; interface, but unfortunately &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;SqlConnection&lt;/span&gt; returns &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;SqlCommand&lt;/span&gt; which returns &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;SqlParameter&lt;/span&gt;, all of which are sealed (&lt;i&gt;double grumble!&lt;/i&gt;)&lt;br /&gt;&lt;br /&gt;I thought about downloading one of the mocking tools, like TypeMock, but my time is limitted, and I'm not an expert .NET programmer. &amp;nbsp; &lt;br /&gt;&lt;br /&gt;So rather than fiddle around with trying to get a mocking framework or a database up and running &lt;i&gt;(triple grumble)&lt;/i&gt; I decided just to refactor without running the tests. &lt;i&gt;(Gasp, Horror)&lt;/i&gt;&amp;nbsp; What can you do when the test environment isn't supplied...&lt;br /&gt;&lt;br /&gt;So I went back to the test and started to read.&amp;nbsp; The first thing it does is create a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;CommentData&lt;/span&gt; object, so I looked at the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;CommentData&lt;/span&gt; class.&amp;nbsp; Here's a small snippet.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp; public class CommentData {&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;summary&amp;gt;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// Id of the comment&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; /// &amp;lt;/summary&amp;gt;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public Int32? CommentId { get; set; }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I really hate these kinds of comments.&amp;nbsp; The comment tells you nothing more than the property name, so why is it there?&amp;nbsp; So I deleted it and it's ilk.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;To be fair to Jonathan, this class is not in his "clean" folder.&amp;nbsp; It's one of the classes he didn't refactor.&amp;nbsp; Still, I think the point is an important one so I chose to show it anyway.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Next is this lovely function:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public bool Equals(CommentData obj) {&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (!CommentId.Equals(obj.CommentId)) return false;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (!Comment.Equals(obj.Comment)) return false;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (!CommentorId.Equals(obj.CommentorId)) return false;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return true;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Wouldn't this read better if it was written like this:&lt;br /&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public bool Equals(CommentData obj) {&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return CommentId == obj.CommentId &amp;amp;&amp;amp;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Comment.Equals(obj.Comment) &amp;amp;&amp;amp;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; CommentorId == obj.CommentorId;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;And doesn't this need a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;null&lt;/span&gt; check for the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Comment&lt;/span&gt; property?&lt;br /&gt;&lt;br /&gt;Next the test calls the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;static Execute&lt;/span&gt; method of &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;CommentInsertCommand&lt;/span&gt;.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp; public static void Execute(CommentData commentData,&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int userId,&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SqlConnection cn)&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp; {&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ThrowExceptionIfExecuteMethodCommentParameterIsInvalid(commentData);&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; List&amp;lt;CommentData&amp;gt; comments = new List&amp;lt;CommentData&amp;gt;(1);&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; comments.Add(commentData);&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Execute(comments, userId, cn);&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp; }&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This function is nice and small.&amp;nbsp; However, the creation of the list comes out of nowhere.&amp;nbsp; It make sense when you look at the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Execute&lt;/span&gt; statement two lines down,&amp;nbsp; but I dislike the fact that the reader has to look two lines down to understand what's going on.&amp;nbsp; So this might be better:&lt;br /&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="font-size: x-small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;span style="font-size: x-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; public static void Execute(CommentData commentData,&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; int userId,&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; SqlConnection cn) {&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; ThrowExceptionIfExecuteMethodCommentParameterIsInvalid(commentData);&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Execute(toList(commentData), userId, cn);&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; private static List&amp;lt;CommentData&amp;gt; toList(CommentData commentData) {&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; List&amp;lt;CommentData&amp;gt; comments = new List&amp;lt;CommentData&amp;gt;(1);&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; comments.Add(commentData);&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return comments;&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&amp;nbsp; &lt;br /&gt;The function that checks the exceptions looks like this:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected static void ThrowExceptionIfExecuteMethodCommentParameterIsInvalid(&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; CommentData commentData) {&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (null == commentData)&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new ArgumentNullException("commentData");&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (commentData.CommentId.HasValue)&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new ArgumentNullException(&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; "commentData",&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; "CommentInsertCommand is only for adding new data.");&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I understand the old C programmer's trick of inverting equality statements.&amp;nbsp; It prevents the inadvertent omission of a &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;=&lt;/span&gt; from being silent.&amp;nbsp; But I don't like it.&amp;nbsp; It doesn't read right.&amp;nbsp; I prefer:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (commentData == null)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;CommentData&lt;/span&gt; is the subject of that sentence, and &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;null&lt;/span&gt; is the direct object.&amp;nbsp; Inverting them doesn't jive well with the way we think.&amp;nbsp; I dislike any statement in code that causes the reader to do a double-take.&amp;nbsp; Code that protects the author at the expense of the reader is flawed code.&lt;br /&gt;&lt;br /&gt;There is another function in this class that has the following name:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ThrowExceptionIfExecuteMethodCommentsParameterIsInvalid&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Can you tell the difference between that function name, and the one we just looked at?&amp;nbsp; It bothers me that these two function have names that are so very similar.&amp;nbsp; What's worse is that they use two different conventions.&amp;nbsp; The latter refers directly to the &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;comments&lt;/span&gt; argument of the function that calls it.&amp;nbsp; However, the former does not use the precise name of the argument it is checking.&amp;nbsp; Rather it abbreviates &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;CommentData&lt;/span&gt; to &lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;Comment&lt;/span&gt;.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;Fixing this changes the method names as follows:&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ThrowExceptionIfExecuteMethodCommentDataParameterIsInvalid&lt;/div&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ThrowExceptionIfExecuteMethodCommentsParameterIsInvalid &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;That's really not that much better.&amp;nbsp; So how about this:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ThrowIfCommentDataIsInvalid(CommentData)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ThrowIfListOfCommentsIsInvalid(IEnumerable&amp;lt;CommentData&amp;gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Or maybe even this:&lt;br /&gt;&lt;br /&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ThrowIfInvalid(CommentData)&lt;/div&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;ThrowIfInvalid(IEnumerable&amp;lt;CommentData&amp;gt;)&lt;/div&gt;&lt;br /&gt;Usually I prefer the longer names.&amp;nbsp; But in this case the argument type is easily seen as part of the function name.&amp;nbsp; So I think I like it better.&lt;br /&gt;&lt;br /&gt;The implementation of the second function is:&lt;br /&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="font-size: x-small;"&gt; &lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="font-size: x-small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected static void ThrowIfInvalid(IEnumerable&amp;lt;CommentData&amp;gt; comments) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (comments == null)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new ArgumentNullException("comments");&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (AreAllCommentsNew(comments))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new ArgumentNullException(&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&lt;span style="font-size: x-small;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; "comments", "CommentInsertCommand is only for saving new data.");&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected static bool AreAllCommentsNew(IEnumerable&amp;lt;CommentData&amp;gt; Comments) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return (0 == Comments.Count(x =&amp;gt; !x.CommentId.HasValue));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Notice that the implementations of these two functions have some redundancy. They both perform the following check:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;commentData.CommentId.HasValue&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;And they both emit the same (or very similar) exception message.&amp;nbsp; It seems to me that the check in the first function need not exist.&amp;nbsp; It can be shortened to:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; protected static void ThrowIfInvalid(CommentData commentData) {&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; if (commentData == null)&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; throw new ArgumentNullException("commentData");&lt;/span&gt;&lt;br style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;" /&gt;&lt;span style="font-family: &amp;quot;Courier New&amp;quot;,Courier,monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;That's about all I have time for today.&amp;nbsp; The dog is barking at my door, and my wife has fish cooking upstairs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-2292924539589399008?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/2292924539589399008/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2010/09/john-macintyres-clean-code-experience-1.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/2292924539589399008'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/2292924539589399008'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2010/09/john-macintyres-clean-code-experience-1.html' title='John MacIntyre&apos;s Clean Code Experience #1.'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-7630456797329532771</id><published>2010-08-24T06:18:00.000-07:00</published><updated>2010-08-24T06:35:00.555-07:00</updated><title type='text'>QA or When do you flip a pancake?</title><content type='html'>When do you flip a pancake?&amp;nbsp; We know what a good pancake looks like.&amp;nbsp; It's nicely brown on both sides, with a cheery ring of white along the rim.&amp;nbsp; But when you start with a pitcher of pancake batter, and a restaurant full of hungry lumberjacks,&amp;nbsp; how do you get your pancakes to meet those requirements?&lt;br /&gt;&lt;br /&gt;The requirements are completely unambiguous.&amp;nbsp; Brown sides.&amp;nbsp; White ring.&amp;nbsp; What could be simpler?&amp;nbsp; So let's design a development process that will make our pancakes come out right:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Developer pours pancake batter.&lt;/li&gt;&lt;li&gt;Developer flips pancakes at a rate based on the schedule. &lt;/li&gt;&lt;li&gt;Developer throws "done" pancake over the wall to QA.&lt;/li&gt;&lt;li&gt;QA inspects pancake.&amp;nbsp; Rejects are thrown back over the wall to the developer to "fix".&amp;nbsp; &lt;/li&gt;&lt;/ol&gt;Clearly, unless the developer is really good at estimating, the result of this process will be a lot of wasted pancakes, delayed breakfasts, angry customers, and accountants who, concerned about costs, suggest that pancake developers should be outsourced.&lt;br /&gt;&lt;br /&gt;OK, so let's design a different process.&amp;nbsp; Based on our observations of pancake&amp;nbsp; cooking, we notice that the perfect time to flip the pancake is when the bubbles on the top have just popped, and the surface starts to look slightly dry.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Developer pours pancake batter.&lt;/li&gt;&lt;li&gt;Developer applies the test to determine when to flip the pancake.&lt;/li&gt;&lt;li&gt;Developer sees pancakes are perfect and ships them. &amp;nbsp;&lt;/li&gt;&lt;li&gt;QA simply observes the pancakes on a statistical basis.&lt;/li&gt;&lt;/ol&gt;When we apply this process, we find that QA hardly ever rejects a pancake.&amp;nbsp; Breakfast cooking becomes efficient.&amp;nbsp; Customers are happy.&amp;nbsp; Accountants, concerned about costs, suggest downsizing the QA group.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Moral of the story:&lt;/b&gt;&amp;nbsp; Developers are not &lt;i&gt;done&lt;/i&gt; until the acceptance tests pass!&lt;br /&gt;&lt;br /&gt;Who designs the acceptance tests?&amp;nbsp; QA of course.&lt;br /&gt;&lt;br /&gt;I recently read a blog by Dennis Stevens entitled &lt;a href="http://www.dennisstevens.com/2010/08/23/we-are-doing-qa-all-wrong/"&gt;We Are Doing QA All Wrong&lt;/a&gt;. He is, of course, quite right.&amp;nbsp; We are, and have been, doing QA all wrong for years.&amp;nbsp; Indeed, the current role of QA only exists because developers have been so &lt;i&gt;bad&lt;/i&gt; at doing their jobs.&lt;br /&gt;&lt;br /&gt;QA is at the end of the process because development never learned when to flip the pancakes. Decades ago, frustrated by the terrible quality coming out of development, managers created an inspection step at the end of the process.&amp;nbsp; QA (or QC as Stevens would have it) was born.&amp;nbsp; This role for QA reinforced the bad behavior of development that spawned it.&amp;nbsp; Because QA was at the end, developers didn't need to care about getting things right.&amp;nbsp; Developers no longer had to worry about bugs; that was now QAs role.&amp;nbsp; All developers needed to do was to "say" that the code worked as far as they were concerned, and then throw it over the wall.&amp;nbsp; &lt;i&gt;Deadlines are a lot easier to make when you don't have to make the code actually work.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Management, in order to justify the existence of QA to the accountants, who were very concerned about the cost, began to measure QAs efficiency.&amp;nbsp; The more bugs that QA found, the better the job they were doing.&amp;nbsp; &lt;i&gt;Notice how insane that is!&lt;/i&gt;&amp;nbsp; The only way for QA to be measured well is for development to screw up royally.&amp;nbsp; The more bugs that developers create the better QA looks.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;And so an unholy alliance of blame avoidance was born.&amp;nbsp; Developers can appear to meet deadlines by delivering crap.&amp;nbsp; QA is measured highly because they find lots of bugs.&amp;nbsp; Everybody is happy -- except the end customer, and the accountants who are very concerned about costs.&lt;br /&gt;&lt;br /&gt;Look, this isn't rocket science.&amp;nbsp; If QA's input is primarily at the back end of the process, you are going to have lots of waste, rework, delay, and angry customers.&amp;nbsp; I mean:&amp;nbsp; &lt;i&gt;Duh!&amp;nbsp; &lt;/i&gt;(Pronounced "DUUU-uuuh")&lt;br /&gt;&lt;br /&gt;So where do we put QA?&amp;nbsp; How do we break the unholy alliance, and stop avoiding the blame?&amp;nbsp; Simple!&amp;nbsp; Move QA to the front.&lt;br /&gt;&lt;br /&gt;What if QA's job was &lt;i&gt;not to test the product&lt;/i&gt;, but to &lt;i&gt;design&lt;/i&gt; the tests that developers use to know when to flip the pancake?&amp;nbsp; If QA created suites of automated acceptance tests using tools like &lt;a href="http://fitnesse.org/"&gt;&lt;i&gt;FitNesse&lt;/i&gt;&lt;/a&gt;, then developers would &lt;i&gt;know&lt;/i&gt; when they were done.&amp;nbsp; Developers would continue working until the acceptance tests all passed.&amp;nbsp; Indeed, &lt;i&gt;it would be the developers who executed those tests.&amp;nbsp;&amp;nbsp;&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;This is how good agile teams are organized.&amp;nbsp; QA (and development) works with the business to define the requirements &lt;i&gt;as a suite of automated tests&lt;/i&gt; that developers execute to know when they are done.&amp;nbsp; When all the tests pass, QA makes a final &lt;a href="http://en.wikipedia.org/wiki/Exploratory_testing"&gt;exploratory&lt;/a&gt; pass over the product, and sends it on to production.&lt;br /&gt;&lt;br /&gt;That last step is a little more complicated than that, but is beyond the scope of this article.&amp;nbsp; Suffice it to say that exploratory testing is a craft in it's own right that needs to be part of the process on an on-going basis.&lt;br /&gt;&lt;br /&gt;So, in the end, when do you flip a pancake?&amp;nbsp; What is the definition of "done"?&amp;nbsp; Developers are done when the automated acceptance tests design by QA all execute and all pass.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-7630456797329532771?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/7630456797329532771/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2010/08/qa-or-when-do-you-flip-pancake.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/7630456797329532771'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/7630456797329532771'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2010/08/qa-or-when-do-you-flip-pancake.html' title='QA or When do you flip a pancake?'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3898534372669113633.post-2984238604657372538</id><published>2010-08-18T11:42:00.000-07:00</published><updated>2010-08-18T11:45:02.709-07:00</updated><title type='text'>Why Clojure?</title><content type='html'>I have recently become quite an enthusiast for the language &lt;a href="http://clojure.org/"&gt;&lt;i&gt;Clojure&lt;/i&gt;&lt;/a&gt;.&amp;nbsp; But why?&amp;nbsp; Why would someone who has spent the last 30 years programming in C, C++, Java, C#, and Ruby suddenly become enamored with a language that has roots that go back to 1957, i.e. Lisp?&lt;br /&gt;&lt;br /&gt;During my first few decades as a professional programmer, I never learned Lisp.&amp;nbsp; I had heard of it, of course; though mostly in derisive terms.&amp;nbsp; People sneered about it with names like "Lots of InSignificant Parentheses".&amp;nbsp; So my view was not particularly favorable.&lt;br /&gt;&lt;br /&gt;A few years ago, someone suggested that I learn Lisp by reading a book entitled: "&lt;a href="http://mitpress.mit.edu/sicp/"&gt;The Structure and Interpretation of Computer Programs&lt;/a&gt;".&amp;nbsp; So I went to Amazon and ordered a copy from the used books section.&amp;nbsp; It arrived a week or so later, and then sat on my "to read" stack for a couple of years.&lt;br /&gt;&lt;br /&gt;I started reading it about two years ago; and it changed everything I had previously felt and believed about Lisp.&amp;nbsp; It also changed a great deal of what I felt and believed about programming in general.&amp;nbsp; In short, the book was &lt;i&gt;startling&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;SICP is a literary masterpiece.&amp;nbsp; It's not often that you can say that a technical book is a page-turner, but that's just what I found SICP to be.&amp;nbsp; The book moves from topic to topic with rare ease and clarity, but more importantly it moves with &lt;i&gt;purpose&lt;/i&gt; and &lt;i&gt;mission&lt;/i&gt;.&amp;nbsp; As you read it, you can feel the authors slowly building a tension towards a climax.&amp;nbsp; The chapters fly by as you read about data structures, algorithms, message passing, first-class procedures, and so much else.&amp;nbsp; Each concept leads inevitably to the next.&amp;nbsp; Each chapter adds to the ever building tension.&amp;nbsp; By time you are half-way through the book, the sense that something important is about to change becomes palpable.&amp;nbsp; &lt;br /&gt;&lt;br /&gt;And then something important changes!&amp;nbsp; Something you had not anticipated.&amp;nbsp; Something you should have guessed, but did not.&amp;nbsp; On page 216 they introduce a concept so familiar that most programming books start with it.&amp;nbsp; On page 216 they prove to you that you've had some wrong ideas about programming all along.&amp;nbsp; On page &lt;i&gt;two hundred and sixteen&lt;/i&gt;, after talking about algorithms, data structures, recursion, iteration, trees, high-order procedures, scoping, local variables, data abstraction, closures, message-passing, and a plethora of other topics -- after all that, they introduce &lt;i&gt;assignment&lt;/i&gt;!&lt;br /&gt;&lt;br /&gt;And with that elegant coup-de-grace (which is not the last in this book!), they vanquish the concept that programming is about manipulating state.&amp;nbsp; With that one stroke, they force you to look back on all you had done in the previous pages in a new and enlightened way -- a functional way.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Moore's Law &lt;/span&gt;&lt;br /&gt;Why is functional programming important?&amp;nbsp; Because &lt;a href="http://en.wikipedia.org/wiki/Moore%27s_law"&gt;Moore's law&lt;/a&gt; has started to falter.&amp;nbsp; Not the part of the law that predicts that the number of transistors on a chip doubles every two years.&amp;nbsp; Thankfully, that part of the law seems to still be in effect.&amp;nbsp; The part that faltered is the part that says the speed of computers doubles every two years.&amp;nbsp; &lt;span id="goog_214416420"&gt;&lt;/span&gt;&lt;span id="goog_214416421"&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.gotw.ca/images/CPU.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="396" src="http://www.gotw.ca/images/CPU.png" width="400" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;What this means is that our computers can still get faster, but only if we put multiple CPUs on a chip.&amp;nbsp; This is why we've seen all these multi-core processors showing up.&amp;nbsp; And &lt;i&gt;that&lt;/i&gt; means that programs that need greater speed will have to be able to take advantage of the multiple cores.&lt;br /&gt;&lt;br /&gt;If you've ever written multi-threaded code, the thought of eight, sixteen, thirty-two, or even more processors running your program should fill you with dread.&amp;nbsp; Writing multi-threaded code correctly is &lt;i&gt;hard&lt;/i&gt;!&amp;nbsp; But why is it so hard?&amp;nbsp; Because it is hard to manage the state of variables when more than one CPU has access to them.&lt;br /&gt;&lt;br /&gt;And this is where functional programming comes in.&amp;nbsp; Functional programming, of the kind shown in SICP, is a way to write code that does not manage the state of variables, and could therefore be partitioned to run in parallel on as many processors as you like -- at least in theory.&amp;nbsp; In practice it might not be quite that trivial; but one thing is certain.&amp;nbsp; Moving functional programs to massively parallel system will be easier than moving non-functional programs.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Why Clojure?&lt;/span&gt;&lt;br /&gt;So why is Clojure the best option for a functional language?&amp;nbsp; After all, there are lots of functional languages out there.&amp;nbsp; Some are old, like Haskell, and Erlang.&amp;nbsp; Some are new like Scala and F#.&amp;nbsp; Why is Clojure the language that has everybody so fired up?&amp;nbsp; Here are just a few reasons.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Clojure is Lisp.&amp;nbsp; And Lisp is a functional, simple, well-known, elegant language. The syntax is almost laughably terse. This is in contrast to languages like F# and Scala which have a complexity and "quirkiness" reminiscent of C++.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Clojure is Java.&amp;nbsp; Clojure sits on top of the Java stack, and has the ability to inter-operate with Java with extreme ease.&amp;nbsp; Java programs can call Clojure, and Clojure can call Java.&amp;nbsp; You can write Clojure code that derives from Java classes and overrides Java methods.&amp;nbsp; In short, if you can do it in Java, you can do it in Clojure.&amp;nbsp; What's more there is a Clojure port for the CLR!&amp;nbsp; So Clojure may be the only functional language that inter-operates well with both major VMs.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Clojure implements &lt;a href="http://en.wikipedia.org/wiki/Software_transactional_memory"&gt;Software Transactional Memory&lt;/a&gt; which means that any time a Clojure programmer want's to change the state of a variable, they must do so using the same kind of transaction management as they would use for a database. This enforces the functional paradigm do a degree that few other functional languages do.&amp;nbsp; The STM facilities of Clojure are elegant and simple, just like the rest of the language.&amp;nbsp; They do not intrude where they aren't needed, and they are simple to employ where state must be changed.&lt;br /&gt;&amp;nbsp;&lt;/li&gt;&lt;li&gt;Clojure is fast.&amp;nbsp; Data structures in functional languages are immutable.&amp;nbsp; For example, you can't add an item to a list, instead you create a copy of the list with the new item added.&amp;nbsp; This copying could obviously slow things down a lot.&amp;nbsp; Clojure manages complex immutable data structures using a &lt;a href="http://blog.higher-order.net/2009/02/01/understanding-clojures-persistentvector-implementation/"&gt;sharing technique&lt;/a&gt; that eliminates the need to make deep copies of those structures. This means that Clojure runs very fast.&amp;nbsp; &lt;br /&gt;&lt;/li&gt;&lt;li&gt;Clojure is supported.&amp;nbsp; There are tutorials and blogs.&amp;nbsp; There are IDE plugins.&amp;nbsp; And there are &lt;a href="http://groups.google.com/group/clojure"&gt;mailing lists&lt;/a&gt; and user groups.&amp;nbsp; If you program in Clojure, you won't be alone.&amp;nbsp; &lt;/li&gt;&lt;/ul&gt;&lt;span style="font-size: large;"&gt;Conclusion&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;The last few decades have seen us migrate from procedures to objects.&amp;nbsp; Now the physical constraints of our hardware is&amp;nbsp; driving us to make a similar kind of paradigm shift towards functional languages.&amp;nbsp; The next few years will see us experiment with many different projects using those languages as we try to figure out which functional languages are best.&amp;nbsp; I fully expect Clojure to be ranked very highly when the results of those experiments come in.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3898534372669113633-2984238604657372538?l=thecleancoder.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thecleancoder.blogspot.com/feeds/2984238604657372538/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://thecleancoder.blogspot.com/2010/08/why-clojure.html#comment-form' title='28 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/2984238604657372538'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3898534372669113633/posts/default/2984238604657372538'/><link rel='alternate' type='text/html' href='http://thecleancoder.blogspot.com/2010/08/why-clojure.html' title='Why Clojure?'/><author><name>Uncle Bob</name><uri>http://www.blogger.com/profile/02481406139679244157</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>28</thr:total></entry></feed>
