<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Gojko Adzic &#187; productivity</title>
	<atom:link href="http://gojko.net/tag/productivity/feed/" rel="self" type="application/rss+xml" />
	<link>http://gojko.net</link>
	<description>Building software that matters</description>
	<lastBuildDate>Tue, 22 May 2012 19:12:44 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>When TDD goes bad</title>
		<link>http://gojko.net/2008/02/25/when-tdd-goes-bad/</link>
		<comments>http://gojko.net/2008/02/25/when-tdd-goes-bad/#comments</comments>
		<pubDate>Mon, 25 Feb 2008 18:11:27 +0000</pubDate>
		<dc:creator>gojko</dc:creator>
				<category><![CDATA[articles]]></category>
		<category><![CDATA[productivity]]></category>
		<category><![CDATA[tdd]]></category>

		<guid isPermaLink="false">http://gojko.net/2008/02/25/when-tdd-goes-bad/</guid>
		<description><![CDATA[Last week, at the London .NET User Group meeting, Ian Cooper talked about Test-driven development, focusing on both good and bad practices. I&#8217;m a big fan of learning from anti-patterns and mistakes of other people, so the second part of his session was very interesting to me. Here is a...]]></description>
			<content:encoded><![CDATA[<p><img src="/images/933309_rottenlemons.jpg" style="float:left;" />Last week, at the <a href="http://www.dnug.org.uk/" target="_blank">London .NET User Group</a> meeting, <a href="http://codebetter.com/blogs/ian_cooper/default.aspx" target="_blank">Ian Cooper</a> talked about Test-driven development, focusing on both good and bad practices. I&#8217;m a big fan of learning from anti-patterns and mistakes of other people, so the second part of his session was very interesting to me. Here is a short list of things that Ian identified as symptoms that TDD has gone bad in a project, along with my comments:<span id="more-103"></span></p>
<ul>
<li>Disabling tests to make a build pass:
<p>If the build is failing because of a test, developers disable the test to make the build pass. This is a bad practice because tests become irrelevant or get lost &mdash; people don&#8217;t remember to fix and enable them later. If the test is deprecated, then delete it completely. If it is not deprecated, don&#8217;t disable it but make it pass. </p>
</li>
<li>Continuous integration not failing when unit tests fail:
<p>The point of continuous integration is to automate problem checking and prevent a big-bang integration before a release. Broken unit tests should raise an alarm and get fixed before problems pile up. If the CI server does not break the build when a unit test fails, then CI configuration must be changed.</p>
</li>
<li>Not monitoring customer tests:
<p>Ian put integration and acceptance tests under the &#8220;customer tests&#8221; group. These tests don&#8217;t break the build because they will not pass for most of the development, but they still might go down from 30% to 20%, for example. That is a sure sign that something bad happened, yet if nobody is monitoring the reports, this will again lead to a big bang integration on the end. In my eyes, integration tests and customer tests should be split into two parts: the first one (integration) should break the build, and the second one (acceptance) should not, but it should still be monitored.</p>
</li>
<li>UI change causes tests to fail (interface sensitivity):
<p>If tests depend on the UI heavily, then they will be brittle and hard to maintain. I wrote about this earlier in <a href="http://gojko.net/2007/09/25/effective-user-interface-testing/">Effective User Interface Testing</a>.</p>
</li>
<li>(3rd party)  API changes cause tests to fail:
<p>If changes to 3rd party APIs propagate to tests, then tests are again hard and expensive to maintain. I guess that the bigger underlying problem here is that the business logic is not isolated properly from 3rd party libraries.</p>
</li>
<li>Many tests fail when a single behaviour changes:
<p>This applies to unit tests, and signals that tests are not properly granulated and focused on code units, but try to test too much. Again, the issue arising from this is high cost of test maintenance.</p>
</li>
<li>Data-sensitive tests:
<p>Tests that depend on some data pre-conditions (such as certain records existing in the database) are also brittle and will break when the data changes. Test harness should ideally set up all the pre-conditions for a test. A telling sign of this are tests that use hard-coded database IDs.</p>
</li>
<li>(Shared) Context Sensitivity:
<p>If tests depend on other tests to set up the context, then the order of test execution becomes important and you can no longer run individual tests in isolation. This can lead to big problems, especially if the test runner does not guarantee the order of tests. Again, the test harness should ideally set up all the pre-conditions for a test and individual tests should be independent.</p>
</li>
<li>Conditional test logic:
<p>The telling sign of this problem is that tests choose validations based on run-time context (<i>if (&#8230;) test this&#8230; else test that&#8230;</i>). This signals that the test is not clearly focused on a single thing, and that the author does not really understand what he is testing.</p>
</li>
</ul>
<h2>A quick summary</h2>
<p>Tests that break without anyone reacting do not prevent problems from piling up. This defeats the point of tests being a traffic light that keeps the problems small and prevents a big-bang integration on the end. When tests fail, alarm bells should ring. </p>
<p>High maintenance cost of tests defeats the whole point of having them, as a way to guarantee that code changes are easy and cost-effective. Keep unit tests independent and focused on a single code unit. Then they will be easy to maintain and will support change rather then inhibit it.</p>
<p><b>Image credits:</b><a href="http://www.sxc.hu/profile/Splenetic" target="_blank">Lorenzo González</a></p>
]]></content:encoded>
			<wfw:commentRss>http://gojko.net/2008/02/25/when-tdd-goes-bad/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>How to avoid getting lost in translation</title>
		<link>http://gojko.net/2008/01/30/how-to-avoid-getting-lost-in-translation/</link>
		<comments>http://gojko.net/2008/01/30/how-to-avoid-getting-lost-in-translation/#comments</comments>
		<pubDate>Wed, 30 Jan 2008 11:38:43 +0000</pubDate>
		<dc:creator>gojko</dc:creator>
				<category><![CDATA[articles]]></category>
		<category><![CDATA[communication]]></category>
		<category><![CDATA[ddd]]></category>
		<category><![CDATA[productivity]]></category>
		<category><![CDATA[ubiquitous language]]></category>

		<guid isPermaLink="false">http://gojko.net/2008/01/30/how-to-avoid-getting-lost-in-translation/</guid>
		<description><![CDATA[I am getting more convinced every day that communication is, in fact, what makes or breaks software projects. Programming tools, practices and methods are definitely important, but if the communication fails then the rest is just painting the corpse. From that point of view, getting the language right is one...]]></description>
			<content:encoded><![CDATA[<p><img src='/images/436457_guidebooks.jpg' style='float:left;margin:5px 5px 5px 5px' /> I am getting more convinced every day that communication is, in fact, what makes or breaks software projects. Programming tools, practices and methods are definitely important, but if the communication fails then the rest is just painting the corpse. From that point of view, getting the language right is one of the key steps for any software project, because the language provides the foundations for all communication. The right language does not, of course, guarantee that the correct thing will be built on time and within budget &mdash; but the wrong language is practically a guarantee that the project will fail. <span id="more-95"></span></p>
<p>The importance of a common language is nothing new or specific to software projects. The western civilisation has been learning that complex projects have no chance of success without a common language <a href='http://en.wikipedia.org/wiki/Confusion_of_tongues' target='_blank'>at least for the last two thousand years</a>, but it seems that we have still not taken that message seriously. In the software world, the language of projects has been getting much more attention recently, especially due to Eric Evans and his book <a target="_blank" href="http://www.amazon.com/gp/product/0321125215?ie=UTF8&#038;tag=swingwiki-20&#038;linkCode=as2&#038;camp=1789&#038;creative=9325&#038;creativeASIN=0321125215">Domain-Driven Design: Tackling Complexity in the Heart of Software</a><img src="http://www.assoc-amazon.com/e/ir?t=swingwiki-20&#038;l=as2&#038;o=1&#038;a=0321125215" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />. Evans coined the phrase <a target='_blank' href='http://domaindrivendesign.org/discussion/messageboardarchive/UbiquitousLanguage.html'>Ubiquitous language</a> to describe the best practice to fight different jargons on project teams. Using an ubiquitous language requires business analysts, customers and programmers to all have the same names for the same things. But getting everyone to use common phrases is just one part of the puzzle.</p>
<p>I have stumbled upon a few very interesting conclusions about the language and how important it is to choose good metaphors and names in Douglas Hofstadter&#8217;s book <a target="_blank" href="http://www.amazon.com/gp/product/0465026567?ie=UTF8&#038;tag=swingwiki-20&#038;linkCode=as2&#038;camp=1789&#038;creative=9325&#038;creativeASIN=0465026567">Gödel, Escher, Bach</a><img src="http://www.assoc-amazon.com/e/ir?t=swingwiki-20&#038;l=as2&#038;o=1&#038;a=0465026567" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />. That title has intrigued me for a few years, but as a quick look on Amazon told me that is has almost 800 pages, it had to wait for me to change my daily routine before I could even start reading it. The last few months have been much more quiet than usual, so I finally had some time to dive in. Although the book deals with something completely unrelated to software projects, it contains some very interesting ideas that we can apply to improve software development. I especially like the thoughts on how humans understand formal systems and how the meanings of abstractions form in our minds. </p>
<p>Before this starts to sound too philosophical, let me change the direction of this story. I was recently involved in a project where the common language was chosen and agreed upon, but caused a lot more confusion then I expected. Even with the definitions written down and published on a wiki site, a lot of time was wasted on misunderstandings of basic concepts and going back to explain the same things over and over again. The phrases of that common language were OK from the aspect that they made sense, but they were a compromise between business jargon and technical design and somehow fell short of pleasing anyone. It was a strange situation because all the people involved were techies, and I expected that people with technical education should generally be OK with abstracting things a bit, understanding and using formal definitions even if they do not necessarily bear the same meaning as in common everyday language. But that has not worked out as expected. I had a feeling of what went wrong, but I did not have strong arguments to support that opinion.  Hofstadter, however, provides a very nice explanation for that on pages 90 and 91:</p>
<blockquote><p><i>&#8230; Therefore, when someone gives a definition for a common word in the hopes that we will abide by that  definition, it is a foregone conclusion that we will not do so, but will  instead be guided, largely unconsciously, by what our minds find in their associative stories&#8230;</i></p></blockquote>
<p>In short, redefining a common phrase is not going to work. Whether we like it or not, our understanding of a common concept gets in the way of applying it in a different context.  &#8220;Gödel, Escher, Bach&#8221; offers some very interesting examples how attempting to impose definitions of common phrases and words was a very hard thing to do throughout history, starting with that Euclid&#8217;s Elements and his attempt to specify what “point”, “straight line” and “circle” mean.</p>
<p>On page 94,  Hofstadter explains another interesting idea:</p>
<blockquote><p><i>&#8230;The symbols automatically pick up passive meanings in accordance with the theorems they occur in&#8230;</i></p></blockquote>
<p>So regardless of the actual name used for something, our mind gives it a passive meaning depending on the way in which it is used and cooperates with other concepts. If a name given to some concept does not match the way it is being used, we will effectively attach a different name and a meaning to it. The way things are used dictates how we perceive them, regardless of the names that were enforced for those things.</p>
<p>Armed with this new insight, here are some ideas that I will definitely try on my next project:</p>
<p>&mdash; To name a concept, start from the way it will be used and try to find a intuitive match for that. </p>
<p>&mdash; Avoid generic names such as &#8220;Controller&#8221;, &#8220;Manager&#8221; or &#8220;Content&#8221;. They already carry too much ambiguity.</p>
<p>&mdash; For all common phrases from the business or technical jargon that have been selected for the ubiquitous language, double-check that there are no other related meanings that could cause confusion.</p>
<p><b>Image credits:</b> <a href='http://www.sxc.hu/profile/dogmadic' target='_blank'>Dog Madic</a></p>
]]></content:encoded>
			<wfw:commentRss>http://gojko.net/2008/01/30/how-to-avoid-getting-lost-in-translation/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>When windows are not enough</title>
		<link>http://gojko.net/2007/08/21/when-windows-are-not-enough/</link>
		<comments>http://gojko.net/2007/08/21/when-windows-are-not-enough/#comments</comments>
		<pubDate>Tue, 21 Aug 2007 14:16:33 +0000</pubDate>
		<dc:creator>gojko</dc:creator>
				<category><![CDATA[articles]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[best practices]]></category>
		<category><![CDATA[productivity]]></category>

		<guid isPermaLink="false">http://gojko.net/2007/08/21/when-windows-are-not-enough/</guid>
		<description><![CDATA[It&#8217;s not uncommon for &#8220;star&#8221; programmers to be an order of magnitude more productive than their colleagues. I believe that a large part of that productivity gap comes not from doing tasks faster, but from not doing them at all. Good programmers make the machine sweat instead. I recently had...]]></description>
			<content:encoded><![CDATA[<p><img align='left' src='/images/253568_clock_7.jpg' style='border:1px solid black; margin:5px 5px 5px 5px;' /> <i>It&#8217;s not uncommon for &#8220;star&#8221; programmers to be an order of magnitude more productive than their colleagues. I believe that a large part of that productivity gap comes not from doing tasks faster, but from not doing them at all. Good programmers make the machine sweat instead.</i><span id="more-40"></span></p>
<p>I recently had a very unpleasant talk with one of our support developers. She was very annoyed, in a defensive mood, arguing that she is already too busy and cannot take on a bit more work. After twenty minutes of talking, she finally calmed down, and we came to the root of the problem. It&#8217;s not the programming part of her work that is killing her, but the fact that she has to go through several terminal servers to deploy changes to client environments, and that she has to merge all her changes into several revisions. And she does that for every single change, several times a day. So, in fact, she spent most of her time logging on to different computers and copying files between them. Although she understood the problem herself, the thought of automating those silly tasks never came to her mind. </p>
<p>It&#8217;s incredible how, for a profession based around telling machines how to perform dull and error-prone tasks instead of humans, so few programmers think about how to automate their own work.  This is especially noticeable with the &#8220;Windows generation&#8221;, people who never effectively used the command line. GUI programs are, without a doubt, more user friendly and easier to use, but they are bloody hard to automate. When a task has to be done fifty times, or performed across the network, words &#8220;ease of use&#8221; take on a completely different meaning. That is the point when good programmers break from the usual practices and find better ways to do the job, and bad programmers stick to their old habits. </p>
<h2>Breaking from the old habits</h2>
<p>A few years ago, I did some consultancy work for a company whose application generated huge log files on clustered servers. To find the cause of any problem, programmers and support staff transferred gigabytes of data from client&#8217;s web servers to their computers in order to analyse them. Each transfer took at least 10 to 15 minutes. There was no special reason for pulling all the log files to local machines, people were just used to doing their job like that. I was even more amazed to see that even some &#8220;senior&#8221; programmers in that organization repeatedly (tried) to open monstrous log files in Notepad and than wasted the next 20 minutes waiting for their machine to unfreeze.  All that just to find a few lines of text, which could have been done in a minute or two using <i>findstr</i> on the server. </p>
<p>When a solution clearly does not scale to the problem, we look for a better one, or a different way to implement it. The solution often requires using a different approach, or different tools. The same holds for non-programming tasks. We must look for better ways to perform daily tasks when the usual tricks don&#8217;t work. In this case, the proper solution was to use the command line. Programs like <i>tail</i> and <i>grep</i> were developed at a time when network connections were bad, and computing power was scarce, so they don&#8217;t require a lot of typing and clicking.  Although available bandwidth and computing power have improved greatly over the last 20 years, such tools are still irreplaceable for processing large text files, especially on remote computers. Sadly, I meet more and more developers who never heard of those tools. If you are reading these lines and thinking to yourself &#8220;<i>what the heck is grep</i>&#8220;, here is just a brief introduction to some common tasks that these tools do really, really well: </p>
<blockquote>
<h3>grep</h3>
<ul>
<li>get all lines containing a string (or a regular expression) from a large file &#8211; for example, get all log items for a particular session or user</li>
<li>count the number of occurrences of a string (or regular expression) in a file &#8211; for example, find how many times someone has logged yesterday</li>
<li>find all files that contain a string (or regular expression) &#8211; for example, list log files that contain a particular username</li>
</ul>
<h3>more</h3>
<ul>
<li>view the start of a large file &#8211; for example, see the IIS log file format which prints column headers in the first line</li>
</ul>
<h3>tail</h3>
<ul>
<li>quickly view the last few lines of a large file &#8211; for example, check out the last exception</li>
<li>monitor how a log file is changing while other processes are writing into it &#8211; great for troubleshooting a live application, because it does not lock the file</li>
</ul>
<h3>awk</h3>
<ul>
<li>extract lines from a large file and reformat them &#8211; for example build URLs by appending fields from a tab-separated log file to the site prefix, or create a block of SQL statements to populate tables from some data export file</li>
<li>calculate statistics on file content &#8211; find top 20 client IPs by web bandwidth used and print the number of requests and total bandwidth used by each one</li>
<li>split a file into several other files, based on line content &#8211; for example, extract multi-line exceptions from a log file </li>
<li>quickly analyse a comma-separated, tab-separated or any other file format with multiple fields in a line</li>
</ul>
<h3>sed</h3>
<ul>
<li>&#8220;replace all&#8221; for large files and sets of files</li>
</ul>
</blockquote>
<p>Working on Windows is often an excuse for not using command-line tools, but that is just an excuse. There are several free sets of tools which bring power to the Windows command line. For example, <a href='http://www.cygwin.com/' target='_blank'>Cygwin</a> package allows most popular Unix tools to run from Windows. <a target='_blank' href='http://www.microsoft.com/downloads/details.aspx?FamilyID=9D467A69-57FF-4AE7-96EE-B18C4790CFFD&#038;displaylang=en'>Windows Resource Kit</a> from Microsoft contains <i>tail</i> and <i>qgrep</i> (a fairly usable variant of grep). <a href='http://www.microsoft.com/technet/sysinternals/utilities/pstools.mspx' target='_blank'>PsTools</a>, another package now owned by Microsoft, contains gems like <i>psexec</i> that can run a program on a remote computer. Some tools, like <a href='http://gnuwin32.sourceforge.net/packages/gawk.htm' target='_blank'>GNU Awk</a> have been directly ported to Windows by the GNU foundation. </p>
<p>On any variant of Unix, you can expect these tools to be already installed. Some trimmed-down replacements exist even for the standard Windows command line (like <i>findstr</i> which can be used instead of <i>grep</i> if you don&#8217;t look for regular expressions). However, most of these tools can just be copied to a remote machine and started (no need to &#8220;install&#8221; them), so you don&#8217;t require any special privileges to run them on client&#8217;s web servers, for example. You can just drop them on a remote computer and start using them. So don&#8217;t even try pulling the entire log file from the customers web site just to do a simple search: copy <i>gawk</i> there and process the log on the server.</p>
<p>In addition to being very efficient, these tools can easily be automated (scripted). It does not really matter whether shell scripts, batch files or some scripting language like vbscript, python or perl is used. Storing a <i>grep</i> or <i>awk</i> command line along with all the strange parameters will save you from the pain of writing them again tomorrow. </p>
<h2>Three strikes, and you are out</h2>
<p>&#8220;<i>Don&#8217;t repeat yourself</i>&#8221; is one of fundamental guidelines of Extreme Programming. Most good programmers today take care not to repeat the code, the ones that are even better find similarities in design and consolidate them, but very few apply the same rule to their habits or non-coding related work. I&#8217;m not just talking about half-hour tasks like sorting e-mail and analysing debug logs, but also small jobs like checking whether the client database is on-line or replacing seven occurrences of a field name in a script. </p>
<p>Apart from saving time, using <i>replace all</i> will also prevent errors, but you have to test it first before updating a 200 MB file on a client&#8217;s environment. The same tasks have to be applied for replacement in a 5 KB script file. There is always some overhead involved in automating the tasks, but when does it begin to pay off, and when is it unjustified? The rule I stick to is Roberts&#8217; rule of Three (from Fowler&#8217;s <a onClick="javascript:urchinTracker('/books/refactoring');"  target="_blank" href="http://www.amazon.com/gp/product/0201485672?ie=UTF8&#038;tag=swingwiki-20&#038;linkCode=as2&#038;camp=1789&#038;creative=9325&#038;creativeASIN=0201485672">Refactoring: Improving the Design of Existing Code</a><img src="http://www.assoc-amazon.com/e/ir?t=swingwiki-20&#038;l=as2&#038;o=1&#038;a=0201485672" width="1" height="1" border="0" alt="" style="border:none !important; margin:0px !important;" />), another version of DRY:</p>
<blockquote>
<h3>The Rule of Three by Don Roberts</h3>
<p>The first time you do something you just do it. The second time you do something similar, you wince at the duplication, but you do the duplicate thing anyway. The third time you do something similar, you refactor.
</p></blockquote>
<p>This is also a good rule of thumb for tasks outside of coding. Read it like this: If you catch yourself doing something for the third time, chances are that you will have to do it again, so automate it. Use the <i>replace all</i> if you have to replace the same string more than two times. More importantly, stick to the rule when things get complicated! If you are not dealing with plain strings, but have to re-format the data a bit, don&#8217;t fall back to manual work: utilise regular expressions (if you don&#8217;t know how to use regular expressions, <a href='http://www.gnu.org/manual/gawk/html_node/Regexp.html' target='_blank'>now is the time to learn</a>). If this is the third time this week that you are doing the same replacement, don&#8217;t use the regular expressions manually, but write a script. When you catch yourself running that script every day (week, month) add it to the scheduled tasks list (or cron jobs).</p>
<p>Automating tasks is especially important when your client has to perform them. Having a nice automated installer instead of a two-page word document explaining all the steps required to set up the software goes a long way. It makes the task less error-prone so the customers will be happier, and it leaves us with more time for the fun stuff.  </p>
<p>Image credits: <a href='http://www.sxc.hu/profile/dlee' target='_blank'>D Lee/SXC</a></p>
]]></content:encoded>
			<wfw:commentRss>http://gojko.net/2007/08/21/when-windows-are-not-enough/feed/</wfw:commentRss>
		<slash:comments>19</slash:comments>
		</item>
	</channel>
</rss>

