<?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-8528631747209969303</id><updated>2011-12-27T16:49:32.991-05:00</updated><category term='Python'/><category term='Kata'/><category term='Manager'/><category term='Book Review'/><category term='How To'/><category term='javascript'/><category term='Craftsmanship'/><category term='Source Control'/><category term='Technical Debt'/><category term='Clojure'/><category term='Programming Practices'/><category term='User Groups'/><category term='Teams'/><category term='Coaching'/><category term='Presentations'/><category term='SubVersion'/><category term='Testing'/><category term='Development'/><category term='Games'/><category term='Agile'/><category term='Functional Programming'/><category term='git'/><category term='Ruby'/><category term='User Experience'/><category term='FitNesse'/><category term='Retrospectives'/><category term='Mac'/><category term='Career'/><category term='Rant'/><category term='Ruby on Rails'/><category term='Scheme'/><category term='Event'/><category term='Metrics'/><title type='text'>Doc On Dev</title><subtitle type='html'>Michael Norton (doc) is an Agile Coach and a partner with &lt;a href="http://www.leandog.com/"&gt;LeanDog&lt;/a&gt; living in Wadsworth, OH. Michael's experience covers a wide range of development topics. Michael declares expertise in no single language or methodology and is immediately suspicious of anyone who declares such expertise. A frequent speaker, Michael is passionate about helping others become better developers, working with teams to improve delivery, and Software Craftsmanship.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.docondev.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://www.docondev.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>DocLogic</name><uri>http://www.blogger.com/profile/09149149882666714621</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://3.bp.blogspot.com/_rTMzO9gHrhM/Sd0iXzZQY8I/AAAAAAAAABE/OpHqxzM9EN4/S220/Profile_Picture.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>88</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-2005669749730531565</id><published>2011-12-27T10:28:00.002-05:00</published><updated>2011-12-27T11:52:55.866-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Kata'/><title type='text'>Roman Numeral Kata</title><content type='html'>While working on the &lt;a href="http://codingdojo.org/cgi-bin/wiki.pl?KataRomanNumerals"&gt;Roman Numeral Kata&lt;/a&gt;, I was bothered by the existence of special pairs in my numerals hash.&lt;br /&gt;&lt;pre class="brush: ruby"&gt;&lt;br /&gt;class Converter&lt;br /&gt;    NUMERALS = { 50 =&gt; "L", 40 =&gt; "XL", 10 =&gt; "X", 9 =&gt; "IX", 5 =&gt; "V", 4 =&gt; "IV", 1 =&gt; "I" }&lt;br /&gt;    def convert(number)&lt;br /&gt;        return NUMERALS[number] if NUMERALS[number]&lt;br /&gt;        to_roman(number) &lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    private&lt;br /&gt;&lt;br /&gt;    def to_roman(number)&lt;br /&gt;        result = ""&lt;br /&gt;        NUMERALS.each do |value, numeral|&lt;br /&gt;            while number &gt;= value&lt;br /&gt;                result += numeral&lt;br /&gt;                number -= value&lt;br /&gt;            end &lt;br /&gt;        end&lt;br /&gt;        result&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Notice the 40, 9, and 4. These aren't unique numerals, rather they are pairs that represent special subtraction rules. Doing this gets my tests to pass and solves the problem, but I wanted to see if I could come up with a way that better represented how roman numerals work.&lt;br /&gt;&lt;br /&gt;Looking for inspiration, I asked twitter and google for some help, but everything I found either used this technique or did some magic number substitution (YUCK). So I set out to find my own solution. Notice I am not professing I set out to find a better solution, only my own, alternative solution.&lt;br /&gt;&lt;br /&gt;I won't be showing all of the tests as we go along, but the entire solution was test driven with RSpec. You can review the history and see the tests on &lt;a href="https://github.com/DocOnDev/kata/tree/roman_numeral"&gt;github&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;h3&gt;Pairing Numerals&lt;/h3&gt;After a bit of thought, it occurred to me that I could "pair" numerals. A numeral could be assigned a pair. A numeral and it's pair make a new numeral pair through simple subtraction. For example, five is paired with one. Five's pair_numeral is now 4 with a roman value of "IV".&lt;br /&gt;&lt;h4&gt;The numeral class:&lt;/h4&gt;&lt;pre class="brush: ruby"&gt;&lt;br /&gt;class Numeral&lt;br /&gt;    attr_accessor :arabic&lt;br /&gt;    attr_accessor :roman&lt;br /&gt;    attr_accessor :pair&lt;br /&gt;&lt;br /&gt;    def initialize(*args)&lt;br /&gt;        if args[0] == args[0].to_i&lt;br /&gt;            @roman = args[1]&lt;br /&gt;            @arabic = args[0]&lt;br /&gt;        else&lt;br /&gt;            @roman = args[0]&lt;br /&gt;            @arabic = args[1]&lt;br /&gt;        end&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def pair_numeral&lt;br /&gt;        return Numeral.new(@arabic - @pair.arabic, @pair.roman + roman) if @pair&lt;br /&gt;        nil&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def ==(compare_to)&lt;br /&gt;        return @arabic = compare_to.arabic &amp;&amp; @roman == compare_to.roman&lt;br /&gt;    end&lt;br /&gt;end&lt;/pre&gt;&lt;br /&gt;I thought later that I don't really need to pass in parameters in variable order and if I do, I could just use a hash, but I didn't get around to cleaning that one up.&lt;br /&gt;&lt;h4&gt;The converter class:&lt;/h4&gt;&lt;pre class="brush: ruby"&gt;&lt;br /&gt;require 'numeral'&lt;br /&gt;&lt;br /&gt;class Converter&lt;br /&gt;    NUMERALS = { 1000 =&gt; Numeral.new(1000,"M"), 500 =&gt; Numeral.new(500,"D"), 100 =&gt; Numeral.new(100,"C"), 50 =&gt; Numeral.new(50,"L"), 10 =&gt; Numeral.new(10,"X"), 5 =&gt; Numeral.new(5,"V"), 1 =&gt; Numeral.new(1,"I") }&lt;br /&gt;&lt;br /&gt;    def initialize&lt;br /&gt;        @result = ""&lt;br /&gt;        NUMERALS[5].pair = NUMERALS[1]&lt;br /&gt;        NUMERALS[10].pair = NUMERALS[1]&lt;br /&gt;        NUMERALS[50].pair = NUMERALS[10]&lt;br /&gt;        NUMERALS[100].pair = NUMERALS[10]&lt;br /&gt;        NUMERALS[500].pair = NUMERALS[100]&lt;br /&gt;        NUMERALS[1000].pair = NUMERALS[100]&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def convert(number)&lt;br /&gt;        return NUMERALS[number].roman if NUMERALS[number]&lt;br /&gt;        to_roman(number) &lt;br /&gt;        @result&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    private&lt;br /&gt;&lt;br /&gt;    def to_roman(number)&lt;br /&gt;        NUMERALS.each do |value, numeral|&lt;br /&gt;            number = roman_reduce(number, numeral)&lt;br /&gt;            number = roman_reduce(number, numeral.pair_numeral) if numeral.pair_numeral&lt;br /&gt;        end&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def roman_reduce(number, numeral)&lt;br /&gt;        while number &gt;= numeral.arabic&lt;br /&gt;            @result += numeral.roman&lt;br /&gt;            number -= numeral.arabic&lt;br /&gt;        end &lt;br /&gt;        number&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This isn't bad, I suppose. Of course, there's a lot more code than the original solution, but it better represents how roman numerals work. Or does it?&lt;br /&gt;&lt;br /&gt;The name pair doesn't really make sense. And while I got rid of the special cases in my NUMERALS hash, I call each of them out in the converter class anyway.&lt;br /&gt;&lt;br /&gt;I asked friends on twitter to take a look and give me feedback. It was suggested that I change the names "pair" and "pair_numeral" to something else that better expresses what's really happening. So I changed "pair" to "subtrahend" and "pair_numeral" to "difference".&lt;br /&gt;&lt;h4&gt;The numeral class:&lt;/h4&gt;&lt;pre class="brush: ruby"&gt;&lt;br /&gt;class Numeral&lt;br /&gt;    attr_accessor :arabic&lt;br /&gt;    attr_accessor :roman&lt;br /&gt;    attr_accessor :subtrahend&lt;br /&gt;&lt;br /&gt;    def initialize(*args)&lt;br /&gt;        if args[0] == args[0].to_i&lt;br /&gt;            @roman = args[1]&lt;br /&gt;            @arabic = args[0]&lt;br /&gt;        else&lt;br /&gt;            @roman = args[0]&lt;br /&gt;            @arabic = args[1]&lt;br /&gt;        end&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def difference&lt;br /&gt;        return Numeral.new(@arabic - @subtrahend.arabic, @subtrahend.roman + roman) if @subtrahend&lt;br /&gt;        nil&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def ==(compare_to)&lt;br /&gt;        return @arabic = compare_to.arabic &amp;&amp; @roman == compare_to.roman&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;h4&gt;The converter class:&lt;/h4&gt;&lt;pre class="brush: ruby"&gt;&lt;br /&gt;require 'numeral'&lt;br /&gt;&lt;br /&gt;class Converter&lt;br /&gt;    NUMERALS = { 1000 =&gt; Numeral.new(1000,"M"), 500 =&gt; Numeral.new(500,"D"), 100 =&gt; Numeral.new(100,"C"), 50 =&gt; Numeral.new(50,"L"), 10 =&gt; Numeral.new(10,"X"), 5 =&gt; Numeral.new(5,"V"), 1 =&gt; Numeral.new(1,"I") }&lt;br /&gt;&lt;br /&gt;    def initialize&lt;br /&gt;        @result = ""&lt;br /&gt;        NUMERALS[5].subtrahend = NUMERALS[1]&lt;br /&gt;        NUMERALS[10].subtrahend = NUMERALS[1]&lt;br /&gt;        NUMERALS[50].subtrahend = NUMERALS[10]&lt;br /&gt;        NUMERALS[100].subtrahend = NUMERALS[10]&lt;br /&gt;        NUMERALS[500].subtrahend = NUMERALS[100]&lt;br /&gt;        NUMERALS[1000].subtrahend = NUMERALS[100]&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def convert(number)&lt;br /&gt;        return NUMERALS[number].roman if NUMERALS[number]&lt;br /&gt;        to_roman(number) &lt;br /&gt;        @result&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    private&lt;br /&gt;&lt;br /&gt;    def to_roman(number)&lt;br /&gt;        NUMERALS.each do |value, numeral|&lt;br /&gt;            number = roman_reduce(number, numeral)&lt;br /&gt;            number = roman_reduce(number, numeral.difference) if numeral.difference&lt;br /&gt;        end&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    def roman_reduce(number, numeral)&lt;br /&gt;        while number &gt;= numeral.arabic&lt;br /&gt;            @result += numeral.roman&lt;br /&gt;            number -= numeral.arabic&lt;br /&gt;        end &lt;br /&gt;        number&lt;br /&gt;    end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now it is obvious that we are subtracting the subtrahend from the minuend in order to ascertain the difference. Right?&lt;br /&gt;&lt;br /&gt;Right?&lt;br /&gt;&lt;br /&gt;Damn. Still doesn't &lt;em&gt;"feel"&lt;/em&gt; right.&lt;br /&gt;&lt;br /&gt;I'm trying it again. Stay tuned.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-2005669749730531565?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/2005669749730531565/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2011/12/roman-numeral-kata.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/2005669749730531565'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/2005669749730531565'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2011/12/roman-numeral-kata.html' title='Roman Numeral Kata'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-1548895601276521300</id><published>2011-11-18T16:44:00.001-05:00</published><updated>2011-11-19T11:08:27.935-05:00</updated><title type='text'>SCNA 2011 Apprenticeship Panel</title><content type='html'>This year, at SCNA 2011, I had the honor of moderating a panel on apprenticeship. I was lucky enough to get participation commitments from an impressive list of individuals. I feared I would not be able to get a decent panel together and instead, I had to pare the panel from a list of eleven amazing people down to just six.&lt;br /&gt;&lt;br /&gt;I want to thank all of the folks who agreed to participate; &lt;a href="http://twitter.com/#!/shayarnett" target="_blank"&gt;Shay Arnett&lt;/a&gt;, &lt;a href="http://twitter.com/#!/kauerrolemodel" target="_blank"&gt;Ken Auer&lt;/a&gt;, &lt;a href="http://twitter.com/#!/david_j_crosby" target="_blank"&gt;David Crosby&lt;/a&gt;, &lt;a href="http://twitter.com/#!/zachdennis" target="_blank"&gt;Zach Dennis&lt;/a&gt;, &lt;a href="http://twitter.com/#!/jgehtland" target="_blank"&gt;Justin Ghetland&lt;/a&gt;, &lt;a href="http://twitter.com/#!/coreyhaines" target="_blank"&gt;Corey Haines&lt;/a&gt;, &lt;a href="http://twitter.com/#!/redsquirrel" target="_blank"&gt;Dave Hoover&lt;/a&gt;, &lt;a href="http://twitter.com/#!/slagyr" target="_blank"&gt;Micah Martin&lt;/a&gt;, &lt;a href="http://twitter.com/#!/unclebobmartin" target="_blank"&gt;Robert Martin&lt;/a&gt;, &lt;a href="http://twitter.com/#!/donmullen" target="_blank"&gt;Don Mullen&lt;/a&gt;, and &lt;a href="http://twitter.com/#!/mattyoho" target="_blank"&gt;Matt Yoho&lt;/a&gt;. Your commitment to furthering our profession is inspirational.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Audience Participation&lt;/h3&gt;We wanted to make sure we got participation from the audience, but also wanted to keep the discussion moving as quickly as possible. We decided to have the audience tweet questions with the #scnapanel hash tag rather than deal with the logistics of getting microphones to the audience or having to repeat every question asked.&lt;br /&gt;&lt;br /&gt;As it turned out, this was a fantastic method. Questions that interested several people were retweeted, pushing them back to the top of the queue and I was able to hunt through the questions looking for common themes. This also allowed us to continue the conversation well beyond the panel. Dave Hoover and Ken Auer took the time to answer questions via twitter later that afternoon.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The Questions&lt;/h3&gt;As I mentioned, there were a lot of tweets in a relatively short period of time. We had over 300 tweets on the topic with more than 200 of them coming in during the live session.&lt;br /&gt;&lt;br /&gt;There were a few common themes; how to select an apprentice, what makes for a good program, and how to get a program started. I've made the entire &lt;a href="http://dl.dropbox.com/u/11131130/SCNA-Apprenticeship-Panel-Questions.pdf" target="_blank"&gt;apprenticeship panel tweet stream&lt;/a&gt; available. The following are a few example questions.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;What are the factors you take into consideration when building your apprenticeship curriculum?&lt;/li&gt;&lt;li&gt;what is the worst mistake you made as a mentor or in your program ?&lt;/li&gt;&lt;li&gt;does someone ever stop being an apprentice?&lt;/li&gt;&lt;li&gt;Any formal milestones in your apprenticeship programs? Complete a project, etc.&lt;/li&gt;&lt;li&gt;Do you also do apprenticeship with existing employees (developers) that might need more training to reach "the next level"?&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Continuing the Conversation&lt;/h3&gt;I think apprenticeship is a valuable and important undertaking. If the name "apprentice" does not resonate with you, then call it something else. The assigned label is the least important aspect of growing and nurturing our next generations. I invite you to join the &lt;a href="http://groups.google.com/group/software_craftsmanship" target="_blank"&gt;Software Craftsmanship google group&lt;/a&gt; and &lt;a href="http://groups.google.com/group/software_craftsmanship/browse_thread/thread/67ddf2f17370ba9f" target="_blank"&gt;engage in the discussion&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-1548895601276521300?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/1548895601276521300/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2011/11/scna-2011-apprenticeship-panel.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/1548895601276521300'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/1548895601276521300'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2011/11/scna-2011-apprenticeship-panel.html' title='SCNA 2011 Apprenticeship Panel'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-7428850878329845636</id><published>2011-08-21T20:31:00.001-04:00</published><updated>2011-08-21T20:46:45.717-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Coaching'/><category scheme='http://www.blogger.com/atom/ns#' term='Teams'/><category scheme='http://www.blogger.com/atom/ns#' term='How To'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Retrospectives'/><title type='text'>Fighting Entropy</title><content type='html'>It was 1983 and I was in science class when I first heard the term entropy. &lt;img border="0" height="100" src="http://4.bp.blogspot.com/-FNQNuDdIiSo/TlGbA571HcI/AAAAAAAAAKQ/6PnUiPQj5o0/s320/entropy.gif" align="right" hspace="10" vspace="10" /&gt; I don't recall if we were discussing energy conversion, heat as waste, or some other topic wherein entropy plays a part, but I do recall how profound the concept of entropy seemed to me. The notion that there was a lack of order, a lack of predictability, and a gradual decline into disorder resonated with me deeply.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Entropy is the state of existence&lt;/h3&gt;I long attributed the phrase "entropy is the state of existence" to my science teacher. Looking back, I suspect that I either misunderstood him or made it up myself, but in any case, the phrase stuck with me and I use it to this day.&lt;br /&gt;&lt;br /&gt;For me, entropy is not a fatalistic notion, rather a reminder that all things need tended. &lt;blockquote class="left_callout"&gt;It requires the application of new energy to keep a system at status quo&lt;/blockquote&gt;Disorder is natural and all systems, left un-tended, eventually fall apart. It requires the application of new energy to keep a system at status quo. Our desire to change nothing in order to keep things as they are is unrequited. We must change in order to stay the same.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Entropy and Process&lt;/h3&gt;No matter how well your process works today, I can promise you, left unchecked, it will eventually fail to deliver the results it once did. I believe there to be two primary reasons for this. First is that the process in-deliberately changes over time. Second is that our needs for process change as our project evolves and our team matures.&lt;br /&gt;&lt;br /&gt;&lt;blockquote class="right_callout"&gt;The process in-deliberately changes over time&lt;/blockquote&gt;How many of you have been on a team with stale stand-ups? The format hasn't changed. The participants haven't changed. And yet the value isn't what it once was. We stick to the process and try to recapture the magic.&lt;br /&gt;&lt;br /&gt;How many of you have participated in a process that doesn't seem to make sense anymore? When the team started working together, no one knew the system well and there were lengthy debates over what &lt;i&gt;might&lt;/i&gt; be true. The code might be complex or poorly covered. It might not.&lt;blockquote class="left_callout"&gt;Our needs for process change over time&lt;/blockquote&gt;Estimating sessions took forever. So management put a silent estimating process in place. This allowed the team to get through estimating sessions quickly. Six months later, everyone had solid experience with the code and was able to articulate real concerns, but the process didn't allow for it. No worries, the process served them well this far; it must be right.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Inspect and Adapt&lt;/h3&gt;As a runner, I train regularly in order to maintain my current level of fitness. &lt;img border="0" height="160" src="http://2.bp.blogspot.com/-CSL0WSEcdj8/TlGcvYMpFwI/AAAAAAAAAKY/5KGVD90NHMg/s320/n522273860_782833_5796.jpg" align="right" hspace="10" vspace="10" /&gt; I vary my training to ensure balance. It requires effort simply to stay the same. And if I want to improve, I must assess my current status, evaluate where improvement is needed, and adjust my training accordingly. If I need to build strength, I work in more hills. If I need to improve my speed, I focus on track work. I monitor my progress to ensure I'm getting the desired results. Pain, fatigue, faster times, improved strength, and no perceivable change are all valuable pieces of information that help me determine if what I am doing is working and what other adjustments need to be made. Invariably, when I stop paying attention, I end up with an injury.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Enter the Retrospective&lt;/h3&gt;Retrospectives are the one practice I feel are an absolute must for teams; agile or otherwise. Remember, entropy is the state of existence. It requires the application of new energy to keep a system at status quo. A regular dialogue about what is working, what is not, and what we plan to change is paramount to simple survival. Without it, entropy wins.&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-7428850878329845636?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/7428850878329845636/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2011/08/fighting-entropy.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7428850878329845636'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7428850878329845636'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2011/08/fighting-entropy.html' title='Fighting Entropy'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-FNQNuDdIiSo/TlGbA571HcI/AAAAAAAAAKQ/6PnUiPQj5o0/s72-c/entropy.gif' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-3279882171517731258</id><published>2011-05-24T16:15:00.002-04:00</published><updated>2011-05-25T11:12:30.182-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Teams'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><category scheme='http://www.blogger.com/atom/ns#' term='How To'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><title type='text'>Estimating our Work</title><content type='html'>I've been thinking quite a bit about estimations and our general obsession with getting them "right". After all, we need to know when the project will be done. And we need accuracy. Knowing the entire project will be done before the end of the third quarter isn't good enough. We need to know that the project will be done this month or this week or perhaps even on this specific day.&lt;br /&gt;&lt;br /&gt;&lt;blockquote class="right_callout"&gt;Through consistency, we attempt to achieve predictability.&lt;/blockquote&gt;I've watched teams put a great deal of effort into improving their estimates. I've seen teams compare stories from this sprint to stories from prior sprints to try to maintain consistency. I've seen teams use a reference story for a single point. When estimating, they look at the reference story and then estimate all others compared to it. These seem like decent practices. The goal of these practices is consistency. Through consistency, we attempt to achieve predictability.&lt;br /&gt;&lt;br /&gt;But one thing I've never understood is the notion of estimates versus actuals. Here we look at the original estimate for a story and we then estimate again once the story is complete. The idea here is that the estimate upon completion is an actual. This provides us a learning opportunity whereby we can improve our estimates going forward. This, to me, is a flawed approach. To illustrate my point, let's look at estimations from a slightly different angle.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Estimating Sudoku&lt;/h3&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;Indulge me for a bit here. Writing code is really problem solving. Sudoku is (clearly) problem solving. Admittedly, sudoku is far more simple than writing code. Simple in terms of strictly constrained and with very few possible solutions (often one solution). If we can agree that sudoku can serve as a simple model for writing code, then please do read on.&lt;br /&gt;&lt;br /&gt;I have a sudoku game on my phone. It breaks the games down into four categories; easy, medium, hard, and expert. Clearly, the games are all on the same size grid with the exact same rules. The difference between these games is merely the number of seeded answers and their locations on the board. These two factors make a game more or less difficult to solve. I don't know that a medium is twice as difficult as an easy, but I am certain that a medium is more difficult than an easy.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Actuals&lt;/h4&gt;I've played hundreds of sudoku games on my phone. I've played each level of difficulty at least 50 times. And the game has tracked my actual time to complete for every play. The following graph shows the time to complete for 40 games at each skill level. The y-axis is the time to complete. The x-axis is the number of games.&lt;br /&gt;&lt;img border="0" height="317" width="400" src="http://1.bp.blogspot.com/-99fN-R0kmw0/Tdv99cbmmeI/AAAAAAAAAGw/zQKt31bLYs4/s400/sudoku.png" align="right" /&gt;&lt;br /&gt;At point 6 on the x axis, the easy story takes nearly 8 minutes to complete. This is well outside the normal effort for an easy. In fact, it exceeds the average for a medium. After completion of this puzzle, were you to have asked me, I might have concluded that it was actually a medium or even a hard. But the truth is, it was an easy. For some reason, I struggled to solve it. Maybe I missed a subtle clue. Maybe I made a mistake that sent me down a wrong path for quite a while. I honestly don't recall. But the amount of effort it took me to determine the solution does not change the quality of the puzzle itself.&lt;br /&gt;&lt;br /&gt;&lt;blockquote class="right_callout"&gt;It didn't become an easy puzzle just because I found it easy to solve.&lt;/blockquote&gt;Similarly, there are a number of times where I managed to complete expert puzzles in times consistent with a medium or even an easy. Again, this does not change the fact that the puzzle was an expert level puzzle. It didn't become an easy puzzle just because I found it easy to solve.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Back to software&lt;/h3&gt;Looking at the variance in simple sudoku puzzles, I hope we can agree the same kind of variance is perfectly reasonable in software development. An estimate of 1 point indicates the team agrees this is a story of relatively low complexity and that it is similar in complexity to other stories that we previously agreed were also 1 point. An estimate of 1 point does not directly indicate that it will take a specific amount of time (or less). An estimate of 1 point does not necessarily indicate that it will be faster to complete than a 2 point or 3 point story. On average, a 1 point story will be completed in less time than a 2 or 3. On average.&lt;br /&gt;&lt;br /&gt;&lt;blockquote class="right_callout"&gt;A 3 point story doesn't become a 1 point story just because you completed it quickly.&lt;/blockquote&gt;There are times when a story changes. Say certain requirements are dropped or we discover that we'd already written some of the code months ago. I am sure there are other reasons. But just because a story took longer or shorter than the average time to complete similarly sized stories does not mean the story was improperly sized. A 3 point story doesn't become a 1 point story just because you completed it quickly.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;It's All Relative&lt;/h3&gt;I recommend you use a reference story. Identify a story that the entire team can agree is 1 point. When you are estimating, keep that story in mind and attempt to estimate all others relative to it. Then, at the end of the estimating session, compare the stories to one another. Do the points still feel right? Compare the stories to random selections from prior iterations? Do the points still feel right? If not, make adjustments to your new estimates as necessary.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-3279882171517731258?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/3279882171517731258/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2011/05/estimating-our-work.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/3279882171517731258'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/3279882171517731258'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2011/05/estimating-our-work.html' title='Estimating our Work'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-99fN-R0kmw0/Tdv99cbmmeI/AAAAAAAAAGw/zQKt31bLYs4/s72-c/sudoku.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-8349380501015914580</id><published>2011-04-06T06:49:00.001-04:00</published><updated>2011-04-06T06:59:05.219-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Coaching'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Technical Debt'/><title type='text'>"Necessary" Refactoring</title><content type='html'>In a discussion on the Agile Alliance Linked In Group, &lt;a href="http://lnkd.in/wf3zq3" target="_blank"&gt;Michael Moles asked how refactoring fit into the agile process&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The Question&lt;/h3&gt;&lt;h4&gt;Refactoring: How does it fit into your Agile process?&lt;/h4&gt;We are in the midst of writing a new product, at this point the developers are realizing that some of the code should be refactored to improve performance and or clarity for ease of use. How do you fit refactoring into you Agile process? We have created separate backlog items for refactoring specific pieces of code. These backlog items are treated exactly like any other backlog item (meaning they have effort assigned and are committed to sprints by the team). What do you do when refactoring is necessary? &lt;br /&gt;&lt;br /&gt;- Mike&lt;br /&gt;&lt;h3&gt;General Consensus&lt;/h3&gt;Most folks (myself included) didn't really answer Mike's question. He wants to know how you schedule refactoring when it becomes necessary. But the general consensus seems to be that refactoring is necessary and should not be scheduled. Instead, it should happen as needed.&lt;br /&gt;&lt;h3&gt;My Answer&lt;/h3&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;In my mind, there are two types of refactoring; real-time and planned. In each case, we are changing the implementation without altering behavior. In each case, we need comprehensive test coverage. Without tests, we don't know for certain if we've altered behavior or not. &lt;br /&gt;&lt;br /&gt;Real-time refactoring is a great behavior to cultivate. It is a natural part of the TDD flow. Red =&gt; Green =&gt; Refactor. We are continually looking for small ways to improve the code; rename a variable, extract methods to create a composite method, generally make the code readable, DRY, and well composed. &lt;br /&gt;&lt;br /&gt;Planned refactorings tend to be larger chunks. We've realized the need create a base class and derive from it rather than have this complex conditional. We see now that we have a lot of responsibility in the wrong place and need to re-work a section of the code to reduce coupling. &lt;br /&gt;&lt;br /&gt;Following TDD practices, we tend to have more real-time refactoring and less planned. This is good. It means the code is generally better composed. We are keeping it clean as we go along rather than letting it get bad and then asking for permission to clean it up. &lt;br /&gt;&lt;br /&gt;Many agile teams adopt the practices of TDD and ATDD to ensure they can deliver working software and respond to change. For those teams, refactoring is a given.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-8349380501015914580?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/8349380501015914580/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2011/04/necessary-refactoring.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/8349380501015914580'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/8349380501015914580'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2011/04/necessary-refactoring.html' title='&quot;Necessary&quot; Refactoring'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-7729750811655785381</id><published>2011-03-15T17:44:00.000-04:00</published><updated>2011-03-15T17:44:37.088-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Manager'/><category scheme='http://www.blogger.com/atom/ns#' term='Coaching'/><category scheme='http://www.blogger.com/atom/ns#' term='Teams'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><title type='text'>Values and Beliefs</title><content type='html'>Earlier this week, Bob Marshall (&lt;a href="http://twitter.com/flowchainsensei" target="_blank"&gt;@flowchainsensei&lt;/a&gt;) &lt;a href="http://twitter.com/greatleadership/status/46897101363347456" target="_blank"&gt;retweeted&lt;/a&gt; an article by Dan McCarthy on &lt;a href="http://www.greatleadershipbydan.com/2011/03/meaning-of-respect.html" target="_blank"&gt;The Meaning of Respect&lt;/a&gt;, where he discussed respect as a value. I then saw a blog post from Seth Godin entitled "&lt;a href="http://sethgodin.typepad.com/seths_blog/2011/03/seven-questions-for-leaders.html" target="_blank"&gt;Seven Questions for Leaders&lt;/a&gt;" where he asks if you would walk away from a client or employee whose values don't match yours. This weekend, at &lt;a href="http://agileandbeyond.org/" target="_blank"&gt;Agile and Beyond&lt;/a&gt;, I got into a conversation with several others about company values and walking away from clients when there is a mis-match. At &lt;a href="http://www.leandog.com/"&gt;LeanDog&lt;/a&gt;, we proudly display our &lt;a href="http://www.leandog.com/who-we-are/" target="_blank"&gt;company values&lt;/a&gt; and we often refer to the &lt;a href="http://www.extremeprogramming.org/values.html" target="_blank"&gt;XP values&lt;/a&gt; of Simplicity, Communication, Feedback, Respect, and Courage.&lt;br /&gt;&lt;br /&gt;I've long held the perspective that shared values is an insufficient basis for determining if two parties are compatible. In fact, it can be downright misleading.&lt;br /&gt;&lt;br /&gt;Our beliefs are a better test, but often more difficult to identify.&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;h3&gt;Family First&lt;/h3&gt;Before they were married, Tom and Janet had several late night discussions about what their future would look like. They agreed they wanted children and above all else, family had to come first. "Family First" became a mantra in the early years of their marriage. They both worked hard and rather than taking vacations, they saved and invested, waiting for the day they had their first child.&lt;br /&gt;&lt;br /&gt;With the arrival of Jacob, their first baby, they talked and agreed that Tom would quit work to take care of the household while Janet continued to work. Janet had a more significant income and a better benefits program. This was a simple decision for the two of them. "Family First".&lt;br /&gt;&lt;br /&gt;But shortly after the baby arrived and Janet returned to work, things started to take a turn. Tom found himself and the baby eating dinner without mom as she worked extra hours. Janet often brought work home and while she spent some time with the little one, much of her time at home was dedicated to work.&lt;br /&gt;&lt;br /&gt;The strain took its toll and Janet and Tom found themselves arguing over petty things. The months passed and the resentment built.&lt;br /&gt;&lt;br /&gt;One evening, after a particularly trying day, Tom sat down to relax for a moment with Janet before bed. She had her laptop open and was instant messaging with someone from work.&lt;br /&gt;&lt;br /&gt;"You know", Tom blurted, "you say 'family first', but you're never here. Even when you are here, you're not here."&lt;br /&gt;&lt;br /&gt;"How dare, you?", Janet responded, "I work for the family. I make money for the family. Everything I do is for the family! How can you possibly say I don't put family first after all the sacrifices I've made?"&lt;br /&gt;&lt;br /&gt;"Sacrifices? Sacrifices? You're never here. You don't clean up the mess. You don't do the laundry! You don't do anything for the family, except help put Jacob to bed and put a check in the bank. I have to do it all."&lt;br /&gt;&lt;br /&gt;"Of course I put a check in the bank! You don't work at all. You haven't even picked up a part-time job. You won't even consider putting Jacob into day care a couple days per week to help with all of this pressure. I have to do it all."&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Shared Values&lt;/h4&gt;Tom and Janet agree on the value of "Family First". Neither of them is lying about that. Both of them are living those values. So how is it that it has come to this even before Jacob's second birthday?&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Differing Beliefs&lt;/h4&gt;Tom believes that "Family First" means you spend time with the family. Play time, limited work hours, keeping the home, educating your children, and just being a supportive family to your children. Tom has made great sacrifices to live true to his values and he wants Janet to do the same.&lt;br /&gt;&lt;br /&gt;Janet believes that "Family First" means supporting the family. Doing what it takes to provide them with the best schools, making sure they are provided healthy foods, providing a safe house, offering them a promising future, and being a support system for your children. Janet has made great sacrifices to live true to her values and she wants Tom to do the same.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Beliefs are held to be true&lt;/h3&gt;The boiling point of water is 100 °C (212 °F) at standard pressure. This is a fact. It is true.&lt;br /&gt;&lt;br /&gt;Good parents spend ample quality time with their children. This is a belief. It is often held to be true, but that does not make it a fact.&lt;br /&gt;&lt;br /&gt;We evaluate the behaviors of others by contrasting them with our values and beliefs. When someone says they share our values, we expect they will behave in a congruent manner. But that manner is shaped by our beliefs. Beliefs which they unlikely hold in the same degree and manner.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Consider your own beliefs&lt;/h4&gt;Do they serve you well? Are they moving you toward or away from the things you hope to achieve? Why do you hold these beliefs? Could you change them?&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Consider the beliefs of others&lt;/h4&gt;Do you know what they are? Can you accept them as valid from that individual's perspective? Does understanding a person at this level help you to better communicate with them? Better understand them? Better love them for who they are and not for who you want them to be?&lt;br /&gt;&lt;br /&gt;I think so.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-7729750811655785381?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/7729750811655785381/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2011/03/values-and-beliefs.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7729750811655785381'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7729750811655785381'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2011/03/values-and-beliefs.html' title='Values and Beliefs'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-1310972924429400194</id><published>2011-03-10T09:30:00.000-05:00</published><updated>2011-03-10T09:30:37.531-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Coaching'/><category scheme='http://www.blogger.com/atom/ns#' term='Teams'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><category scheme='http://www.blogger.com/atom/ns#' term='How To'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><title type='text'>Stabilizing Velocity</title><content type='html'>Have you ever been on a team where your velocity suffered wild variances? Maybe you ended up using a running average instead of yesterday's weather?&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-8ALTQmk8ZpA/TW7airywvfI/AAAAAAAAAF0/7y_psho0Cs8/s1600/Screen%2Bshot%2B2011-03-02%2Bat%2B6.48.47%2BPM.png" imageanchor="1" style="clear:right; float:right; margin-left:1em; margin-bottom:1em"&gt;&lt;img border="0" width="280" src="http://3.bp.blogspot.com/-8ALTQmk8ZpA/TW7airywvfI/AAAAAAAAAF0/7y_psho0Cs8/s320/Screen%2Bshot%2B2011-03-02%2Bat%2B6.48.47%2BPM.png" /&gt;&lt;/a&gt;&lt;/div&gt;Have you heard phrases like, "Well, our velocity last iteration was 3, but our average is still 22"?&lt;br /&gt;&lt;br /&gt;Have you ever heard the phrase, "Dude, we need to get this velocity stable."&lt;br /&gt;&lt;br /&gt;Have you worked on teams where they took partial credit for done at the end of the iteration? Where maybe you'd split a card strictly on points and award some apportion to the current iteration and assign the remainder of the card to the next iteration.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Velocity should stabilize&lt;/h3&gt;It seems much of what we read tells us that velocity will do two things; stabilize and improve. According to the VersionOne Agile 101, &lt;a href="http://www.versionone.com/Agile101/velocity.asp" target="_blank"&gt;we can expect that velocity will stabilize within three to six months&lt;/a&gt;. The Agile Sherpa tells us &lt;a href="http://www.agilesherpa.org/agile_coach/metrics/velocity/" target="_blank"&gt;it usually takes 3-4 iterations for velocity to stabilize at a consistent level&lt;/a&gt;. James Shore's "The Art of Agile" tells us to &lt;a href="http://books.google.com/books?id=g_ji7cRb--UC&amp;pg=PA264&amp;lpg=PA264&amp;dq=stabilize+agile+velocity&amp;source=bl&amp;ots=vlQBwoSB9v&amp;sig=p2q7u9ohmQud_JsvTFID2vHMhic&amp;hl=en&amp;ei=A1RtTZrjEMjZgQfg3KSHBA&amp;sa=X&amp;oi=book_result&amp;ct=result&amp;resnum=7&amp;ved=0CD4Q6AEwBg#v=onepage&amp;q&amp;f=false" target="_blank"&gt;give it three or four iterations to stabilize&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;But what if velocity doesn't stabilize?&lt;/h3&gt;First, take a deep breath; and then repeat after me:&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;blockquote class="right_callout"&gt;If you have an erratic velocity, it is telling you of a problem. And your problem is not an erratic velocity.&lt;/blockquote&gt;"Velocity is a health indicator. Velocity is a health indicator. Velocity is a health indicator. Velocity is ..."&lt;br /&gt;&lt;br /&gt;Velocity lets us know how things are going. It reveals issues to us in sometimes subtle ways.&lt;br /&gt;&lt;br /&gt;Think of velocity as heart rate. An abnormal heart rate, be it too fast, too slow, or irregular can indicate a number of underlying issues such as electrolyte imbalance, overstimulation, insufficient rest, autoimmune disorders, thyroid problems, or various forms of heart disease. If you have an abnormal heart rate, it is telling you of a problem. And your problem is not an abnormal heart rate.&lt;br /&gt;&lt;br /&gt;An erratic velocity can indicate a number of underlying issues such as poor story composition, dependencies on other teams or individuals, too much work in progress, silos, and various forms of mismanagement. If you have an erratic velocity, it is telling you of a problem. And your problem is not an erratic velocity.&lt;br /&gt;&lt;br /&gt;Whatever the underlying problem, it is something you can adjust. Adjustments for which you can observe the outcome. But the important thing to remember is that the velocity is not the problem. Do &lt;strong&gt;&lt;em&gt;not&lt;/em&gt;&lt;/strong&gt; try to fix the velocity. Try to figure out what it is telling you and fix that.&lt;br /&gt;&lt;h3&gt;What should I adjust?&lt;/h3&gt;&lt;blockquote class="right_callout"&gt;...poor story composition, dependencies on other teams or individuals, too much work in progress, silos, and various forms of mismanagement.&lt;/blockquote&gt;If an erratic velocity could be telling me any number of things, then how do I know what to adjust? Ask your team. They probably know. They may not know they know, but they can give you indicators.&lt;br /&gt;&lt;br /&gt;Let's look through some of the common underlying causes.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Poor story composition&lt;/h4&gt;By story composition, I mean story size and dependencies. &lt;a href="http://www.agileproductdesign.com/blog/the_shrinking_story.html" imageanchor="1" style="clear:left; float:left;margin-right:1em; margin-top:1em; margin-bottom:1em" target="_blank"&gt;&lt;img border="0" height="80" src="http://www.agileproductdesign.com/blog/images/mini_me.jpg" /&gt;&lt;/a&gt;The larger the story, the more risk there is of getting it to done. But it is not just about making stories small. It is about making them small and independent. Small stories that cannot be delivered independent of one another are really just tasks for a large story.&lt;br /&gt;&lt;br /&gt;If we have an issue with proper story composition, we may find we get several stories close to done, but we cannot run acceptance tests on them until all of them are complete, leaving us with too much testing at the end of the iteration. It we don't get all of the stories ready, none of them can move. Then, next iteration, we complete the last strays and a glut of cards/points move to done. Alternatively, some stories are just too big to complete in a single iteration.&lt;br /&gt;&lt;br /&gt;Mike Cohn has a number of good resources on &lt;a href="http://www.mountaingoatsoftware.com/presentations/103-effective-user-stories" target="_blank"&gt;creating user stories&lt;/a&gt;. &lt;a href="http://www.w3.org/2004/10/RecsFigure-Smaller.png" imageanchor="1" style="clear:right; float:right; margin-left:1em; margin-bottom:1em"&gt;&lt;img border="0" width="150" src="http://www.w3.org/2004/10/RecsFigure-Smaller.png" /&gt;&lt;/a&gt;There is no need to get your stories perfect up front. Get them good enough to do a high-level estimate; think epics. Then as you start planning releases, break them down into features to get a finer-course estimate. Finally, as you plan iterations, break them down again into small, independently deliverable items. Beware the temptation to split stories across technical seams. Instead, focus on small stories that are thin vertical slices through the technology stack.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Dependencies on other teams or individuals&lt;/h4&gt;&lt;img border="0" align="left" height="119" src="http://4.bp.blogspot.com/-ousbHhIgUI8/TXP5qni8DgI/AAAAAAAAAF8/am3aOXNnUlg/s200/dependent.jpg" /&gt;Perhaps your product owner is not available often enough and there is too much re-work due to slow feedback cycles. Maybe you haven't rights to your various environments and code migrations are executed in durations of days rather than minutes. It's possible some other technical team is not able to be as responsive or relies on process more than interactions for the exchange of information. Whatever it might be, any point where you need to wait for extended periods of time, is likely to lead to other problems. You can't sit idle, so you grab another card to work on, leading to too much work in progress.&lt;br /&gt;&lt;br /&gt;Work with these teams and individuals on ways to automate processes or find other ways to reduce their response time. Invite sponsors and others to your stand-ups, iteration planning, and retrospectives. If they consistently don't show, see if you can get another representative. Be professional and courteous, but there is no need to be completely deferent. If the project is important, you should be able to ask for the necessary support.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Too much work in progress&lt;/h4&gt;This is a remarkably common issue. In my experience, management often encourages this behavior. I don't know if it is the notion that we will get more done if we work on more things simultaneously. Or perhaps there is a fear we won't get enough things done unless we work on several of them at once.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.amazon.com/Myth-Multitasking-Doing-Gets-Nothing/dp/0470372257/ref=sr_1_1?ie=UTF8&amp;s=books&amp;qid=1299760242&amp;sr=1-1" style="clear:left; float:left;margin-right:1em; margin-bottom:1em"&gt;&lt;img border="0" width="186" src="http://4.bp.blogspot.com/-Mk9-Cp9OnXk/TXjEN8xuBQI/AAAAAAAAAGM/kocCn_PAtZw/s320/myth-of-multitasking-cover.jpg" /&gt;&lt;/a&gt;But what happens when we try to work on a few stories each? Remarkably, we make progress on several, but complete precious few. The more work in flow, the more context switching we all need to make. Coordination of the stories complicates testing and migrations. We look busy, but at the end of the iteration, we've fewer things complete. Then, at the beginning of the next iteration, a glut of work moves to done, setting us up with a couple day delay wrapping up the prior iteration and pushing us into yet another complicated cycle.&lt;br /&gt;&lt;br /&gt;Drive each card to completion before picking up the next one. If a card is blocked, make getting it un-blocked a priority rather than letting it wait three days because George on the DBA team has a three-day SLA.&lt;br /&gt;&lt;h4&gt;Silos&lt;/h4&gt;Most teams I work with have three distinct roles; BA, Developer, and QA. Most teams I work with have three distinct phases of their work; gather requirements, build, verify. Even on agile teams, these separations exist. There are clear delineations in the process and clear segregation of responsibilities. But this segregation is a contributor to erratic velocity. How many "agile" teams do you know of where the BA group is an iteration ahead of the developers who are an iteration ahead of QA, leaving us with a three-iteration cycle time and significant lag in our feedback loops between the groups?&lt;br /&gt;&lt;br /&gt;Tighten the loops. Get people working together in not only close proximity, but close time-frame. Involve the developers and QA in the formation of requirements. Push QA to the front and automate, automate, automate. Don't let manual testing be a bottle neck. Start development before you've polished the requirements. And don't wait until the end to test it all comprehensively.&lt;br /&gt;&lt;h4&gt;Various Forms of Mismanagement&lt;/h4&gt;Herein lies my primary onus for the mantra, "Agile ain't practices". Agile is a set of values.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align:center"&gt;&lt;strong&gt;&lt;span style="font-size: larger"&gt;Individuals and interactions&lt;/span&gt;&lt;/strong&gt; over processes and tools&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size: larger"&gt;Working software&lt;/span&gt;&lt;/strong&gt; over comprehensive documentation&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size: larger"&gt;Customer collaboration&lt;/span&gt;&lt;/strong&gt; over contract negotiation&lt;br /&gt;&lt;strong&gt;&lt;span style="font-size: larger"&gt;Responding to change&lt;/span&gt;&lt;/strong&gt; over following a plan&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;blockquote class="right_callout"&gt;Address the actual problem and use velocity to tell you if you have, in fact, done so.&lt;/blockquote&gt;I see organization after organization pick up practices in the name of agile and apply them devoid of the values. Most popular seems to be daily stand-ups and burn-down charts; two tools that provide project management quick feedback on status so that they can make informed decisions about items such as task assignment or if the team needs to put in extra hours to make the deadline. (By the way, that sentence should make you cringe)&lt;br /&gt;&lt;br /&gt;Assigning tasks, driving for excellence in estimating, pushing for points, treating code as if it is only a means to an end, role-based incentives, making the team's decisions for them, leaving the team to make all the decisions (they are self-organizing after all), splitting people's assignment across teams (they only need 1.5 QA), burdensome process, and failure to address impediments are but a few examples of mismanagement.&lt;br /&gt;&lt;h3&gt;Don't mess with the math&lt;/h3&gt;&lt;a href="http://1.bp.blogspot.com/-sKzNR8DJIbA/TXi8hP8yO6I/AAAAAAAAAGE/fttDt2bdIUc/s1600/Screen%2Bshot%2B2011-03-02%2Bat%2B7.00.22%2BPM.png" imageanchor="1" style="clear:right; float:right; margin-left:1em; margin-bottom:1em"&gt;&lt;img border="0" height="187" width="320" src="http://1.bp.blogspot.com/-sKzNR8DJIbA/TXi8hP8yO6I/AAAAAAAAAGE/fttDt2bdIUc/s320/Screen%2Bshot%2B2011-03-02%2Bat%2B7.00.22%2BPM.png" /&gt;&lt;/a&gt;Don't split cards on points and award some apportion to the current iteration and assign the remainder of the card to the next iteration. I am confident this will normalize your velocity. Much like taking cough medicine subdues your cough. Neither of them cures the real problem. They merely hide the symptoms in hopes the real problem will run its course. Erratic velocity is the result of issues that, left unaddressed, are highly unlikely to run their course.&lt;br /&gt;&lt;br /&gt;Address the actual problem and use velocity to tell you if you have, in fact, done so.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-1310972924429400194?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/1310972924429400194/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2011/03/stabilizing-velocity.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/1310972924429400194'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/1310972924429400194'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2011/03/stabilizing-velocity.html' title='Stabilizing Velocity'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-8ALTQmk8ZpA/TW7airywvfI/AAAAAAAAAF0/7y_psho0Cs8/s72-c/Screen%2Bshot%2B2011-03-02%2Bat%2B6.48.47%2BPM.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-2604067646842425983</id><published>2011-02-26T15:31:00.002-05:00</published><updated>2011-02-27T17:33:06.402-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='How To'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Open iTerm Here</title><content type='html'>I've been using iTerm for over a year now. I like it over Terminal for a few reasons, but primarily because it supports multiple frames. This makes my workflow easier as I can see everything on a single screen and can easily navigate from one frame to the other without reaching for the mouse. I've additionally abandoned MacVim for Vim. Now, I can do most everything I need in a single, maximized, iTerm window. But I get annoyed with opening iTerm and having to navigate to the directory of my current desire. Most of the time, I am already browsing the desired directory in Finder as I begin a hacking session.&lt;br /&gt;&lt;br /&gt;What is a guy to do?&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;AppleScript to the rescue&lt;/h3&gt;I created an AppleScript app based on work from a couple of other folks, whom I've given attribution. The AppleScript launches iTerm and changes to whatever directory was active in Finder. If iTerm is running, the script opens a new terminal. If iTerm is not running, the script launches it and changes directories accordingly.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.flickr.com/photos/docondev/5479335031/" title="Screen shot 2011-02-26 at 3.24.41 PM by Doc.On.Dev, on Flickr"&gt;&lt;img src="http://farm6.static.flickr.com/5216/5479335031_e6beb4d233.jpg" width="500" height="65" alt="Screen shot 2011-02-26 at 3.24.41 PM" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/845541.js"&gt; &lt;/script&gt;&lt;br /&gt;&lt;br /&gt;You can use the script for yourself. &lt;br /&gt;&lt;ol&gt;&lt;li&gt;Paste it into the Script Editor application and save it as an application&lt;/li&gt;&lt;li&gt;In Finder, navigate to the application and drag it to the Finder bar&lt;/li&gt;&lt;li&gt;You can now click the button and it will open the foremost directory in Finder&lt;/li&gt;&lt;li&gt;Or you can drag and drop folders onto the icon&lt;/li&gt;&lt;li&gt;Locate iTerm and Select the More Info... button&lt;/li&gt;&lt;li&gt;Locate your new app and Select the More Info... button&lt;/li&gt;&lt;li&gt;Copy the small icon from the top-left of the iTem Info window&lt;/li&gt;&lt;li&gt;Paste it onto the small icon of your app's Info Window&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-2604067646842425983?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/2604067646842425983/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2011/02/open-iterm-here.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/2604067646842425983'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/2604067646842425983'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2011/02/open-iterm-here.html' title='Open iTerm Here'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://farm6.static.flickr.com/5216/5479335031_e6beb4d233_t.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-4993798354470404667</id><published>2011-02-14T11:00:00.002-05:00</published><updated>2011-02-14T12:29:44.850-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Teams'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><category scheme='http://www.blogger.com/atom/ns#' term='How To'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><title type='text'>Telling the complete story</title><content type='html'>&lt;h3&gt;Decomposing the story format&lt;/h3&gt;Working with several clients, I see differing story formats. The format I see&amp;nbsp;most recommended&amp;nbsp;is "As a, I want, So that". &amp;nbsp;The format I see most utilized is "I want". Isn't this the important part of the story anyway?&lt;br /&gt;&lt;br /&gt;I think not. Let's look at the three components: As a, I want, and So that.&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;h4&gt;As a&lt;/h4&gt;This tells us whom the story is for. If we've developed personas or identified our users in some other detailed capacity we probably have a sense of who this person is and what motivates them. If not, we probably have a vague sense of who this person is and are likely to assume they are much like ourselves.&lt;br /&gt;&lt;br /&gt;I like personas. I like real people even better. But let's be honest; fabricated or real, these people are representative of a larger group. They are a generalization whose primary purpose is to help us understand what motivates the group. In other words, we get to know them so that we can empathize and better understand the problems they need solved.&lt;br /&gt;&lt;h4&gt;I want&lt;/h4&gt;This tells us what we anticipate will address our need. If we've followed good usability practices or have done sufficient research we probably have a sense of how likely this is to solve the problem. If not, we probably have a vague sense that this is an appropriate solution and are likely to base the answer on what we've seen in other solutions.&lt;br /&gt;&lt;br /&gt;I am a proponent of user centered design. The more we get users engaged, the better our solution. But the truth is, the "I want" is a guess that will only be proven once tested with real users, in our real application, in the real world.&lt;br /&gt;&lt;h4&gt;So that&lt;/h4&gt;Ah, and here we are, at the crux of it. This is the problem we are trying to solve. The other two components of the story are supporting cast to this, the main character. Why is it that we tuck our star away at the end of the script? I do not know.&amp;nbsp;I've previously suggested&amp;nbsp;&lt;a href="http://www.docondev.com/2010/04/stories-are-about-why-not-what-or-how.html"&gt;people change their story format to "So that, As a, I want"&lt;/a&gt;&amp;nbsp;in order to focus more on the value and less on the means.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;We frequently miss the point&lt;/h3&gt;I often see story cards that miss the mark in subtle ways. Consider the following:&lt;br /&gt;&lt;i&gt;"As an account manager, I want a listing of accounts, so that I can see them on the page."&lt;/i&gt;&lt;br /&gt;&lt;i&gt;"As a member of the support team, I want to track membership updates, so that I have a history of the changes."&lt;/i&gt;&lt;br /&gt;&lt;i&gt;"As a marketing manager, I want to enter testimonials, so that visitors can read them."&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;These stories adhere to the format, but they don't tell the complete story. We don't really know what business problem is being solved. Perhaps we can infer the problem, but there are likely to be vastly differing opinions. If we don't know what problem we are solving, we have no idea if the solution is valid.&lt;br /&gt;&lt;br /&gt;A story that fails to tell us the problem misses the point.&lt;br /&gt;&lt;h3&gt;Tell the complete story&lt;/h3&gt;Let's take a look at how these stories might read after a little more consideration given to the fundamental issue we are trying to resolve.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;"As an account manager, I want a listing of accounts, so that I can quickly access any of my accounts."&lt;/i&gt;&lt;br /&gt;&lt;i&gt;"As a member of the support team, I want to track membership changes, so that I can identify potentially fraudulent accounts."&lt;/i&gt;&lt;br /&gt;&lt;i&gt;"As a marketing manager, I want to enter testimonials, so that prospects can see that we have satisfied customers."&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;These re-worked stories, while certainly not perfect, now tell us what problem we expect to solve. This gives us an opportunity to have a deeper discussion. Does the "I want" satisfactorily resolve the fundamental need described in the "So that"?&lt;br /&gt;&lt;br /&gt;Given these final stories, I expect at least one team member would question the identified solutions. How many accounts does the average user have? Is a listing an appropriate way to access accounts? How would we identify fraudulent accounts? What data should we track and are there patterns we should monitor for in the code?&lt;br /&gt;&lt;br /&gt;These discussions are good. They mean we are focused on the right things and we are thinking about delivering solutions, not features.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-4993798354470404667?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/4993798354470404667/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2011/02/telling-complete-story.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/4993798354470404667'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/4993798354470404667'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2011/02/telling-complete-story.html' title='Telling the complete story'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-4263001053725782896</id><published>2011-02-02T12:00:00.000-05:00</published><updated>2011-02-02T12:00:04.756-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Teams'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><category scheme='http://www.blogger.com/atom/ns#' term='How To'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Pairing is Conversation</title><content type='html'>I really enjoy pair programming. It seems a natural process to me and I often wonder why it is that I like it so when others may not. Clearly, we have differing tastes and styles. I am sure that contributes to the joy (or lack thereof).&lt;br /&gt;&lt;br /&gt;I've been watching others pair lately. And there is something I've noticed; pairing done well is conversation.&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;h3&gt;What makes a conversation?&lt;/h3&gt;A &lt;a href="http://en.wikipedia.org/wiki/Conversation" target="_blank"&gt;conversation is communication between two or more people&lt;/a&gt;. For a successful conversation, the participants need to achieve a workable balance of contribution on a mutually agreeable topic. Conversation is indispensable for the successful accomplishment of almost all activities between people, especially the coordination of work and for learning.&lt;br /&gt;&lt;br /&gt;&lt;blockquote class="right_callout"&gt;Pairing can involve all four elements of human communication; Non-Verbal, Visual, Oral, and Written.&lt;/blockquote&gt;Human &lt;a href="http://en.wikipedia.org/wiki/Communication" target="_blank"&gt;communication&lt;/a&gt; is comprised of four elements; Non-Verbal, Visual, Oral, and Written. In order for there to be a conversation, we require more than one participant and at least one form of communication. Communication is achieved when the receiver of the information understands the sender.&lt;br /&gt;&lt;h4&gt;What makes a good conversation?&lt;/h4&gt;A good conversation involves participants who are genuinely interested in the topic, are informed in various ways, and are respectful of one another. Characteristics of a good conversationalist include being genuinely interested in the topic, listening to the other participants, giving the other participants time to think and respond, and considering the input of others before responding.&lt;br /&gt;&lt;h3&gt;What makes a pairing session?&lt;/h3&gt;A pairing session takes place between two or more people. For a successul pairing session, the participants need to achieve a workable balance of contribution on the story or feature being delivered.&lt;br /&gt;&lt;br /&gt;Pairing can involve all four elements of human communication; Non-Verbal, Visual, Oral, and Written. At a minimum, written is required in the form of code. Code is written in languages. It is a means of communicating intent to both the programmers and the computer. Our pair provides non-verbal cues through their body language, visual cues by writing, drawing, or pointing to the screen, and oral cues by telling us what they are thinking and doing or responding to what it is we are thinking and doing.&lt;br /&gt;&lt;h3&gt;What makes a good pairing session?&lt;/h3&gt;A good pairing session involves participants who are genuinely interested in the story, are informed in various ways, and are respectful of one another. Characteristics of a good pair include being genuinely interested in the work, listening to the other participants, giving other participants time to think and respond, and considering the input of others before responding.&lt;br /&gt;&lt;h3&gt;Participating in the Conversation&lt;/h3&gt;I've been involved in numerous pairing sessions throughout my career; some excellent, some terrible. Just as conversations, you need to know when it is working and when it is not. Just as with conversations, you need to participate if you want to get anything out of it.&lt;br /&gt;&lt;br /&gt;For me, an ideal pairing session is absorbing. My pair and I start with a discussion, perhaps it is one of us getting the other up to speed. Maybe it is a brief review of the problem and what our next test should be. It might be how to approach a large refactoring. &lt;br /&gt;&lt;blockquote class="right_callout"&gt;I'm not going to say you're doing it wrong, but I am going to say I think you're missing out on a fantastic experience.&lt;/blockquote&gt;At some point, one of us starts typing. Who is typing doesn't matter. Often, who was typing is completely unclear. The exchange continues, both of us talking, both of us typing, the solution evolving before us as we go.&lt;br /&gt;&lt;br /&gt;When we are done, neither of us can really recall who was typing when or which one of us came up with more of the solution. And it doesn't matter. We just had a great conversation.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Try it for yourself&lt;/h4&gt;If you're pairing and there is little verbal communication happening, I'm not going to say you're doing it wrong, but I am going to say I think you're missing out on a fantastic experience.&lt;br /&gt;&lt;br /&gt;And how do we get to the place where we don't know which of us is typing? Easy - two keyboards and two mice for each computer. There is no need to hand a keyboard back and forth. The exchange of the token kills the flow. If we agree that two people on a single machine is optimal, why wouldn't we have two sets of input devices?&lt;br /&gt;&lt;br /&gt;The next time you pair, start with a keyboard and mouse for each of you, then begin talking about what you want to do. See where it goes from there.&lt;br /&gt;&lt;br /&gt;I know for me, the best pairing sessions are simply good conversations.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-4263001053725782896?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/4263001053725782896/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2011/02/pairing-is-conversation.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/4263001053725782896'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/4263001053725782896'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2011/02/pairing-is-conversation.html' title='Pairing is Conversation'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-429915511480768511</id><published>2011-01-24T13:00:00.005-05:00</published><updated>2011-01-25T06:54:58.870-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Coaching'/><category scheme='http://www.blogger.com/atom/ns#' term='Teams'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='How To'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>A good coach seeks first to understand</title><content type='html'>Journeyman Jones, a journeyman carpenter is called upon to train a team of aspiring apprentice carpenters at Gable Gates. On the first day, Journeyman Jones sees that the apprentices are all striking nails with the broad-side of the head instead of the intended business end.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Confusion&lt;/h3&gt;"What on earth are you doing?", exclaims Jones.&lt;br /&gt;&lt;br /&gt;"What do you mean? We are framing a house.", replies one apprentice.&lt;br /&gt;&lt;br /&gt;"Yes, but why are you using your hammer like that? It is wrong. No carpenter would ever do that."&lt;br /&gt;&lt;br /&gt;"But this is how Master Smith taught us. He was passing through and showed us to hammer this way."&lt;br /&gt;&lt;br /&gt;"Master Smith?", asks Jones incredulously. "Impossible. Master Smith is one of the finest master carpenters around. He did not tell you to do that."&lt;br /&gt;&lt;br /&gt;"But, he did." insists the apprentice.&lt;br /&gt;&lt;br /&gt;"No matter.", says Journeyman Jones, "Let me show you the right way."&lt;br /&gt;&lt;br /&gt;And so he does.&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;h3&gt;Concern&lt;/h3&gt;Days later, Jones confirms that Master Smith had in fact visited the apprentices only weeks before. Maybe it is true. Maybe Smith did teach the apprentices the wrong way to use a hammer.&lt;br /&gt;&lt;br /&gt;After considerable thought, Jones decides, "The old man must have gone crazy. I need to tell people about this."&lt;br /&gt;&lt;br /&gt;The next day, he tells the apprentices of Gable Gates, "Master Smith has lost his way. He's forgotten the very basics of our trade. Should he pass here again, be polite, but do not listen to what he tells you. Smith is no longer fit to teach proper carpentry."&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Understanding&lt;/h3&gt;Many weeks later, while at a conference, Journeyman Jones happens an opportunity to speak with Master Smith.&lt;br /&gt;&lt;br /&gt;"Master Smith, may I bother you with a question?"&lt;br /&gt;&lt;br /&gt;"You just have.", replies Master Smith. "And I will grant you another." Smith smiles, indicating he isn't bothered in the least.&lt;br /&gt;&lt;br /&gt;"I understand you taught the apprentices of Gable Gates."&lt;br /&gt;&lt;br /&gt;"Yes. But only briefly. I was merely passing through."&lt;br /&gt;&lt;br /&gt;"They insist you instructed them to strike nails with the broad-side of the hammer head. But I am sure that couldn't be so."&lt;br /&gt;&lt;br /&gt;"I did instruct them to do just that.", Smith says in a matter-of-fact manner.&lt;br /&gt;&lt;br /&gt;"But", stumbles Jones, shocked by the tone more than the confirmation, "I don't understand why you would do such a thing. With all due respect, that's just wrong."&lt;br /&gt;&lt;br /&gt;"You see," says Master Smith, "when I first happened upon them, they were tying the framing together with twine. After some discussion, I understood they had quit using the hammer because it damaged the wood every time they missed the nail. Knowing you would be by only two weeks later, I showed them how to use the broad-side of the hammer head to increase the surface area, reduce the likelihood of a miss, and allow them to practice hammering. With two weeks of practice, they would be ready for your instruction. And were they?"&lt;br /&gt;&lt;br /&gt;"Yes.", replies the journeyman, "They were. Thank you for setting them on the right path. And now I must ask your pardon, but I need to return to Gable Gates immediately. There is one more instruction I must give them."&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-429915511480768511?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/429915511480768511/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2011/01/good-coach-seeks-first-to-understand.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/429915511480768511'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/429915511480768511'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2011/01/good-coach-seeks-first-to-understand.html' title='A good coach seeks first to understand'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-3869008688139631991</id><published>2011-01-24T10:34:00.017-05:00</published><updated>2011-11-28T19:47:37.177-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><category scheme='http://www.blogger.com/atom/ns#' term='Kata'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Sharpening the Saw</title><content type='html'>I like to practice my craft. I enjoy participating in Code Retreats. I enjoy facilitating Code Retreats. I like working on kata and koans. And a lot of what I talk about includes references to these practices. We at &lt;a href="http://www.leandog.com/" target="_blank"&gt;LeanDog&lt;/a&gt; are always on the lookout for people who are passionate about improving their own craft. I thought I'd start a blog entry where I catalog resources that might be of interest to others looking for ways to sharpen their saw.&lt;br /&gt;&lt;br /&gt;Please feel free to reply to this post with other resources I don't have listed. I will try to keep it up to date as I discover more.&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;h3&gt;Programming Exercises&lt;/h3&gt;&lt;h4&gt;&lt;a href="http://codekata.pragprog.com/"&gt;Pragmatic Programmers Code Kata&lt;/a&gt;&lt;/h4&gt;A collection of Kata from the folks over at Pragmatic. As of 24-Jan-2011, there are 21 different kata listed on the site.&lt;br /&gt;&lt;br /&gt;You can also find information about kata, koans, kumite, and the Dreyfus model. All interesting topics and worth looking at.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;&lt;a href="http://content.codersdojo.org/home/"&gt;Coders Dojo&lt;/a&gt;&lt;/h4&gt;There are no kata listed on this site, but if you are interested in kata, you need to know about this one. Coders Dojo provides an on-line live dojo for Ruby. You can execute the kata in the browser. Alternatively, you can run the kata on your local machine. In either case, you can then share the kata with other members of the site and get feedback. They have support for several other languages.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;&lt;a href="http://codingdojo.org/cgi-bin/wiki.pl?KataCatalogue"&gt;CodingDojo&lt;/a&gt;&lt;/h4&gt;There are approximately 25 different exercises on this site. They are broken down into categories; Algorithmic, Game Modeling, Math Oriented, String Manipulation, and Specific Technologies.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;&lt;a href="http://codingkata.org/katas/"&gt;Coding Kata&lt;/a&gt;&lt;/h4&gt;Over 20 kata are listed here. This site is nice for the beginner. The first kata is a Hello World that walks you through the steps of setting up a java development environment. They provide steps for several languages, all of which run on the JVM. You can choose from Java, Groovy, Scala, Clojure, JavaFX, Jython, and JRuby. They also have a javascript option.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;&lt;a href="http://www.rubyquiz.com/"&gt;Ruby Quiz&lt;/a&gt;&lt;/h4&gt;While listed as the Ruby Quiz, the problems listed here can be done in any language.&lt;br /&gt;&lt;br /&gt;There are 156 challenges listed here, so there is plenty to keep you busy for quite a while. Many of them are also available on other sites.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;&lt;a href="http://projecteuler.net/"&gt;Project Euler&lt;/a&gt;&lt;/h4&gt;Taken Directly from the Project Euler site:&lt;br /&gt;&lt;br /&gt;Project Euler is a series of challenging mathematical/computer programming problems that will require more than just mathematical insights to solve. Although mathematics will help you arrive at elegant and efficient methods, the use of a computer and programming skills will be required to solve most problems.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;&lt;a href="http://programmingpraxis.com/"&gt;Programming Praxis&lt;/a&gt;&lt;/h4&gt;The sub-title of the programming praxis site is "Sharpen your saw". I discovered this after I named this post.&lt;br /&gt;&lt;br /&gt;There are over 200 programming challenges on this site. You can find listings in chronological order, by themes, or through a search mechanism. Much of what is compiled here is available on other sites as well, but there are several unique challenges to be found here.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;&lt;a href="http://www.spoj.pl/problems/classical/"&gt;Sphere - the mother of them all?&lt;/a&gt;&lt;/h4&gt;There are over 8200 various programming challenges on this site. This is by far the most comprehensive collection of programming challenges I've found thus far.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;&lt;a href="http://sites.google.com/site/tddproblems/"&gt;TDD Problems&lt;/a&gt;&lt;/h4&gt;Thanks to &lt;a href="http://twitter.com/gdinwiddie"&gt;George Dinwiddie&lt;/a&gt; for pointing this one out. TDD Problems is a listing of approximately 30 (so far) that, according to the site's authors, meet the following criteria:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;they are real-world, not just toys&lt;/li&gt;&lt;li&gt;they are targeted towards learning TDD (that is: they are small and easy enough to work out in say half a day)&lt;/li&gt;&lt;li&gt;they don't involve any of the harder-to-test application development areas: GUI, database or file I/O. (since those topics are considered too hard for the TDD-beginner)&lt;/li&gt;&lt;li&gt;they have been solved by a TDD-practitioner previously, proving their appropriateness for [the] site&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h4&gt;&lt;a href="http://craftsmanship.sv.cmu.edu/tags/kata" target="_blank"&gt;Carnegie Mellon Craftsmanship Katas&lt;/a&gt;&lt;/h4&gt;This list of kata is from the Carnegie Mellon University - Silicon Valley curriculum. If you are not familiar with this program, I suggest you look into it. If you've a child considering a major in computer science, this unique program is teaching students how modern software is developed.&lt;br /&gt;&lt;h4&gt;&lt;a href="http://www.iamnotmyself.com/2011/02/13/RefactorThisTheGildedRoseKata.aspx"&gt;The Gilded Rose Kata&lt;/a&gt;&lt;/h4&gt;This kata made the rounds on the Software Craftsmanship Google group. It is in C#, but could easily be recreated in your language of choice. You will want to get the source for the kata off of &lt;a href="https://github.com/NotMyself/GildedRose/tree/v1.0"&gt;NotMyself's github account&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;There is another version of &lt;a href="https://github.com/TerryHughes/RefactorThis"&gt;The Gilded Rose Kata&lt;/a&gt; available from Terry Hughes.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;&lt;a href="http://codebrawl.com/"&gt;Code Brawl&lt;/a&gt;&lt;/h4&gt;CodeBrawl is a series of coding contests. You can subscribe to the feed and get notified when the next contest starts. If you prefer to take your own sweet time, you are free to try out any of the prior contest challenges; create your own testing library, a diff tool, or a command line todo tool among others.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Koans&lt;/h3&gt;A koan is part of the Zen Buddhist lore and history. It is essentially a question or story that is not understandable through rational thought, but may be through intuition. Teachers of Zen practices may ask students about the koan practices through checking questions. These questions are intended to validate insight or awakening. - borrowed liberally from &lt;a href="http://en.wikipedia.org/wiki/K%C5%8Dan" target="_blank"&gt;wikipedia&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;As far as I know, EdgeCase was the first to create a set of programming koans. Today, there are koans available in numerous languages. These are all entertaining and educational.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;&lt;a href="http://rubykoans.com/"&gt;Ruby Koans&lt;/a&gt;&lt;/h4&gt;The Koans walk you along the path to enlightenment in order to learn Ruby. The goal is to learn the Ruby language, syntax, structure, and some common functions and libraries. We also teach you culture. Testing is not just something we pay lip service to, but something we live. It is essential in your quest to learn and do great things in the language. - from the EdgeCase Ruby Koans site.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;&lt;a href="https://github.com/functional-koans/clojure-koans"&gt;Clojure Koans&lt;/a&gt;&lt;/h4&gt;One of the first in a series of functional koans, this was started by Aaron Bedra at CodeMash 2010. Now maintained by Colin Jones, the Clojure Koans are the work of several excellent contributors.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;&lt;a href="https://github.com/liammclennan/JavaScript-Koans"&gt;JavaScript Koans&lt;/a&gt;&lt;/h4&gt;Inspired by the Ruby Koans, Liam McLennan brings us the koans for JavaScript. The JavaScript koans go on to cover equality &amp;amp; “truthyness”, assignment, control structures, strings, numbers, objects, arrays, scope, and regular expressions.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;&lt;a href="http://web.archive.org/web/20031105005932/www.bagley.org/~doug/ocaml/Notes/okoans.shtml"&gt;OCaml Koans&lt;/a&gt;&lt;/h4&gt;The koans here are in a significantly different format from the Ruby and Functional koans already listed. This is a page of koans in the more classic sense. There are stories that are intended to help one learn functional programming concepts.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;&lt;a href="http://skim.la/2011/06/21/gnu-smalltalk-koans/"&gt;Smalltalk Koans&lt;/a&gt;&lt;/h4&gt;Thanks to Steve Kim (&lt;a href="http://twitter.com/#!/skim/"&gt;@skim&lt;/a&gt;) for pointing these out and even more so for authoring them. If you are not familiar with smalltalk, you might want to give it a look. What excites you about modern day languages like Ruby or Python can likely be found in smalltalk.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Testing Exercises&lt;/h3&gt;It is awfully difficult to deliver good software without testing; "nigh impossible", one might say. Actually, I don't really know anyone who would say that, but it doesn't make it any less valid. Thanks to &lt;a href="http://twitter.com/mgaertne"&gt;Markus Gärtner&lt;/a&gt; for giving me the first two entries for this section. I hope to add more.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;&lt;a href="http://testingdojo.org/tiki-index.php"&gt;Testing Dojos&lt;/a&gt;&lt;/h4&gt;This site is designed to help you run a testing dojo. It provides details on the equipment, roles, and mechanics. It covers types of dojos and discusses the value of reflection at the end of each dojo. There is also a small list of Public Dojos available. The dojo list is segregated into conferences (short-term) and locations (long-term).&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;&lt;a href="http://testing-challenges.org/tiki-index.php"&gt;Testing Challenges&lt;/a&gt;&lt;/h4&gt;There are more than 50 different testing challenges available on this site. The setup and description for most of the challenges is pretty brief, but it is sufficient to get you started. There are links to sites with more details and/or the code that will be under test. One especially nice feature is the "Similar" button on each page; click it and get a listing of exercises that are similar in style or approach to the one you are currently viewing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-3869008688139631991?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/3869008688139631991/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2011/01/sharpening-saw.html#comment-form' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/3869008688139631991'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/3869008688139631991'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2011/01/sharpening-saw.html' title='Sharpening the Saw'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-8021957785932941879</id><published>2011-01-22T11:56:00.001-05:00</published><updated>2011-01-25T06:57:03.114-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='How To'/><title type='text'>Squirrel!</title><content type='html'>I've made a pretty significant change to the way I work on my laptop. None of what I'm doing is unique, but I think it is going to help. Before I get into describing the changes I've made, I thought I'd share a bit of the back-story.&lt;br /&gt;&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;h3&gt;Stupid Car...&lt;/h3&gt;This week, my car broke down and through a series of unfortunate events, I spent the entire day alone in my apartment. I decided to work on stuff and things. I waffled a bit about whether I should start on the stuff and get it taken care of, or do the things and let the stuff wait. And then I just sort of started doing; no plan, no pomodoro. I just meandered from item to item.&lt;br /&gt;&lt;br /&gt;As the day was wrapping up, I realized I had completed neither the stuff nor the things. In fact, I couldn't really account for the hours that had passed. I worked a bit on this. I worked a bit on that. I had plenty of time. How could I have accomplished so little?&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Bring me one more browser&lt;/h3&gt;The next day, I picked up my car from the shop and I headed to the &lt;a href="http://www.leandog.com/" target="_blank"&gt;LeanDog&lt;/a&gt; boat. &lt;a href="http://www.twitter.com/redsquirrel" target="_blank"&gt;Dave Hoover&lt;/a&gt; was giving a talk on apprenticeship. I wanted to get there early to see Dave before the event.&lt;br /&gt;&lt;br /&gt;Much to my delight, not only was Dave on the boat, but several others were there. &lt;a href="http://twitter.com/joelhelbling" target="_blank"&gt;Joel Helbling&lt;/a&gt; was pairing with Dave on Conway's game of life. &lt;a href="http://twitter.com/kmsolorio" target="_blank"&gt;Kevin Solario&lt;/a&gt; and &lt;a href="http://twitter.com/joefiorini" target="_blank"&gt;Joe Fiorini&lt;/a&gt; were talking over a project they've been working on. &lt;a href="http://twitter.com/jonathanpenn" target="_blank"&gt;Jonathan Penn&lt;/a&gt; was working on the next great &lt;a href="http://navel-labs.com/" target="_blank"&gt;NavelLabs&lt;/a&gt; release. And &lt;a href="http://twitter.com/benWoz" target="_blank"&gt;Ben Woznicki&lt;/a&gt; was soaking it all in.&lt;br /&gt;&lt;br /&gt;I eventually sat down with Joe Fiorini to learn a little more vim-fu. As we were working our way through the installation of various extensions and exploring their use, I popped open Opera to get to one of the sites.&lt;br /&gt;&lt;br /&gt;"What browser are you using?", Joe asked.&lt;br /&gt;&lt;br /&gt;"Opera.", I said&lt;br /&gt;&lt;br /&gt;"What?"&lt;br /&gt;&lt;br /&gt;"Opera. I don't use it all the time. I ran out of browsers."&lt;br /&gt;&lt;br /&gt;&lt;em&gt;"What?"&lt;/em&gt;&lt;br /&gt;&lt;br /&gt;"I have mail and calendar and stuff in FireFox and I'm reading the things in Chrome. I'm using Safari for an app I'm working on. So I'm using Opera to surf around."&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;&lt;em&gt;"What?"&lt;/em&gt;&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;What indeed.&lt;/h3&gt;&lt;a href="http://twitter.com/jonathanpenn/status/28562383110668288" target="_blank"&gt;Jonathan Penn OH'd me&lt;/a&gt;. I deserved it. Seriously? What was I doing right now? I was running vim in iTerm2 and I was updating my ~/.vimrc file. Did I need four different browsers open let alone however many tabs were anxiously awaiting but a moment of my attention? What about twitter and skype and basecamp and irc?&lt;br /&gt;&lt;br /&gt;Yikes! &lt;a href="http://wn.com/Disney_Pixar_Up!_Squirrel_scenes" target="_blank"&gt;Squirrels&lt;/a&gt; everywhere.&lt;br /&gt;&lt;br /&gt;Pomodoro helps keep me focused, but I sure could use a few less distractions as well.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Let's see how this goes&lt;/h3&gt;I switched to MailPlane to start off. Rather than using two different browsers to manage my primary email accounts, I now have one app where I can quickly switch from account to account. And more important, I can close the whole damn thing quickly with a single Cmd-Q. I can open it nearly as fast thanks to Alfred. Now it does not sit open all the time. I open it when I intend to check mail and I can get the mail taken care of quickly with nary a reach for the mouse. Two squirrels down.&lt;br /&gt;&lt;br /&gt;I then wrapped several apps in fluid. I have an app for my blog which opens two tabs; one to see the stats and one to manage posts. I open it when I am working on my blog. I keep it closed otherwise. One more squirrel gone. I also put BaseCamp in a fluid wrapper. Then GitHub. Then I created one that contains both LinkedIn and FaceBook and called it Social Networks. Four more squirrels eliminated.&lt;br /&gt;&lt;br /&gt;I now run with two spaces down from six. I have twitter and skype open in one. I open whatever I am currently working on in the other. Everything else is closed. I'm thinking about reducing it down to a single space and running twitter and skype minimized.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Duh&lt;/h3&gt;It was certainly one of those moments. I talk to people all the time about limiting your WIP, paying attention to cycle time, working within time-boxes. And here I was, meandering through the fields of my own work, moving from squirrel to squirrel wondering why I wasn't getting anywhere.&lt;br /&gt;&lt;br /&gt;Thanks Joe and Jonathan. Thanks for making fun of me just enough to allow me to see the absolutely ridiculous behavior I was engaged in.&lt;br /&gt;&lt;br /&gt;I hope someday I can return the favor.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-8021957785932941879?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/8021957785932941879/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2011/01/squirrel.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/8021957785932941879'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/8021957785932941879'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2011/01/squirrel.html' title='Squirrel!'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-1635969580941007390</id><published>2011-01-17T10:00:00.002-05:00</published><updated>2011-01-25T06:57:53.856-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Manager'/><category scheme='http://www.blogger.com/atom/ns#' term='Teams'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Career'/><title type='text'>Would you be willing to preach what you practice?</title><content type='html'>&lt;h3&gt;There's an old saying&lt;/h3&gt;&lt;h4&gt;Practice what you preach&lt;/h4&gt;&lt;i&gt;Practice what you preach&amp;nbsp;&lt;/i&gt; is a variation of &lt;i&gt;&lt;a href="http://www.quotationspage.com/quote/24292.html" target="_blank"&gt;Practice yourself what you preach&lt;/a&gt;.&lt;/i&gt;&amp;nbsp;I think we are all familiar with the phrase. I suspect most of us understand the basic sentiment upon first read.&lt;br /&gt;&lt;br /&gt;This phrase addresses hypocrisy. It originally spoke to those who demanded others be pious while themselves partaking in sinful activities. It certainly applies to anyone whose personal life is lived in a manner incongruent with the values and behaviors they publicly espouse.&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;&lt;h3&gt;But what if you don't preach?&lt;/h3&gt;While hypocrisy is certainly distasteful and ugly, most of us are more challenged by what we do and don't openly talk about. Most of us don't preach. Most of us don't presume to publicly tell others what to do, especially if we feel our own behavior is less than exemplary.&lt;br /&gt;&lt;br /&gt;But does failure to be a public hypocrite justify unsavory behavior? Is it acceptable to act in a reprehensible manner so long as you don't tell others they shouldn't?&lt;br /&gt;&lt;h4&gt;It's not personal, it's only business&lt;/h4&gt;I've heard this phrase a few times in my career. I loathe this phrase. Business is nothing if it is not personal. The people who have uttered this phrase to me did so without hesitation. At the moment they said it, they genuinely believed it. They were backing out of a handshake agreement, laying off people to increase their own bonus, or flat out lying to a business partner. Business to them, was about money and nothing else.&lt;br /&gt;&lt;br /&gt;But had they been asked to, would they stand in front of a crowd and condone lying or cheating to make an extra dollar? Would they advise others to behave this way&amp;nbsp;if they knew it was being recorded for posterity to be played back in every future job interview? I doubt it. While they may live this way, they wouldn't publicly admit it.&lt;br /&gt;&lt;h4&gt;What do you want me to do, crack your skull open and pour knowledge into it?&lt;/h4&gt;I was in the room when a former boss of mine said this to a new employee. The employee was asking about a set of instructions for configuring a modem. Our boss had written the instruction set and was "training" the new employee on proper procedure. They had spent much of the day together and the employee, as might be expected, had several questions. This particular question was a legitimate suggestion for improvement masked as an inquiry. But the content of the question didn't seem to matter. It was one question too many for the manager to handle.&lt;br /&gt;&lt;br /&gt;Would this manager blog about yelling at employees as a proper method to keep them in their place? Would this manager be willing to teach an introduction to management course where berating and insulting your employees was encouraged? Certainly not. In fact, he considered himself quite the benevolent dictator.&lt;br /&gt;&lt;h4&gt;Lie and deceive in order to build trust&lt;/h4&gt;&lt;div&gt;I was not new to management, but I was new to management at this particular company. I found the politics especially difficult to navigate. This was a particularly difficult environment for me to work in. A peer and I used to go for runs at lunch. We'd talk the entire time and while discussions were often about training techniques or local races, we would&amp;nbsp;occasionally&amp;nbsp;talk about work. During one work related discussion, I asked him how he dealt with the politics, lack of good leadership, and other issues plaguing our ability to deliver.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;"I tell them what they want to hear and then I do what I know needs to be done. I don't give status unless I'm asked and I don't give it in writing. Most projects die around here for other reasons. As long as they think I'm on schedule, I don't get blamed."&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I thought about it for a while and I said, "So you lie to them."&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;"You can't do it all and nobody wants to hear the truth."&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Would his Master's Thesis be "Lying as a necessary path to success"? Would "Lie to your customer" become a part of the orientation packet for his team. Would he ever consider publishing a "lied and died" project metric? That would be career suicide. Yet he operated every day in this exact fashion.&lt;/div&gt;&lt;h4&gt;Screw them before they screw you&lt;/h4&gt;A former business partner of mine was excellent at finding weaknesses in our contracts and shoring them up. He was excellent at negotiating terms favorable to us. He was adept at ferreting out customers who might be difficult to work with. I genuinely appreciated all of these characteristics as they clearly offset my naivety. But as time went on, I found it more and more difficult to enter into engagements with clients. Our contract and terms were off-putting. Clients were confused by the incongruent presentation; a personable, amicable, partnering sales cycle followed with a iron-clad, one-sided contract. This became a point of contention between us. I was stripping contracts back to basics and working hand-shake deals while my partner was rallying for more stringent terms and insisting we kick anyone who didn't comply to the curb.&lt;br /&gt;&lt;br /&gt;Then one afternoon, we were in a rather heated discussion over the subject and he said to me, "People are out to screw you. Everybody is out to screw us. That's how it works. You need to screw them before they screw you."&lt;br /&gt;&lt;br /&gt;Would he have written a book entitled, "Making it in business: screw them before they screw you"? Would he put on his resume that he was entirely distrustful of people and had no issues screwing them over? I think not. But he lived his life by this very creed.&lt;br /&gt;&lt;h3&gt;C'mon, Doc. Those are extreme cases.&lt;/h3&gt;I am not convinced any of them are extreme. None of them are of a character furthest removed from the ordinary or average. But let's step away from overt actions of personal disregard and distrust and look at the certainly common.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Cut corners to get it done fast&lt;/li&gt;&lt;li&gt;Give teams who are supposed to work together conflicting objectives&lt;/li&gt;&lt;li&gt;Make sure employees are 100% utilized&lt;/li&gt;&lt;li&gt;Use metrics as goals and reward results&lt;/li&gt;&lt;li&gt;Rely strictly on policy to guide behavior&lt;/li&gt;&lt;li&gt;Dispense information on a need to know basis&lt;/li&gt;&lt;li&gt;Demand solutions instead of problems&lt;/li&gt;&lt;li&gt;Accept&amp;nbsp;accolades&amp;nbsp;for success and place blame for failure&lt;/li&gt;&lt;li&gt;Work 60+ hours/week&lt;/li&gt;&lt;li&gt;Foster a culture of heroism&lt;/li&gt;&lt;li&gt;Don't ask for help&lt;/li&gt;&lt;li&gt;Speak for the customer rather than to the customer&lt;/li&gt;&lt;li&gt;Prioritize new features over defect fixes&lt;/li&gt;&lt;li&gt;Make sure everyone knows who's in charge&lt;/li&gt;&lt;li&gt;Tell people what they want to hear, not what you believe can be done&lt;/li&gt;&lt;li&gt;Make everything a top priority&lt;/li&gt;&lt;li&gt;Ask for all or nothing&lt;/li&gt;&lt;li&gt;Multi-task&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;I propose a different saying&lt;/h3&gt;&lt;h4&gt;Preach what you practice.&lt;/h4&gt;I'm not saying we all need to stand atop boxes and share our primarily banal existences with the world. That's what Facebook's for.&lt;br /&gt;&lt;br /&gt;But I do encourage you to stop and reflect regularly; would you be willing to preach what you practice?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-1635969580941007390?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/1635969580941007390/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2011/01/would-you-be-willing-to-preach-what-you.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/1635969580941007390'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/1635969580941007390'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2011/01/would-you-be-willing-to-preach-what-you.html' title='Would you be willing to preach what you practice?'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-5822144211957484334</id><published>2011-01-16T22:12:00.001-05:00</published><updated>2011-01-25T06:59:41.217-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><title type='text'>Leading by Example</title><content type='html'>I'm nothing special. I've known this for a long time. I'm not a naturally talented programmer, if there even is such a thing. Nor am I a top programmer. This is not self-deprecation. I am not ashamed of this fact. I don't think I should be.&lt;br /&gt;&lt;br /&gt;Where I am today as a developer is remarkably reminiscent of my days running high school cross country. I was not a natural talent at running either. I worked hard. I became a varsity runner. This put me in the top 10% of the team. I never placed first for my team in a varsity race. Not once. But I frequently placed third or fourth for the team, putting me in a scoring position. I was regionally ranked in the top 100 and we were the best region in the state, putting me somewhere in the top 250 in the state. Nationally, however, I was nowhere near the top 1000. I never ran in a state meet. I never made the local paper except when the whole team made the paper.&lt;br /&gt;&lt;a name='more'&gt;&lt;/a&gt;&lt;br /&gt;I was, as you might imagine, opinionated and vocal. I read about running. I put what I read into practice. I read about diet and I applied what I learned. I was by no means the fastest on the team, but I was confident that I was doing the right things to maximize my personal abilities and I wanted to share that with anyone who wanted to listen. Truth be told, I shared it with many who really didn't want to listen.&lt;br /&gt;&lt;br /&gt;My enthusiasm paid off. My senior year, I was named co-captain of the team. I was an official leader of the team. It was a role I took very seriously.&lt;br /&gt;&lt;br /&gt;There was another kid on the team. He was quiet. He didn't speak up much. He was supportive, helpful, kind, and fast; faster than me. Like me, he never placed first for the team, he never made it to state, and he never made the local paper as an individual. He, however, did not make team captain.&lt;br /&gt;&lt;br /&gt;All things considered, he should have made captain. He should have been labeled the leader. He worked hard; he was supportive, kind, and helpful. He possessed all the characteristics of a leader. And he was fast; faster than me.&lt;br /&gt;&lt;br /&gt;But he was not outspoken. He did not tell others about his latest readings or his new diet ideas. He did not try to get others to listen to him and validate his thoughts. Instead, he just did his thing. He just ran. And through his behavior he set an example for everyone else. Through his actions, not his words, he modeled what it was to be a good runner.&lt;br /&gt;&lt;br /&gt;He didn't make team captain. Maybe because he didn't need it. Or maybe because I needed it more and tradition limited the number of captains. But he was a leader. He was absolutely a leader on that team.&lt;br /&gt;&lt;br /&gt;I meet people like this every now and again. Someone who is so humble and unassuming, you are likely to overlook them. You are likely not to notice what it is they have to offer.&lt;br /&gt;&lt;br /&gt;As runners, there was no doubt. You could see who was fastest. It was quite clear. But as developers, you can't always see the beauty, the grace, or the power. As developers, our ability is not so readily apparent.&lt;br /&gt;&lt;br /&gt;I paired with such a developer today. &lt;a href="http://edgecase.com/about#matt_yoho" target="_blank"&gt;His name is Matt Yoho&lt;/a&gt;. I've met him before. I've talked with him before. But today, I came to see the beauty, the grace, and the power that he brings. What I like most about this guy is that he leads by example.&lt;br /&gt;&lt;br /&gt;Matt performs and it speaks for itself to anyone who cares to listen.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-5822144211957484334?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/5822144211957484334/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2011/01/leading-by-example.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/5822144211957484334'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/5822144211957484334'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2011/01/leading-by-example.html' title='Leading by Example'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-1757370582637964443</id><published>2011-01-01T17:27:00.005-05:00</published><updated>2011-01-05T20:47:06.104-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Teams'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Career'/><title type='text'>You are a Leader</title><content type='html'>&lt;h3&gt;Leaders are chosen&lt;/h3&gt;Leadership is neither assigned nor selected. People choose whom to follow and a leader thereby emerges.&lt;br /&gt;&lt;blockquote&gt;“The led must not be compelled, they must be able to choose their own leader”&lt;span style="color: #666666;"&gt;&amp;nbsp;-&amp;nbsp;Albert Einstein&lt;/span&gt;&lt;/blockquote&gt;We always have a choice. We may not like our options. We may feel we are choosing the lesser of two evils, but nevertheless, we follow at a minimum because we choose not to do otherwise.&lt;br /&gt;&lt;blockquote&gt;“The man who lets a leader prescribe his course is a wreck being towed to the scrap heap.”&lt;span style="color: #666666;"&gt;&amp;nbsp;-&amp;nbsp;Ayn Rand&lt;/span&gt;&lt;/blockquote&gt;&lt;h3&gt;Leadership is by example&lt;/h3&gt;&lt;blockquote&gt;Example is not the main thing in influencing others, it is the only thing.&lt;span style="color: #666666;"&gt;&amp;nbsp;-&amp;nbsp;Albert Schweitzer&lt;/span&gt;&lt;/blockquote&gt;Words inspire others to action, but they don't make a leader. Words make an orator. Action makes a leader. One must do, must set an example, must establish a direction in order for others to choose to follow.&lt;br /&gt;&lt;br /&gt;Positive, negative, or even neutral; the actions taken set examples for others.&lt;br /&gt;&lt;blockquote&gt;A leader leads by example, whether he intends to or not.&lt;span style="color: #666666;"&gt;&amp;nbsp;-&amp;nbsp;John Quincy Adams&lt;/span&gt;&lt;/blockquote&gt;&lt;h3&gt;The quality of a leader is the quality of their decisions&lt;/h3&gt;Every action is the result of a decision. The quality of our decisions are not determined by the quality of the choices available, rather by the quality of our character. What we do and do not consider to be available choices is entirely about character. What we ultimately choose is a mere nuance.&lt;br /&gt;&lt;blockquote&gt;The self is not something ready-made, but something in continuous formation through choice of action.&lt;span style="color: #666666;"&gt;&amp;nbsp;-&amp;nbsp;John Dewey&lt;/span&gt;&lt;/blockquote&gt;Through character, we make our decisions. Through each decision, we determine an action. Through each action, we create a result. Through each result, we garner a lesson. Through each lesson, we build character.&lt;br /&gt;&lt;h3&gt;Leaders follow&lt;/h3&gt;All leaders are followers. All followers are potential leaders.&lt;br /&gt;&lt;blockquote&gt;You cannot be a leader ... unless you know how to follow, too.&lt;span style="color: #666666;"&gt;&amp;nbsp;-&amp;nbsp;Sam Rayburn&lt;/span&gt;&lt;/blockquote&gt;Leaders select others from whom they take cues; others whose actions they find inspiring.&lt;br /&gt;&lt;blockquote&gt;To lead, one must follow.&lt;span style="color: #666666;"&gt;&amp;nbsp;-&amp;nbsp;Lao Tzu&lt;/span&gt;&lt;/blockquote&gt;Leaders inspire others through action. Great leaders fall in stride beside others who are on the same path.&lt;br /&gt;&lt;h3&gt;We are all leaders&lt;/h3&gt;We all make decisions. We all take action. We all set examples. We are all leaders.&lt;br /&gt;&lt;br /&gt;We may deny our qualifications. We may retract our candidacy for leadership. But it is not up to us. Leadership is neither assigned nor selected. Leaders are chosen.&lt;br /&gt;&lt;br /&gt;When you show up late to stand-up and fail to uphold your team agreement, you have take an action and are, in that moment, a potential leader for others to choose to follow.&lt;br /&gt;&lt;br /&gt;When you invite a team mate to pair with you, you have taken an action and are, in that moment, a potential leader for others to choose to follow.&lt;br /&gt;&lt;h3&gt;Strive to be a good leader&lt;/h3&gt;Your influence, intentional or not, is greater than you may imagine. Strive to do well. Endeavor to do right. Be cognizant of the example you set with every action.&lt;br /&gt;&lt;blockquote&gt;The creation of a thousand forests is in one acorn.&lt;span class="Apple-style-span" style="color: #666666;"&gt;&amp;nbsp;-&amp;nbsp;Ralph Waldo Emerson&lt;/span&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-1757370582637964443?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/1757370582637964443/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2011/01/you-are-leader.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/1757370582637964443'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/1757370582637964443'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2011/01/you-are-leader.html' title='You are a Leader'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-3950667044467096481</id><published>2010-12-20T10:00:00.004-05:00</published><updated>2010-12-20T10:00:06.498-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Manager'/><category scheme='http://www.blogger.com/atom/ns#' term='Teams'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><title type='text'>What are you rewarding?</title><content type='html'>&lt;h3&gt;We don't pay bonuses&lt;/h3&gt;It is nearing the end of the year and we at &lt;a href="http://www.leandog.com/" target="_blank"&gt;LeanDog &lt;/a&gt;are wrapping up our fiscal year. We're looking at the potential tax benefits of spending some of our reserve and we're mulling over other ideas related to the spend of money. We are not, however, discussing our bonus objectives. We aren't discussing them because we don't have them. I, for one, am happy that we don't.&lt;br /&gt;&lt;br /&gt;Plenty of companies have bonus objectives. Many of those companies are spending a great deal of time (and money) trying to make sure that those objectives are met (or at least appear to be met). To some, this sounds like a good idea. To me, it sounds like rampant dysfunction.&lt;br /&gt;&lt;h3&gt;Bonus programs often fail&lt;/h3&gt;I recall working with a customer who was very keen on ensuring maximum utilization of their "resources". Each manager had utilization targets with associated fiscal incentives. Meet the target, get a bonus. Fail and get none. Simple enough.&lt;br /&gt;&lt;br /&gt;But this entire system proved to be counter productive and misguided.&lt;br /&gt;&lt;h4&gt;The metric becomes more important&lt;/h4&gt;Managers were spending a great deal of time monitoring the&amp;nbsp;time-sheets&amp;nbsp;of their employees. Managers would download the data and run it against various formulas to make sure they were within limits. If an employee's ratio was off, the manager needed to figure out how to allocate the time to get the ratios correct, discuss it with the employee, and validate the changes once they were made. In many cases, the time was tracked under the wrong category because the task that was clearly most applicable was not categorized in accord with the allocations. The time was instead allotted to some other task in order to get it into the right category. Much work was done to make sure the allocations were met. The accuracy of the system degraded over time. People's hours were no longer tracked to the actual task, but instead tracked to areas that kept the ratios favorable.&lt;br /&gt;&lt;h4&gt;Good work is sometimes punished&lt;/h4&gt;Among the development teams, there was one that delivered to the delight of the customer every time. Their bug count was extremely low. Their customer was actively engaged in setting priority and was aware of the status at any given time. The team worked together, communicating, collaborating, and making things happen. They delivered more frequently with higher quality than any other team in the department. But their ratios were off. For a utilization target of 90%, they were consistently floating at 85%. They were tracking their time honestly. Their manager refused to doctor the time while all other managers were complicit in time doctoring. Directors were given incentives for the percentage across all their teams. So unless the other teams fudged enough to beat the target by a few percent, the director wasn't going to make the bonus mark.&lt;br /&gt;&lt;br /&gt;Ultimately, the manager who delivered and was honest failed to meet the bonus objective and was both paid less and reprimanded for failure to meet the company standard. Other teams failed to deliver anything in a year, but showed the proper allocations and were given a bonus.&lt;br /&gt;&lt;h3&gt;A raise is a bonus that lasts forever&lt;/h3&gt;My advice to managers, directors, and executives who want to pay bonuses? Don't. If you must do so, then break it down based on each employee's income. If you have a top performer, don't give them a bigger bonus, give them a raise. Think of a raise as a bonus that lasts forever.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-3950667044467096481?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/3950667044467096481/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/12/what-are-you-rewarding.html#comment-form' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/3950667044467096481'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/3950667044467096481'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/12/what-are-you-rewarding.html' title='What are you rewarding?'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-6775359824946164683</id><published>2010-12-08T14:17:00.000-05:00</published><updated>2010-12-08T14:17:36.708-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Games'/><category scheme='http://www.blogger.com/atom/ns#' term='Teams'/><category scheme='http://www.blogger.com/atom/ns#' term='How To'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><title type='text'>Lost in Translation - An Agile Game</title><content type='html'>&lt;b&gt;&lt;u&gt;Timing:&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;One hour, but this can be extended or contracted as needed.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;u&gt;Materials:&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;Pencils, paper, timer, and a collection of pictures (royalty free).&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;u&gt;Instructions:&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;One person is the facilitator. The facilitator keeps time, makes sure the rules are being followed, and facilitates the retrospectives.&lt;br /&gt;&lt;br /&gt;The rest of the people are broken up into teams of three; a product owner, an analyst, and a developer. The product owner is provided a picture chosen at random from a collection.&lt;br /&gt;&lt;br /&gt;The product owner is not allowed to show the picture to anyone else.&lt;br /&gt;&lt;br /&gt;The team needs to create a hand-drawn depiction of the picture.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Round One:&lt;/b&gt;&lt;br /&gt;&lt;em&gt;Requirements (10 minutes)&lt;/em&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The developer leaves the room.&lt;/li&gt;&lt;li&gt;The product owner describes the picture to the analyst.&lt;/li&gt;&lt;li&gt;The analyst captures the requirements.&lt;/li&gt;&lt;li&gt;The analyst may ask as many questions as needed in the time allowed.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;em&gt;Delivery (10 minutes)&lt;/em&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The developer returns and the product owner leaves.&lt;/li&gt;&lt;li&gt;The product owner needs to remain nearby for questions, but not in the room&lt;/li&gt;&lt;li&gt;The analyst provides the written specification to the developer.&lt;/li&gt;&lt;li&gt;The analyst may provide answers to any of the developer's questions.&lt;/li&gt;&lt;li&gt;The analyst may ask the product owner as many questions as necessary, but must leave the room to do so.&lt;/li&gt;&lt;li&gt;The developer draws the picture.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;Retrospective (10 minutes)&lt;/b&gt;&lt;br /&gt;What went well? What did not go well? What would have made it better?&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Round Two:&lt;/b&gt;&lt;br /&gt;The product owner is provided another random picture.&lt;br /&gt;&lt;br /&gt;&lt;em&gt;Delivery (15 minutes)&lt;/em&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Everyone stays in the room.&lt;/li&gt;&lt;li&gt;The analyst and developer work together to create the picture.&lt;/li&gt;&lt;li&gt;The analyst and developer may ask the product owner as many questions as necessary.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;b&gt;Retrospective (15 minutes)&lt;/b&gt;&lt;br /&gt;What went well this time? What did not go well? What would have made this better?&lt;br /&gt;&lt;br /&gt;How does round one compare with round two?&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;u&gt;Learning Points:&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Working face to face is easier and more rewarding&lt;/li&gt;&lt;li&gt;Working together in real time produces a better product&lt;/li&gt;&lt;li&gt;Documentation is less valuable than communication&lt;/li&gt;&lt;li&gt;Roles are not so important when it comes to getting the work done&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-6775359824946164683?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/6775359824946164683/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/12/lost-in-translation-agile-game.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/6775359824946164683'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/6775359824946164683'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/12/lost-in-translation-agile-game.html' title='Lost in Translation - An Agile Game'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-1594246978301722237</id><published>2010-12-02T11:40:00.000-05:00</published><updated>2010-12-02T11:40:45.280-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Teams'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><category scheme='http://www.blogger.com/atom/ns#' term='How To'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>The Three "R"s of Clean Code</title><content type='html'>&lt;h3&gt;Establishing Code Quality Standards&lt;/h3&gt;&lt;h4&gt;Mandate via Manual&lt;/h4&gt;&lt;div&gt;A client of &lt;a href="http://www.leandog.com/" target="_blank"&gt;LeanDog&lt;/a&gt; was looking for a way to introduce code quality standards to their development teams. There had been a few meetings prior to LeanDog's involvement. The prevalent line of thinking was to draft a standards manual for dissemination to the teams. This would consist of a comprehensive set of rules and clear specifications to which all teams need comply.&lt;br /&gt;&lt;br /&gt;There was a good deal of discussion around people's historic failure to read and follow this type of documentation. Such failure to comply mandated policing. There were a number of possible solutions; training, financial incentives, managerial targets, code reviews, code audits, and code compliance tools.&lt;/div&gt;&lt;h5&gt;Ummm, yeah. Don't do that. Ok?&lt;/h5&gt;&lt;div&gt;Keep it as simple as possible. Assume the people you work with are competent, capable, and want to do their jobs well. Developers tend to take personal pride in their work, as do most people. I've yet to meet anyone in the field who proudly (and seriously) proclaims, "I do my job poorly."&lt;br /&gt;&lt;br /&gt;This kind of governance should not be necessary. If it is necessary, then remember that your people are competent, capable, and want to do their jobs well. Failure to meet a standard says more about the standard than the people.&lt;br /&gt;&lt;br /&gt;It is likely the problem is the manner of communication and enforcement.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Voice via Vignette&lt;/h4&gt;Rather than a tome of requirements or a blanket statement such as, "Follow the standards in &lt;a href="http://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882" target="_blank"&gt;Clean Code&lt;/a&gt;.", give the team simple guidelines that they can agree to and internalize. Short, simple reminders of what quality is to the team. With these simple reminders, they have a catalyst that fires the synapse that brings back all the other "rules".&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;h3&gt;Enter the Three "R"s of Clean Code&lt;/h3&gt;For this particular client, &lt;a href="http://www.leandog.com/" target="_blank"&gt;LeanDog&lt;/a&gt; helped to establish a set of three simple reminders; Readable, Reliable, and Responsible. These may not be the right reminders for your team. Work together to find what resonates with you.&lt;br /&gt;&lt;br /&gt;We restricted ourselves to a single sheet of 8.5"x11" paper and documented the standards we felt were most important. Once the page was filled, we reduced it by eliminating duplicates and highly similar items. We then sorted it in priority order and cut it to half of a page. We then studied the list and came up with groupings. We moved items into the groups and discussed how it all "felt". It took only a couple of iterations to finalize the list.&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/_9BSWFzzwekI/TPfLhiY3TWI/AAAAAAAAAE4/Bzv8SV77_bI/s1600/BoyScoutRule.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="117" src="http://2.bp.blogspot.com/_9BSWFzzwekI/TPfLhiY3TWI/AAAAAAAAAE4/Bzv8SV77_bI/s200/BoyScoutRule.png" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;The team now has four signs that hang in their work space. The three Rs and &lt;a href="http://programmer.97things.oreilly.com/wiki/index.php/The_Boy_Scout_Rule" target="_blank"&gt;The Boy Scout Rule&lt;/a&gt; Each of the R signs has a short list that further describes what the team means by the "rule".&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_9BSWFzzwekI/TPfLJqgpFqI/AAAAAAAAAEs/vworG_wo-lM/s1600/Readable.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="112" src="http://3.bp.blogspot.com/_9BSWFzzwekI/TPfLJqgpFqI/AAAAAAAAAEs/vworG_wo-lM/s200/Readable.png" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;h4&gt;Readable&lt;/h4&gt;&lt;div&gt;Descriptive Function Names&lt;br /&gt;Small Functions&lt;br /&gt;Few Comments&lt;br /&gt;Few Arguments&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/_9BSWFzzwekI/TPfLS3yRGMI/AAAAAAAAAEw/EjJcWPJmVvc/s1600/Reliable.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="110" src="http://3.bp.blogspot.com/_9BSWFzzwekI/TPfLS3yRGMI/AAAAAAAAAEw/EjJcWPJmVvc/s200/Reliable.png" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;h4&gt;Reliable&lt;/h4&gt;Tested&lt;br /&gt;Descriptive Function Names&lt;br /&gt;Necessary Code&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/_9BSWFzzwekI/TPfLZB5oe1I/AAAAAAAAAE0/FONL1GBaGf0/s1600/Responsible.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="110" src="http://3.bp.blogspot.com/_9BSWFzzwekI/TPfLZB5oe1I/AAAAAAAAAE0/FONL1GBaGf0/s200/Responsible.png" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;h4&gt;Responsible&lt;/h4&gt;Single Responsibility Principle&lt;br /&gt;Necessary Code&lt;br /&gt;Tested&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;h3&gt;Less is More&lt;/h3&gt;We did not cover many things. We don't talk about specific conventions for naming. We don't cover formatting items such as indentation or where the curly-brackets belong. We focused on a select few things that the team felt would guide them toward better overall code. These signs hang up around the work space as regular, simple reminders. And the entire team not only knows what these mean, they follow them without any governance beyond integrity and a commitment to the team.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;What would be on your list?&lt;/h3&gt;As I said, the list was developed by the team for the team. Maybe there is something you think is very important that was overlooked. Think on this for a while and then let us know what your personal (or team) list would look like.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-1594246978301722237?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/1594246978301722237/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/12/three-rs-of-clean-code.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/1594246978301722237'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/1594246978301722237'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/12/three-rs-of-clean-code.html' title='The Three &quot;R&quot;s of Clean Code'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_9BSWFzzwekI/TPfLhiY3TWI/AAAAAAAAAE4/Bzv8SV77_bI/s72-c/BoyScoutRule.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-4354830176285523877</id><published>2010-11-29T09:46:00.012-05:00</published><updated>2010-11-30T06:31:09.131-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Manager'/><category scheme='http://www.blogger.com/atom/ns#' term='How To'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Retrospectives'/><title type='text'>LeanDog Extreme Meeting</title><content type='html'>&lt;h3&gt;What is an Extreme Meeting?&lt;/h3&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_9BSWFzzwekI/TPTfp5D0i9I/AAAAAAAAAEk/pmvZ7F0euxw/s1600/IMG_0369.JPG" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="320" src="http://3.bp.blogspot.com/_9BSWFzzwekI/TPTfp5D0i9I/AAAAAAAAAEk/pmvZ7F0euxw/s320/IMG_0369.JPG" width="240" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Stairs made it "easier"&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;I definitely have to give the nod to Jon Stahl on this one. I'm not sure where he got the idea. I've not asked. But it wouldn't surprise me if he came up with it all on his own. If you know Jon, you know what many of us would consider extreme is pretty commonplace for him. If you get the opportunity to sit down with him and you don't want to talk about agile or lean, be sure to ask him about his trip to the far north. It is an epic story.&lt;br /&gt;&lt;br /&gt;The basic premise is simple; get out and do something that tests your stamina, creates a sense of team, and allows you to have discussions you might not otherwise have.&lt;br /&gt;&lt;br /&gt;So far, I have to say I am a fan. I liked the concept, but was apprehensive of the potential outcome. My primary concern was if everyone could make a 14 mile challenging hike. We placed a vehicle at the turn-around point, which helped. We also chose a route that started easy, got more difficult, and then ended very flat and easy. Warm up, work hard, cool down.&lt;br /&gt;&lt;h4&gt;Format&lt;/h4&gt;&lt;h5&gt;Pre-Event&lt;/h5&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_9BSWFzzwekI/TPTe5VenQ8I/AAAAAAAAAEg/2kK_9Qzea3Y/s1600/IMG_0368.JPG" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="200" src="http://2.bp.blogspot.com/_9BSWFzzwekI/TPTe5VenQ8I/AAAAAAAAAEg/2kK_9Qzea3Y/s200/IMG_0368.JPG" width="150" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Status Update&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;We preselected a few important strategic topics. Individuals were assigned responsibility for the items. To be quite specific, we ran an A3 process several days prior to the hike. But the A3 piece is not necessary, only a select set of key topics and an "owner" for each topic.&lt;br /&gt;&lt;h5&gt;Iterations&lt;/h5&gt;We were headed out for a 14 mile hike, so we broke the hike up into sections approximately three miles each. The team met at the trail head and each topic owner gave a brief overview of their item. We then split up into small groups, each focused on a specific topic.&lt;br /&gt;&lt;br /&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: left; margin-right: 1em; text-align: left;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_9BSWFzzwekI/TPTgM0RtZiI/AAAAAAAAAEo/eGvztLZSWdk/s1600/IMG_0363.JPG" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="150" src="http://2.bp.blogspot.com/_9BSWFzzwekI/TPTgM0RtZiI/AAAAAAAAAEo/eGvztLZSWdk/s200/IMG_0363.JPG" width="200" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Jon Selects a Lunch Spot&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;We hiked a leg of the trail, talking over our thoughts and ideas on the specific topic. The topic owner facilitated the session, making sure we stayed near enough to the original topic, without entirely dominating and controlling the discussion.&lt;br /&gt;&lt;br /&gt;At the end of each leg, we briefly discussed the experience as a larger group. We then split up into new groups. We decided at each point if we wanted to retire a topic and introduce a new one or continue with a prior topic. It was all quite dynamic and the general lack of formal agenda allowed us to organize around things as we thought necessary.&lt;br /&gt;&lt;h4&gt;Retrospective&lt;/h4&gt;&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_9BSWFzzwekI/TPTeV9-KQII/AAAAAAAAAEc/kX8gAqr8Dbw/s1600/IMG_0370.JPG" imageanchor="1" style="clear: left; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="150" src="http://2.bp.blogspot.com/_9BSWFzzwekI/TPTeV9-KQII/AAAAAAAAAEc/kX8gAqr8Dbw/s200/IMG_0370.JPG" width="200" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Discussing Strategy&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;At the end of the hike, we met at The Winking Lizard in Peninsula, OH. The Lizard is a wings and beer pub that has been around for many years. It was a nice venue to wind-down, have a drink, and get something to eat.&lt;br /&gt;&lt;br /&gt;We generally agreed to try mini-presentations at each break. This would allow each of us to get a quick (3-minute) update on each of the topics.&lt;br /&gt;&lt;h4&gt;Next Event&lt;/h4&gt;We are thinking about an over-night canoe trip for the next one. Clearly, this will have to wait until the weather is more appropriate. Other suggestions were sky diving,&amp;nbsp;rappelling, and white water rafting. They all sound fun (or at least extreme), but it is important that the activity provide for discussion first and foremost. I, for one, would have a hard time holding a conversation while simultaneously fighting to hold down my lunch.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-4354830176285523877?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/4354830176285523877/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/11/leandog-extreme-meeting.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/4354830176285523877'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/4354830176285523877'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/11/leandog-extreme-meeting.html' title='LeanDog Extreme Meeting'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_9BSWFzzwekI/TPTfp5D0i9I/AAAAAAAAAEk/pmvZ7F0euxw/s72-c/IMG_0369.JPG' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-6314748541191890862</id><published>2010-11-07T02:53:00.001-05:00</published><updated>2010-11-07T02:56:18.854-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Career'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>One week of this positivember crap</title><content type='html'>You know, this wasn't as easy as I thought it would be - this whole being positive thing. I made it really hard on myself at first. If I faltered, if I had a negative thought or got frustrated, I got down on myself for not doing better. After about 36 hours of that, I realized that getting down on myself was certainly not in the spirit of &lt;a href="http://programmingtour.blogspot.com/2010/11/positivember.html"&gt;positivember&lt;/a&gt;. I realized that it was not a lack of negativity that I needed to focus on, rather an increase in positivity. Not happy fluffy bunny stuff with cotton candy and unicorns and rainbows. Although unicorns are cool. But just looking for the good in others, the positive of the moment, or how I could do something to make the day of another a little better.&lt;br /&gt;&lt;br /&gt;So I decided to allow myself to get down or grumpy or frustrated, but only for a moment. And rather than admonish myself for having done so, I'd make an effort to counter the negativity and then surpass it. After about 36 hours of that, I realized I wasn't feeling negative nearly as often. I was actually feeling pretty positive.&lt;br /&gt;&lt;br /&gt;I also decided to learn something new every day in November. It doesn't have to be huge, but I do have to make an active effort to achieve it. If I happen to pick something up along the way (which I often do), that doesn't count. And in the last week, I've learned a bit more about vim, I've taken another look at closures in javascript, and I've worked my way deeper into the clojure koans.&lt;br /&gt;&lt;br /&gt;I know it is only day seven, but November is shaping up nicely.&lt;br /&gt;&lt;br /&gt;Honestly, I see no reason to limit myself to just one month. Maybe I'll try to keep the streak going until the end of the year.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-6314748541191890862?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/6314748541191890862/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/11/one-week-of-this-positivember-crap.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/6314748541191890862'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/6314748541191890862'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/11/one-week-of-this-positivember-crap.html' title='One week of this positivember crap'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-4409470668205492822</id><published>2010-11-02T10:09:00.000-04:00</published><updated>2010-11-02T10:09:52.222-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Teams'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><title type='text'>Keep your ears, your eyes, and your mind open</title><content type='html'>&lt;h3&gt;Developers shouldn't specialize&lt;/h3&gt;Davey Brion wrote a post not too long ago &lt;a href="http://davybrion.com/blog/2010/10/developers-shouldnt-specialize/" target="_blank"&gt;warning developers about the dangers of specializing in a particular technology&lt;/a&gt;.&lt;br /&gt;&lt;h3&gt;The real message&lt;/h3&gt;Davey concludes his post with the following paragraph:&lt;br /&gt;&lt;blockquote&gt;"Keep your ears, your eyes and your mind open. If you notice that a group of people gets excited about something new, then figure out why. If you notice that something appears to be working well for others, then figure out why. If you notice an increasing stream of criticism on the technology you’re using, then figure out why. You’ll need information like this to make well-founded decisions about&amp;nbsp;&lt;em&gt;your&amp;nbsp;&lt;/em&gt;future."&lt;/blockquote&gt;If you are a practitioner of Lean, you are likely to find yourself trying to convince others that they should focus on one item at a time and observe the flow of work. If you are a practitioner of Scrum, you are likely to find yourself trying to convince others that they need to commit to an amount of work each iteration and observe the burn down. And if you are a practitioner of XP, you are likely to find yourself trying to convince others they need to use TDD, pair programming, and&amp;nbsp;other&amp;nbsp;engineering practices.&lt;br /&gt;&lt;br /&gt;There are good ideas in each of these approaches. There are a few conflicting ideas, certainly. But there is a lot more in common than there is different. And there are valuable ideas from each that fill gaping holes in the others.&lt;br /&gt;&lt;br /&gt;When you focus on a single approach, you not only constrict your ability to grow and learn, but worse, you cultivate a bias. When the information you receive is accepted or rejected based on how consistent it is with your current thinking, you limit your ability to make new distinctions.&lt;br /&gt;&lt;br /&gt;I encourage you to follow Davey's advice. Pay attention to the buzz around new ideas. Rather than figure out how to tear it down and dismiss it, find what it offers that is of value. If you hear of others achieving success with other approaches, investigate and seek new ideas you can adopt. Pay attention to the frequent criticisms of your own ideas. Rather than immediately trying to defend your ideas, give legitimate consideration to why this counter-perception exists and if there is anything you can learn from it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-4409470668205492822?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/4409470668205492822/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/11/keep-your-ears-your-eyes-and-your-mind.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/4409470668205492822'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/4409470668205492822'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/11/keep-your-ears-your-eyes-and-your-mind.html' title='Keep your ears, your eyes, and your mind open'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-8163707300480257838</id><published>2010-10-31T09:11:00.001-04:00</published><updated>2010-10-31T16:36:04.701-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><category scheme='http://www.blogger.com/atom/ns#' term='How To'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><category scheme='http://www.blogger.com/atom/ns#' term='Technical Debt'/><title type='text'>Should we always pay back Technical Debt?</title><content type='html'>&lt;h3&gt;Jim Highsmith on Technical Debt&lt;/h3&gt;A former coworker of mine, Jim Highsmith, has recently written an article on &lt;a href="http://www.jimhighsmith.com/2010/10/19/the-financial-implications-of-technical-debt/" target="_blank"&gt;The Financial Implications of Technical Debt&lt;/a&gt;. Jim states that recent studies indicate the cost of technical debt is near $1 trillion in the U.S. I would like to see these studies. I do know that not too long ago, &lt;a href="http://www.gartner.com/it/page.jsp?id=1439513" target="_blank"&gt;Gartner released a report&lt;/a&gt; indicating that the worldwide cost of IT Debt will be $1 trillion by 2015. Regardless, the point he makes is still valid - technical debt is egregious.&lt;br /&gt;&lt;br /&gt;Jim states, "Unfortunately, by the time many organizations are paying attention, all the solutions are bad ones: 1) do nothing and it gets worse, 2) re-place/re-write the software (expensive, high risk, doesn’t address the root cause problem), or 3) systematically invest in incremental improvement."&lt;br /&gt;&lt;br /&gt;Of these three (bad) options, I think the second is often a better choice than the third. The first represents failure to make a necessary decision.&lt;br /&gt;&lt;h3&gt;Just chuck it&lt;/h3&gt;Let's assume a product has been in development for a few years. During that history, the software delivery team has garnered a significant amount of domain knowledge through trial and error. Some assumptions were validated, others definitively proven incorrect. Adjustments have been made, entire screens have been overhauled to improve the user experience. The data model has been tweaked to accomodate unanticipated requirements without invalidating all prior collected data. And, as we've established, there is significant technical debt.&lt;br /&gt;&lt;br /&gt;In this same amount of time, the development tools have undergone three major revision updates, the database platform has undergone one major revision update, and the standards for the web-based front-end have undergone significant change, not to mention the advantages of jQuery, which your app is using sparsly.&lt;br /&gt;&lt;br /&gt;The cost of maintenance and new development is on a steep incline. Making reparations as we go along will result in a slow recovery. If it took us four years to get here, it will likely take us four years to recover; perhaps longer. If you've ever worked for a couple of days on a piece of code and lost it, you know it takes about half a day to write the whole thing again and do it better.&lt;br /&gt;&lt;br /&gt;So what is more risky? Continuing to work on this code base, cobbling together mis-matched parts in old technologies and slowly grinding out improvements or writing a new one?&lt;br /&gt;&lt;br /&gt;I agree good code is an asset. But, just as in other investments, sometimes the best move is to take the loss and get out rather than holding on in hopes of a recovery.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Then do it better&lt;/h3&gt;We've the opportunity to advance the tools and technologies. We've an opportunity to build it again fortified with several years of learning through trial and error. Take advantage of this opportunity and do it well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-8163707300480257838?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/8163707300480257838/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/10/should-always-we-pay-back-technical.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/8163707300480257838'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/8163707300480257838'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/10/should-always-we-pay-back-technical.html' title='Should we always pay back Technical Debt?'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-7986664730069627695</id><published>2010-10-28T23:43:00.001-04:00</published><updated>2010-10-29T11:11:18.119-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Presentations'/><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><category scheme='http://www.blogger.com/atom/ns#' term='Career'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Training Software Professionals</title><content type='html'>&lt;h3&gt;The Slides&lt;/h3&gt;Here is the slide deck to my SCNA talk, "Training Software Professionals, Just What the Doctor Ordered". In the past, my slide decks stood on their own. That is, you could thumb through the deck and easily glean all the key points of the talk. But I am trying to move away from that presentation style to one where the slides offer visual support, but the speaker (me) tells the actual story.&lt;br /&gt;&lt;div id="__ss_5588632" style="width: 425px;"&gt;&lt;strong style="display: block; margin: 12px 0 4px;"&gt;&lt;a href="http://www.slideshare.net/DocOnDev/training-software-professionals-just-what-the-doctor-ordered" title="Training Software Professionals - Just What the Doctor Ordered"&gt;Training Software Professionals - Just What the Doctor Ordered&lt;/a&gt;&lt;/strong&gt;&lt;object height="355" id="__sse5588632" width="425"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=training-software-professionals-reducedsize-101027205500-phpapp02&amp;stripped_title=training-software-professionals-just-what-the-doctor-ordered&amp;userName=DocOnDev" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed name="__sse5588632" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=training-software-professionals-reducedsize-101027205500-phpapp02&amp;stripped_title=training-software-professionals-just-what-the-doctor-ordered&amp;userName=DocOnDev" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;div style="padding: 5px 0 12px;"&gt;View more &lt;a href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/DocOnDev"&gt;Michael Norton&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;h3&gt;The Story&lt;/h3&gt;&lt;h4&gt;I am a Software Craftsman&lt;/h4&gt;From the moment the phrase was uttered, people starting formulating opinions about what it means. From guilds, exclusionists, and elitism to irresponsibly meticulous artsy-fartsy types to passionate life-long learners.&lt;br /&gt;&lt;br /&gt;For me, Software Craftsmanship is trying to live my life in accord with &lt;a href="http://manifesto.softwarecraftsmanship.org/" target="_blank"&gt;the values&lt;/a&gt;. I am not claiming that I live my life entirely in accord with the values. I am saying that I endeavor to do so. Every day. Some days, I do better than others.&lt;br /&gt;&lt;h4&gt;We Need To Talk&lt;/h4&gt;We need to talk amongst ourselves and with others. We need to talk about what we're doing to actively improve the quality of software. Or more accurately, what we're actively doing to improve the quality of software practitioners, through whom, software is developed and delivered. I don't believe I have the answers. I'm not even certain I have all the right questions. But I am certain that we, as a community, have everything we need to effectively address the issue of quality in our profession.&lt;br /&gt;&lt;h4&gt;$1 Trillion by 2015&lt;/h4&gt;On September 10, 2010, Gartner Group published &lt;a href="http://www.gartner.com/it/page.jsp?id=1439513" target="_blank"&gt;a comprehensive study of IT Debt worldwide&lt;/a&gt;. The debt is estimated at $500 billion at the end of 2010 with a projection to hit $1 trillion by 2015. Many discussions on software quality meander their way into a debate about the lack of need for rigor when lives are not at stake. Given worldwide IT Debt at $1 trillion, even if only 10 percent of it is from code, we are looking at $100 billion due to poor coding practices. This is somewhere in the range of $14 for each living human. This is more than a complete year's salary for every developer on earth. While we may not be able to draw a straight line from this debt to the loss of human lives, I've no doubt the connection exists.&lt;br /&gt;&lt;br /&gt;Our profession is failing to deliver. We must do something.&lt;br /&gt;&lt;br /&gt;How do we improve the quality of our code? I suggest we start by improving the quality of our practitioners.&lt;br /&gt;&lt;h4&gt;What are others doing?&lt;/h4&gt;Many professions have been around for far longer than ours; hundreds of years, even thousands. We may be able to accelerate our learning by observing those who've gone before us. Among the professions actively dealing with the quality of their practitioners, is medicine. This is not to suggest the medical field has yet mastered their shortcomings, but we can still benefit from their progress.&lt;br /&gt;&lt;h5&gt;Educating Medical Practitioners&lt;/h5&gt;Today's physicians are educated both at school and long after graduation. They begin with a general education followed by a more specific focus on medical science. While this provides them with the science, theory, and philosophy of medicine, it does little to teach them how to apply this learning to the care of people. School is followed by a period of internship or residency where budding physicians learn how to apply their knowledge to the art of caring for people. Physicians are licensed to practice medicine and certified in areas of specialty. They engage in lifelong learning both collaboratively and intentionally on the job as well as through formal (and sometimes informal) continuing education.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;General / Specialized Medicine&lt;/li&gt;&lt;li&gt;Internship / Residency&lt;/li&gt;&lt;li&gt;Licensing / Certification&lt;/li&gt;&lt;li&gt;Collaborative Learning&lt;/li&gt;&lt;li&gt;Continuing Education&lt;/li&gt;&lt;/ul&gt;&lt;h5&gt;Software Development in Contrast&lt;/h5&gt;&lt;div&gt;Comparatively, the standard educational process for software developers is a general education with a few classes covering multiple aspects of general technology and perhaps some classes focused on a language or development practices. No residency. Certifications with questionable value. No licensing. Informal self-directed collaborative learning. And no continuing education requirement.&lt;/div&gt;&lt;h4&gt;A quick history of Western Medicine&lt;/h4&gt;To appreciate where the medical profession is today, it helps to take a look at the events that shaped their profession. This is not a comprehensive review. The medical profession has been around for over 5000 years. In 3000 BC, the egyptians had hospitals, nursing homes, and even medical insurance. Our focus is on Western Medicine with an emphasis on events influencing the course of medical education.&lt;br /&gt;&lt;h5&gt;Hippocrates - 400 BC&lt;/h5&gt;Hippocrates is often referred to as the Father of Western Medicine. He made many significant contributions to the medical field. Much of what is done today can be traced to the findings and teachings of Hippocrates.&lt;br /&gt;&lt;br /&gt;Perhaps most significant of Hippocrates' contributions was the separation of faith and medicine. Prior to Hippocrates, most of what ailed humans was considered to be attributable to deity. But Hippocrates thinking allowed him to look more locally for the source of what ails us.&lt;br /&gt;&lt;br /&gt;Hippocrates taught in a Master/Apprentice fashion. He housed a few students and taught them in exchange for which they helped to tend to his land and stock. Students were provided the opportunity to learn, experiment, and eventually practice as he felt they were ready and capable. Students moved on to be practicing physicians and several eventually took on apprentices of their own. Significant priority was given to the proper clinical care and treatment of patients.&lt;br /&gt;&lt;br /&gt;The &lt;b&gt;Master/Apprentice&lt;/b&gt; format was the prevailing form of education for centuries to follow.&lt;br /&gt;&lt;h5&gt;Canon of Medicine - 1025&lt;/h5&gt;The Canon of Medicine is a vast collection of medical knowledge from both Eastern and Western cultures spanning several millennia of learning. It was considered, at the time of its writing, to be comprehensive and complete. The canon ushered in a new style of medical learning. With a single text to teach from, Masters could significantly expand their audience and share with hundreds of students at one time rather than a mere few.&lt;br /&gt;&lt;h5&gt;Schola Medica Salernitana&lt;/h5&gt;Considered the Birth Place of Modern Medical Education, this &lt;b&gt;medical school&lt;/b&gt; in Solerno Italy set the example for the next several centuries. Physicians moved away from the Master/Apprentice model to a more scalable and rapid form of education taught in lecture format based on the Canon and supporting texts.&lt;br /&gt;&lt;br /&gt;It was generally believed that the texts contained everything possible to know in terms of medical care.&lt;br /&gt;&lt;h5&gt;Black Death - 1350&lt;/h5&gt;The bubonic plague was devastating. Nearly half of England was killed and over one third of all Europe died. Nothing known about the human body, medicine, surgery, or the cause of illness helped.&lt;br /&gt;&lt;br /&gt;Schools focused on finding new ways of identifying and treating human ailments. For the next several hundred years, the medical industry focused intently on scientific discovery and learning.&lt;br /&gt;&lt;br /&gt;But as physicians became significantly better at treating disease, they became far less capable at treating their patients. Science had become such a focus, that proper clinical care and treatment of patients was no longer a significant part of the educational process.&lt;br /&gt;&lt;h5&gt;Osler and Flexner&lt;/h5&gt;In 1904, Sir William Osler wrote a paper urging medical schools to introduce residency as a part of the curriculum. Osler regularly had students accompany him on rounds in the hospital where they learned how to treat people in a clinical setting. He wished to return humanity to the practice of medicine.&lt;br /&gt;&lt;br /&gt;Around the same time, the Flexner report was published. The report has a great deal of controversy surrounding it. The funding and execution were questionable, but the impact was significant. The report rated medical schools in the North Americas, identifying those meeting and those failing to meet a set of standards devised by the benefactor of the report. As a result, more than half of the medical schools in the US were closed or lost significant funding.&lt;br /&gt;&lt;br /&gt;The remaining medical schools were incapable of meeting the demand while simultaneously implementing residency programs. It was not until the 1960s that residency was common practice for all medical students. As late as the 1980s, some medical licensing still did not have a residency requirement.&lt;br /&gt;&lt;h5&gt;Today&lt;/h5&gt;As mentioned at the onset, the medical industry now embraces life-long learning with a balanced focus on clinical and non-clinical learning.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;General / Specialized Medicine&lt;/li&gt;&lt;li&gt;Internship / Residency&lt;/li&gt;&lt;li&gt;Licensing / Certification&lt;/li&gt;&lt;li&gt;Collaborative Learning&lt;/li&gt;&lt;li&gt;Continuing Education&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Lessons and What Next&lt;/h3&gt;&lt;h4&gt;Lessons&lt;/h4&gt;Scholastic education is merely the beginning. Knowledge is far more valuable when we know how to apply it. Licensing and Certification can have a positive impact on the level of professionalism. Practitioners share knowledge amongst themselves and create opportunities to learn together. Professionals engage in intentional life-long learning.&lt;br /&gt;&lt;h4&gt;What Next&lt;/h4&gt;As I said at the onset, I don't believe I have the answers. I'm not even certain I have all the right questions. But I am certain that we, as a community, have everything we need to effectively address the issue of quality in our profession.&lt;br /&gt;&lt;h3&gt;We Need To Talk&lt;/h3&gt;We need to talk amongst ourselves and with others. We need to talk about what we're doing to actively improve the quality of software. Or more accurately, what we're actively doing to improve the quality of software practitioners, through whom, software is developed and delivered.&lt;br /&gt;&lt;br /&gt;But talk should not take too long. Rhetoric may convince many, but will achieve little.&lt;br /&gt;&lt;h3&gt;We Need to Act.&lt;/h3&gt;Do something. Learn from it. Adjust.&lt;br /&gt;&lt;h5&gt;References&lt;/h5&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Lucida Grande', verdana, arial, helvetica, sans-serif; font-size: 14px; line-height: 19px;"&gt;&lt;a href="http://books.google.com/books?id=afYzWG1FLroC&amp;amp;printsec=frontcover&amp;amp;dq=history+of+medical+education&amp;amp;source=bl&amp;amp;ots=M4YGTvQ7A0&amp;amp;sig=vwJ5CAGuScAY6NYn3tyZtr-FyyA&amp;amp;hl=en&amp;amp;ei=fESnTOStBIWdlgeh9I3bDQ&amp;amp;sa=X&amp;amp;oi=book_result&amp;amp;ct=result&amp;amp;resnum=7&amp;amp;ved=0CD8Q6AEwBg#v=twopage&amp;amp;q&amp;amp;f=false" style="color: #0033cc; padding-bottom: 1px; padding-left: 1px; padding-right: 1px; padding-top: 1px; text-decoration: underline;"&gt;The History of medical education: an international symposium …, Volume 673&lt;/a&gt;&amp;nbsp;By Charles Donald O’Malley, University of California, Los Angeles. Dept. of Medical History&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Medicine" style="color: #0033cc; padding-bottom: 1px; padding-left: 1px; padding-right: 1px; padding-top: 1px; text-decoration: underline;"&gt;Medicine&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Medical_school" style="color: #0033cc; padding-bottom: 1px; padding-left: 1px; padding-right: 1px; padding-top: 1px; text-decoration: underline;"&gt;Medical School&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Schola_Medica_Salernitana" style="color: #0033cc; padding-bottom: 1px; padding-left: 1px; padding-right: 1px; padding-top: 1px; text-decoration: underline;"&gt;Schola Medica Salernitana&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Medical_education_in_the_United_States" style="color: #0033cc; padding-bottom: 1px; padding-left: 1px; padding-right: 1px; padding-top: 1px; text-decoration: underline;"&gt;Medical Education in the United States&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.google.com/search?q=history+of+medical+education&amp;amp;hl=en&amp;amp;prmd=ivb&amp;amp;tbs=tl:1&amp;amp;tbo=u&amp;amp;ei=fESnTOStBIWdlgeh9I3bDQ&amp;amp;sa=X&amp;amp;oi=timeline_result&amp;amp;ct=title&amp;amp;resnum=11&amp;amp;ved=0CFAQ5wIwCg" style="color: #0033cc; padding-bottom: 1px; padding-left: 1px; padding-right: 1px; padding-top: 1px; text-decoration: underline;"&gt;History Medical Education&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/History_of_medicine" style="color: #0033cc; padding-bottom: 1px; padding-left: 1px; padding-right: 1px; padding-top: 1px; text-decoration: underline;"&gt;History of Medicine&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Hippocrates" style="color: #0033cc; padding-bottom: 1px; padding-left: 1px; padding-right: 1px; padding-top: 1px; text-decoration: underline;"&gt;Hippocrates&lt;/a&gt;&lt;br /&gt;&lt;a href="http://theglitteringeye.com/?p=1707" style="color: #0033cc; padding-bottom: 1px; padding-left: 1px; padding-right: 1px; padding-top: 1px; text-decoration: underline;"&gt;A short history of medical education in the United States&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/The_Canon_of_Medicine" style="color: #0033cc; padding-bottom: 1px; padding-left: 1px; padding-right: 1px; padding-top: 1px; text-decoration: underline;"&gt;The Canon of Medicine&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.nejm.org/doi/full/10.1056/NEJMra055445#t=article" style="color: #0033cc; padding-bottom: 1px; padding-left: 1px; padding-right: 1px; padding-top: 1px; text-decoration: underline;"&gt;American Medical Education 100 Years after the Flexner Report&lt;/a&gt;&lt;br /&gt;&lt;em&gt;The acquisition of skills for practice requires radical transformation. Although the dictum “see one, do one, teach one” may have characterized the way in which clinical skills were learned in the past, it is now clear that for training in skills to be effective, learners at all levels must have the opportunity to compare their performance with a standard and to practice until an acceptable level of proficiency is attained.&lt;/em&gt;&lt;br /&gt;- The New England Journal of Medicine, September 28, 2006&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Internship_(medical)" style="color: #0033cc; padding-bottom: 1px; padding-left: 1px; padding-right: 1px; padding-top: 1px; text-decoration: underline;" title="Medical"&gt;Internship&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Residency_(medicine)" style="color: #0033cc; padding-bottom: 1px; padding-left: 1px; padding-right: 1px; padding-top: 1px; text-decoration: underline;" title="Medical"&gt;Residency&lt;/a&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/William_Osler" style="color: #0033cc; padding-bottom: 1px; padding-left: 1px; padding-right: 1px; padding-top: 1px; text-decoration: underline;"&gt;William Osler&lt;/a&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: 'Lucida Grande', verdana, arial, helvetica, sans-serif; font-size: 14px; line-height: 19px;"&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-7986664730069627695?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/7986664730069627695/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/10/training-software-professionals.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7986664730069627695'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7986664730069627695'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/10/training-software-professionals.html' title='Training Software Professionals'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-8390117249409032877</id><published>2010-10-25T15:09:00.003-04:00</published><updated>2010-10-25T15:15:51.739-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Uncle Bob on Humility</title><content type='html'>&lt;div class="p1"&gt;The following just hit my inbox. It is a post on the &lt;a href="http://groups.google.com/group/software_craftsmanship?hl=en&amp;amp;pli=1" target="_blank"&gt;Software Craftsmanship Google Group&lt;/a&gt;.&lt;/div&gt;&lt;div class="p1"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="p1"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="p1"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;On Oct 24, 2010, at 12:36 , David Starr wrote:&lt;/span&gt;&lt;/div&gt;&lt;div class="p2"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="p3"&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;My question is, "what can be done to fix the reputation [of elitism] and change the conversation before craftsmanship is deemed irrelevant"?&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="p2"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="p1"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;"&gt;As a craftsman I am dedicated to improving myself; and therefore I realize I am deficient. &amp;nbsp;As someone who is admittedly deficient, I am not interested in pointing out someone else's deficiencies. &amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class="p2"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="p1"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;"&gt;In general, whenever someone asks "what can we, as a group, do to ...", the best answer is going to be of the form: "Each of us, as an individual, should ...". &amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div class="p2"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="p1"&gt;&lt;span class="Apple-style-span" style="font-family: 'Trebuchet MS', sans-serif;"&gt;So, to deal with perceived elitism, each of us as individuals should remember that we are not elite.&lt;/span&gt;&lt;/div&gt;&lt;div class="p2"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="p4"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;----&lt;/span&gt;&lt;/div&gt;&lt;div class="p4"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Robert C. Martin (Uncle Bob)&amp;nbsp;&amp;nbsp;| email: &lt;/span&gt;&lt;span class="s1"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;uncle*@objectmentor.com&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="p4"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;Object Mentor Inc. &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;| blog:&amp;nbsp; &lt;/span&gt;&lt;a href="http://blog.objectmentor.com/"&gt;&lt;span class="s1"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;blog.objectmentor.com&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="p4"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', 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;| web:&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;a href="http://www.objectmentor.com/"&gt;&lt;span class="s1"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;www.objectmentor.com&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="p4"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', 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;| twitter: unclebobmartin&lt;/span&gt;&lt;/div&gt;&lt;div class="p5"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="p5"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="p5"&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/8528631747209969303-8390117249409032877?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/8390117249409032877/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/10/uncle-bob-on-humility.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/8390117249409032877'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/8390117249409032877'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/10/uncle-bob-on-humility.html' title='Uncle Bob on Humility'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-7430121211859139667</id><published>2010-10-24T21:29:00.000-04:00</published><updated>2010-10-24T21:29:20.571-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Games'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><title type='text'>Packing Peanuts Game - Variation</title><content type='html'>&lt;h3&gt;Searching for a Game&lt;/h3&gt;I was looking for a game that helped to emphasize the detrimental results of a focus on speed over quality. How such an approach had only a short-term gain and then proved to be more costly from there forth.&lt;br /&gt;&lt;h3&gt;The Original Game&lt;/h3&gt;I don't know if this is really the original version of the &lt;a href="http://blog.tastycupcakes.com/2010/05/packing-peanuts/" target="_blank"&gt;Packing Peanuts Game&lt;/a&gt;, but it is certainly the first I've found.&lt;br /&gt;&lt;br /&gt;The game was posted to tastycupcakes by &lt;a href="http://www.shojiki-solutions.com/" target="_blank"&gt;Masa K Maeda&lt;/a&gt;, on May 21st, 2010&lt;br /&gt;&lt;br /&gt;Masa identified the game as a way of "understanding what Technical Debt is and why it is so costly to projects." You already know &lt;a href="http://www.docondev.com/search/label/Technical%20Debt"&gt;my feelings on calling sloppy code Technical Debt&lt;/a&gt;, so I won't go into that here. But it is a decent game for showing that haste does in fact make waste and the only way to truly go fast is to go well.&lt;br /&gt;&lt;h5&gt;Timing:&lt;/h5&gt;10 minutes&lt;br /&gt;&lt;h5&gt;Ingredients:&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;4 cardboard boxes. Size: around the standard size of a moving box (13”x18”x12”)&lt;/li&gt;&lt;li&gt;Enough packing peanuts to fill two of the boxes&lt;/li&gt;&lt;li&gt;2 people&lt;/li&gt;&lt;ul&gt;&lt;li&gt;You can do this exercise with more people, adding 2 at a time, up to 6 people without the need to have more boxes or packing peanuts&amp;nbsp;&lt;/li&gt;&lt;li&gt;For more than 6 people you’ll need to add more boxes and packing peanuts&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;h5&gt;Setup:&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;Set 2 lanes across the room&lt;/li&gt;&lt;li&gt;For each lane place one cardboard box (opened for easy access) at each end of the lane.&lt;/li&gt;&lt;li&gt;Fill the boxes at the same end of the lanes with packing peanuts: one of them at 70% capacity, and the other one at 90% capacity&lt;/li&gt;&lt;li&gt;Each participant will stand next to a box with packing peanuts&lt;/li&gt;&lt;/ul&gt;&lt;h5&gt;Execute:&lt;/h5&gt;Explain the participants their goal: To transfer all the peanuts from the box next to them to the box at the other end of their respective lanes.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;The person with the 70%-full box is to transfer all of them in three trips and can use hands and arms (and support them on his/her belly if so desired), but nothing else&lt;/li&gt;&lt;li&gt;The person with the 90%-full box can take as many trips as desired and can use both hands only&lt;/li&gt;&lt;li&gt;The boxes are not to be lifted, tilted, shifted or other. Their sole purpose is to contain the peanuts&lt;/li&gt;&lt;li&gt;Peanuts that fall on the floor are left there&lt;/li&gt;&lt;li&gt;There is no time limit&lt;/li&gt;&lt;li&gt;Do not run and watch your step&lt;/li&gt;&lt;li&gt;Start the game&lt;/li&gt;&lt;li&gt;Let them play for about 2 minutes or until one of them accomplishes the task&lt;/li&gt;&lt;/ul&gt;&lt;h5&gt;Expected Results:&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;The person with the 90%-full box will finish first or will have transferred more peanuts once the time is up&lt;/li&gt;&lt;li&gt;The person with the 70%-full box typically drops way more peanuts to the floor&lt;/li&gt;&lt;li&gt;The person with the 70%-full box exerts and stresses more&lt;/li&gt;&lt;/ul&gt;&lt;h5&gt;Learning Points:&lt;/h5&gt;The peanuts represent features or aspects of features, and those on the floor represent unfinished work, bugs, etc.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;One trip represents a release cycle: more peanuts per trip represent a bigger release&lt;/li&gt;&lt;li&gt;Big monolithic projects generate more technical debt&lt;/li&gt;&lt;li&gt;Big monolithic projects take more energy out of people, and stress them more&lt;/li&gt;&lt;li&gt;Trying to bring all features from start to end at once is way more difficult&lt;/li&gt;&lt;li&gt;Bringing features to completion in small chunks is easier, and generates less technical debt (less peanuts on the floor)&lt;/li&gt;&lt;li&gt;Bringing features to completion in small chunks allows people to work at a better pace and under less stress&lt;/li&gt;&lt;li&gt;Bringing features to completion in small chunks results in more features done in less time&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Variation&lt;/h3&gt;&lt;div&gt;This variation of the game is designed to further accentuate the cost of allowing cruft to build up in the code base.&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Clearly mark the lanes at 24 inches wide.&lt;/li&gt;&lt;li&gt;Teams must travel within their lanes.&lt;/li&gt;&lt;li&gt;When the game starts, the source box has peanuts and the destination box does not.&lt;/li&gt;&lt;li&gt;Fill both source boxes to 90%.&lt;/li&gt;&lt;li&gt;Team A is limited to four trips, but can use arms, chest, and stomach to hold as many peanuts as possible.&lt;/li&gt;&lt;ul&gt;&lt;li&gt;No pouching of clothes or putting peanuts in pockets or up/down clothing.&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Team B can use as many trips as desired, but can use only hands.&lt;/li&gt;&lt;li&gt;When returning to the source box, Team B must collect any previously dropped peanuts and return them to the source box.&lt;/li&gt;&lt;li&gt;Team A does not need to pick up dropped peanuts unless they step on them&lt;/li&gt;&lt;li&gt;Team A must immediately collect any peanuts they step on&lt;/li&gt;&lt;li&gt;Moderators monitor Teams' peanuts and lanes&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Any peanuts dropped outside of a lane are immediately swept into the lane.&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Play until either Team A is out of moves or Team B transfers all peanuts, whichever is first.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;The idea here is to model what happens in many companies. The team is permitted and even encouraged to go fast and sloppy for some period of time. But the mess eventually impedes the team's ability to move forward at all.&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/8528631747209969303-7430121211859139667?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/7430121211859139667/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/10/packing-peanuts-game-variation.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7430121211859139667'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7430121211859139667'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/10/packing-peanuts-game-variation.html' title='Packing Peanuts Game - Variation'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-3376588967006873893</id><published>2010-10-19T08:43:00.003-04:00</published><updated>2010-10-19T12:51:00.124-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Manager'/><category scheme='http://www.blogger.com/atom/ns#' term='Teams'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Code as a Cause of Project Failure</title><content type='html'>&lt;h3&gt;The original question&lt;/h3&gt;During the speaker panel at &lt;a href="http://scna.softwarecraftsmanship.org/"&gt;SCNA&lt;/a&gt; this past weekend, Chad Fowler (&lt;a href="http://twitter.com/chadfowler"&gt;@chadfowler&lt;/a&gt;) asked, "How many projects fail because of the code?". Given the context, I assumed he was making the point that projects fail due to business issues, not code. The room was silent. While one might have assumed this meant the entire group thought it rhetorical, I concluded everyone agreed with Chad. Projects fail not due to code, but due to business issues.&lt;br /&gt;&lt;h3&gt;The follow-up&lt;/h3&gt;Uncle Bob (&lt;a href="http://twitter.com/unclebobmartin"&gt;@unclebobmartin&lt;/a&gt;) later did a quick twitter survey, which I and many others took part in. The results were overwhelmingly in favor of project failure being more attributable to business issues than technical issues. Bob felt many might take this to mean that code is not all that important in the long run and that craftsmanship, therefor, is not all that important either. Bob put together a well thought-out argument explaining why code is important and how it can, in fact, kill not only a project, but entire companies. Rather than reiterate it here, I strongly encourage you to read Bob's article, "&lt;a href="http://thecleancoder.blogspot.com/2010/10/cost-of-code.html"&gt;The Cost of Code?&lt;/a&gt;"&amp;nbsp;I agree with most of what Bob says in this article. The Cost of Code is high. I don't agree that all failed projects are due to code, but his points in support of that statement are no less valid.&lt;br /&gt;&lt;h3&gt;Cause versus Responsibility&lt;/h3&gt;&lt;h4&gt;Smoking Guns&lt;/h4&gt;A man lays dead; a single bullet wound in his chest. A project fails; a mass of crappy code remains. Perhaps it is clear to you that a bullet killed the man. Perhaps it is clear to you that crappy code killed the project. Rather than enumerating other possible conclusions, given our substantial lack of evidence, I will conceded both points. The man was killed by a single bullet and the project was killed by crappy code.&lt;br /&gt;&lt;br /&gt;Yes, technically, the project failed due to code.&lt;br /&gt;&lt;h4&gt;Trigger Men&lt;/h4&gt;Our tragedies do not end there. We can no more stop murder by eliminating bullets than we can save projects by eliminating the need for code. While the bullet or the code may be the cause, they are both effects as well.&lt;br /&gt;&lt;br /&gt;Somebody pulled the trigger.&lt;br /&gt;&lt;br /&gt;In large projects, identifying one guilty party is commonly impossible not to mention grossly naive. In large projects, there are typically many humans responsible for the failure. If we were to perform archeological studies on the ruins of most projects, I am confident we'd find the failure to be between people. I am confident we would find it was a failure of communication. Not one, but hundreds or even thousands of failures; large and small. Lack of vision. Lack of clarity. Lack of cohesion due to lack of vision and clarity. Lack of clear expectations. Unclear status. Keeping quiet when we disagree. Raising disagreements in a non-constructive manner. Approaching debate as if it were battle.&amp;nbsp;Inflammatory&amp;nbsp;language that creates divides. Hiding our mistakes. Sending an email instead of making a phone call. Making a phone call instead of meeting face to face. Too much emphasis on delivery. Thinking speed and quality are diametrically opposed. Undervaluing the work of others. Apathy. The list goes on.&lt;br /&gt;&lt;br /&gt;On a software project, code is critical. You can't have a software project without code. The worse the code, the greater the risk to the project. Bad enough and the project will fail as a result of the code. Significant enough, and the company will fail as a result of the project.&lt;br /&gt;&lt;br /&gt;But don't forget it is we who write the code.&lt;br /&gt;&lt;br /&gt;It is we who pull the trigger.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-3376588967006873893?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/3376588967006873893/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/10/code-as-cause-of-project-failure.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/3376588967006873893'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/3376588967006873893'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/10/code-as-cause-of-project-failure.html' title='Code as a Cause of Project Failure'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-5646492878478607530</id><published>2010-10-18T14:46:00.000-04:00</published><updated>2010-10-18T14:46:06.667-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><title type='text'>On The Scrum Compliance</title><content type='html'>&lt;span class="Apple-style-span" style="color: #333333; font-family: Arial, Helvetica, 'Nimbus Sans L', sans-serif; font-size: 13px; line-height: 15px;"&gt;A recent article by Tobias Mayer has been getting a lot of attention. "&lt;a href="http://agileanarchy.wordpress.com/2010/10/12/the-scrum-compliance/"&gt;The Scrum Compliance&lt;/a&gt;" is an accounting of why Tobias is moving on from the Scrum Alliance. This article is not the first on the ugliness that has become the Scrum Alliance.&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: Arial, Helvetica, 'Nimbus Sans L', sans-serif; font-size: 13px; line-height: 15px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: Arial, Helvetica, 'Nimbus Sans L', sans-serif; font-size: 13px; line-height: 15px;"&gt;I've read this article a number of times and I am disheartened by all of this. Such an ugly series of events playing out in an opaque manner on a semi-public stage. We hear pieces of what has transpired and assumptions about what motivates the participants. We get facts mixed with opinion mixed with emotion. The "logical" conclusions, when seriously considered are not logical. That the committee representing the Scrum Alliance is comprised of power-greedy oligarchs does not at all seem like a logical conclusion. Yet, I hear it stated as if it is known fact based on the "evidence".&lt;br /&gt;&lt;br /&gt;I'm neither defending nor attacking anyone here. I think Tobias is an honorable man who speaks from the heart. I am not saying that he is right or that he is wrong. I am saying I do not know, that very few of us actually does, and that he alone cannot tell the entire story.&lt;br /&gt;&lt;br /&gt;Regardless, I now question my connections with the Scrum Alliance. They are not particularly tight, but whether I believe the rumors or not, it seems a good time to be a distance from the SA rather than standing next to it, taking shrapnel.&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-5646492878478607530?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/5646492878478607530/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/10/on-scrum-compliance.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/5646492878478607530'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/5646492878478607530'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/10/on-scrum-compliance.html' title='On The Scrum Compliance'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-7812921916552701753</id><published>2010-10-10T18:37:00.001-04:00</published><updated>2010-10-10T18:39:36.405-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='User Experience'/><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><title type='text'>Esther Derby asks: Are we aiming too low?</title><content type='html'>&lt;h3&gt;Esther Derby's Post&lt;/h3&gt;Esther Derby put together a nice post on the importance of design for a web site in which she asks, &lt;a href="http://www.estherderby.com/2010/09/are-we-aiming-too-low.html" target="_blank"&gt;"Are we aiming too low?"&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Agile methods manage business risk. They can bring back enjoyment and pride in work for development teams. For the people who use our software, they make work life maybe less frustrating, because the software isn’t buggy, and maybe a little easier because the software does what it’s supposed to do. But I think we are aiming too low. Can we also make software a pleasure to use?&lt;/blockquote&gt;&lt;h3&gt;Makes me wonder&lt;/h3&gt;&lt;h4&gt;Story Composition&lt;/h4&gt;&lt;div&gt;I've been working with teams lately on story composition. We've been discussing how we could break stories down based on value to the business rather than based on how we technically execute. Our objective is to be able to deliver value to the business as quickly as possible. So we want to avoid chunking larger stories out into smaller stories that are then dependent upon one another for delivery. We've really achieved nothing other than creating bottlenecks in our flow. We still have to build the whole thing in order to deliver.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So a common technique we've been using is to break out aspects of the story that are must have from nice to have. Often, this ends up being along the seam between functional and sexy. With functional clearly being must and sexy riding shotgun at best.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Executing on this strategy, we are able to deliver functionality faster and we haven't any dependencies between the stories other than the must have need to come first. But this is perfectly acceptable to the team. Must have should come first.&lt;/div&gt;&lt;h4&gt;Are we missing something important?&lt;/h4&gt;&lt;div&gt;I think we are. I think by consistently breaking the stories down in this manner, we are cheating the customer. We keep putting features that make the application nice to use on the back burner. Frequently they don't get implemented because the next "must haves" bubble to the top of the queue as the "nice to haves" slowly drop.&lt;br /&gt;&lt;br /&gt;But by executing in this manner, we are consistently missing the opportunity to make the user experience truly pleasurable. We are focusing too much on utility and not enough on what makes the application truly&amp;nbsp;desirable.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-7812921916552701753?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/7812921916552701753/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/10/esther-derby-asks-are-we-aiming-too-low.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7812921916552701753'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7812921916552701753'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/10/esther-derby-asks-are-we-aiming-too-low.html' title='Esther Derby asks: Are we aiming too low?'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-7952845394492759305</id><published>2010-10-06T17:15:00.002-04:00</published><updated>2010-10-06T23:09:59.334-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><category scheme='http://www.blogger.com/atom/ns#' term='Technical Debt'/><title type='text'>Technical Debt versus Cruft</title><content type='html'>&lt;h3&gt;Am I Tilting at Windmills?&lt;/h3&gt;&lt;div&gt;I repeatedly find myself in discussions with really smart and experienced people regarding Technical Debt. And I consistently find myself ranting about how cruft and technical debt are not the same thing. I am beginning to feel I am merely &lt;a href="http://en.wikipedia.org/wiki/Tilting_at_windmills" target="_blank"&gt;tilting at windmills&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I don't know if my prior rants on the topic of &lt;a href="http://www.docondev.com/search/label/Technical%20Debt"&gt;Technical Debt&lt;/a&gt; have provided sufficient clarity. In them, I try to better define Technical Debt and point out the differences between it and cruft. But I do not provide any tangible examples. Herein, I attempt to remedy that situation. Today's installment is in narrative form. I intend to provide a later post with code examples.&lt;br /&gt;&lt;h3&gt;Technical Debt - A brief reprise&lt;/h3&gt;Ward Cunningham coined the phrase &lt;a href="http://c2.com/doc/oopsla92.html" target="_blank"&gt;Technical Debt&lt;/a&gt;&lt;br /&gt;&lt;blockquote&gt;"Shipping first time code is like going into debt. A little debt speeds development so long as it is paid back promptly with a rewrite. Objects make the cost of this transaction tolerable. The danger occurs when the debt is not repaid. Every minute spent on not-quite-right code counts as interest on that debt. Entire engineering organizations can be brought to a stand-still under the debt load of an unconsolidated implementation, object- oriented or otherwise."&lt;/blockquote&gt;As he clarifies later in a You-Tube video, Ward was specifically talking about design decisions made in the course of developing software that allowed for more rapid delivery. Rapid delivery not for the sake of meeting a deadline. Rapid delivery to illicit quick feedback, thereby providing the data necessary to adjust the design to be more congruent with actual needs. The object design should change to reflect your current understanding of the domain, even if that understanding is partial. Technical debt is payed back through code refactoring as our understanding of the domain matures.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.youtube.com/watch?v=pqeJFYwnkjE&amp;amp;feature=player_embedded" target="_blank"&gt;Ward clearly states&lt;/a&gt;, "&lt;i&gt;The ability to pay back debt [...] depends upon you writing code that is clean enough to be able to refactor as you come to understand your problem.&lt;/i&gt;"&lt;br /&gt;&lt;br /&gt;Clean Code is actually a prerequisite for Technical Debt. If you don't have Clean Code, you cannot expect to pay the debt back. If you have cruft, you cannot reasonably incur Technical Debt. In fact, you are not incurring debt, you are merely adding to the existing mess.&lt;/div&gt;&lt;h3&gt;Examples (in&amp;nbsp;Narrative&amp;nbsp;Form)&lt;/h3&gt;&lt;h4&gt;Technical Debt&lt;/h4&gt;&lt;h5&gt;Example One&lt;/h5&gt;We are building a new application to allow our customer to sell widgets and parts to distributors.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Widgets represent 75% of the sales.&lt;/li&gt;&lt;li&gt;82% of the customers order on terms.&lt;/li&gt;&lt;li&gt;The cross-section of these two groups represents 69% of all sales.&lt;/li&gt;&lt;/ul&gt;In order to get the application running and generating revenue, we decide to launch with only widgets and terms. We will sell parts later. We will also add other forms of payment later.&lt;br /&gt;&lt;br /&gt;This is a strategic decision. We are creating a design that we know will have to change. We know we will re-visit this code and perhaps even throw away some (or much) of it.&lt;br /&gt;&lt;br /&gt;But we write it well, we test drive it, and we do not compromise quality. We will defer to the last responsible moment and make the design adjustments based on what the business determines is the next highest value activity when it is decided.&lt;br /&gt;&lt;h5&gt;Example Two&lt;/h5&gt;We are working with a third party API for determination of flood plane coverage for a given property. We want to know this so we can decide if we will or will not provide an applicant a loan. We don't give loans on properties in&amp;nbsp;flood planes.&lt;br /&gt;&lt;br /&gt;We can make numerous calls to the service. One, which is simple, will tell us if the property is in a flood plane or not. This is all we need to know for an accept or reject call.&lt;br /&gt;&lt;br /&gt;We decide to go ahead with this basic functionality and make sure the service is consistently reliable in terms of uptime, speed, and accuracy. We are going to run one server against the new service and leave the others running against the old (slow and more expensive) service.&lt;br /&gt;&lt;br /&gt;Once we've determined the service provider is reliable, we will also code the pieces for garnering more specific data. It would be good to have this on the loan application record if there are any questions in the future, but it is not mandatory.&lt;br /&gt;&lt;br /&gt;This is a strategic decision. We are creating a design that we know will be either eliminated or expanded.&lt;br /&gt;&lt;br /&gt;We write all of the code well. We test drive it. After a period of learning, we will either toss the code or we will add new features.&lt;br /&gt;&lt;h4&gt;Cruft&lt;/h4&gt;We are working on a system to schedule production of widgets on the factory floor.&lt;br /&gt;&lt;br /&gt;We have a bonus initiative to get the application done by the end of the year.&amp;nbsp;It is September and we're just getting started due to delays in the delivery of our prior project. According to the schedule, we should have started in May. If we miss the deadline, there will be much gnashing of teeth. If we miss the deadline, we will not get our bonus. We ask our boss if we can deliver only part of the application, but her bonus is much more significant and requires complete delivery. She denies the request, admonishes us for putting her in this situation, and reiterates the priority of this project for "the business". She let's us know that the CEO is watching this one. The CEO was watching the last project too. That's how important IT is to the corporate strategy.&lt;br /&gt;&lt;br /&gt;So we work like crazy. We skip unit testing. We work in silos and make decisions on the fly about ambiguous requirements. We notice the FillQueue class is getting quite large and everything is dependent on it. But we don't have time to change it. It works and we are under pressure to deliver. Besides, we could no longer test these classes in isolation if we wanted to. We'd have to tease them apart at the seams and that could take weeks. It is getting more and more difficult to write the code. It is like a bowl of gelatin; you touch it down here and it wiggles up there? Why does it do that? Whatever. We need to make the deadline.&lt;br /&gt;&lt;br /&gt;This is the wrong decision for the business. This is not a strategic initiative. This is not professional or even ethical behavior. This is a failure.&lt;br /&gt;&lt;br /&gt;But bonuses got paid.&lt;br /&gt;&lt;h3&gt;What about you?&lt;/h3&gt;I've been told delivery teams don't take on Technical Debt as a strategic initiative, rather most produce cruft and then call it Technical Debt. Help me prove otherwise. Please post a comment with an example of Technical Debt (not Cruft) taken on by a team you worked on.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-7952845394492759305?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/7952845394492759305/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/10/technical-debt-versus-cruft.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7952845394492759305'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7952845394492759305'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/10/technical-debt-versus-cruft.html' title='Technical Debt versus Cruft'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-3972639940088386915</id><published>2010-10-04T10:53:00.002-04:00</published><updated>2011-02-14T08:46:06.133-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Career'/><title type='text'>Values Revisited</title><content type='html'>&lt;h3&gt;Then&lt;/h3&gt;In 1992, I started a custom software development company out of my basement. I started it because I was angry. At a relatively young age, I was already keenly aware of the gross dysfunction that existed in most organizations. I didn't want to be a part of that. I wanted to be a part of something different; something better. I had no plan, but I had an abundance of temerity.&lt;br /&gt;&lt;br /&gt;Our progression over the years was adventurous, romantic, and stupid. Moving into our first real office. Housing my partner in my basement. Running out of gas on the way back from a critical meeting because we didn't have enough cash to fill the tank. The victories. The losses. The&amp;nbsp;camaraderie. The angst among us.&lt;br /&gt;&lt;br /&gt;By 1997, we were close to 20 people. Tiny, yes, but I felt it was too big for me to handle at the time. I was 29 years old with no formal education and limited "real-world" experience. My penchant for self doubt was getting the better of me; temerity had been replaced by timidity.&lt;br /&gt;&lt;br /&gt;In a moment of melancholy and introspection, I sat down and drafted the following. It was my intention to express a core set of values to the employees of my fledgling company. And I do suppose it served that purpose. But it was the first time I had committed to paper the things I was looking for in a company. Perhaps the things I was looking for in life.&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;h3&gt;Our Values...&lt;/h3&gt;... are the foundation for all decisions. They serve as the compass that guides us through our personal and professional lives. All action; all thought; in every way we represent ourselves; we must represent our values.&lt;br /&gt;&lt;h4&gt;Be fair.&lt;/h4&gt;Find the answer that best serves all parties. Act upon your highest sense of right.&lt;br /&gt;&lt;h4&gt;Improve.&lt;/h4&gt;Grow continuously, personally and professionally, in small ways. Evolution is the sum of many tiny, nearly indiscernible adjustments.&lt;br /&gt;&lt;h4&gt;Innovate.&lt;/h4&gt;Seek new ways; seek new means; do the unexpected.&lt;br /&gt;&lt;h4&gt;Take Initiative.&lt;/h4&gt;Present your ideas. Put forth the extra effort. The one who makes the most mistakes, learns the most lessons.&lt;br /&gt;&lt;h4&gt;Be accountable.&lt;/h4&gt;Answer for your mistakes and your deserved praise will come.&lt;br /&gt;&lt;h4&gt;Be forgiving.&lt;/h4&gt;Seek to understand and assist. Do not condemn others for their differences. To criticize and dismiss leaves neither party better off.&lt;br /&gt;&lt;h4&gt;Participate.&lt;/h4&gt;Become truly involved. Make this your team, for it already is.&lt;br /&gt;&lt;h4&gt;Have respect.&lt;/h4&gt;Honor your coworkers and clients.&lt;br /&gt;&lt;h4&gt;Live.&lt;/h4&gt;Make your life rich in many ways. Seek new experiences, new relationships, and a new perspective. Then bring it back and teach others.&lt;br /&gt;&lt;h4&gt;And always, Tell The Truth.&lt;/h4&gt;&lt;div style="text-align: right;"&gt;&lt;span class="Apple-style-span" style="color: #999999;"&gt;- Michael J. Norton (1997)&lt;/span&gt;&lt;/div&gt;&lt;hr /&gt;&lt;br /&gt;&lt;h3&gt;Since&lt;/h3&gt;In 2001, we closed the company. The values statement had been posted on my wall for several years. It had become invisible. Sitting in the same place year after year, it was no different than the pencil holder on my desk. I could look in the general direction and not consciously recognize it was there. Only when I specifically sought it out did I truly see it. And I had stopped seeking it out.&lt;br /&gt;&lt;br /&gt;By the time we officially closed the company, I had returned to corporate America, seeking knowledge, wealth, and (most of all) security. As I noted, temerity had long since given way to timidity.&lt;br /&gt;&lt;br /&gt;For several years, I climbed the ladder making my way to CTO. I kept the values statement in my day planner. But it was still invisible. I did not seek it out. And when I stumbled upon it, I glanced and moved on. I felt that most around me were living by a different set of values and that perhaps I was too naive and idealistic.&lt;br /&gt;&lt;br /&gt;In 2009, I was let go. I should have resigned of my own will, but I was too much a coward, so they provided me the opportunity.&lt;br /&gt;&lt;br /&gt;I was feeling melancholy and introspective and for the first time in nearly a decade, I looked at my values statement again. I mean really looked at it.&lt;br /&gt;&lt;br /&gt;And I changed my life.&lt;br /&gt;&lt;h3&gt;Now&lt;/h3&gt;I am a partner in &lt;a href="http://www.leandog.com/" target="_blank"&gt;a firm that is consistent with my values&lt;/a&gt;. I do work that allows me to share these values with others in indirect ways. I surround myself with people who represent who and what I wish to be.&lt;br /&gt;&lt;br /&gt;And I make sure that I take the statement out every so often and look at it.&amp;nbsp;I mean really look at it. Melancholy not required.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-3972639940088386915?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/3972639940088386915/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/10/values-revisited.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/3972639940088386915'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/3972639940088386915'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/10/values-revisited.html' title='Values Revisited'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-3403866245074406464</id><published>2010-09-30T16:40:00.000-04:00</published><updated>2010-09-30T16:40:17.577-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Manager'/><category scheme='http://www.blogger.com/atom/ns#' term='Teams'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><category scheme='http://www.blogger.com/atom/ns#' term='How To'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Retrospectives'/><title type='text'>A blank wall and a fist full of index cards</title><content type='html'>&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial; font-size: small;"&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: Arial, Helvetica, 'Nimbus Sans L', sans-serif; line-height: 15px;"&gt;I'm&amp;nbsp;occasionally&amp;nbsp;asked, "Doc, we're looking at product X, Y, and Z, but we just can't decide which is the best one for our project. What do you recommend?"&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial; font-size: small;"&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: Arial, Helvetica, 'Nimbus Sans L', sans-serif; font-size: 13px; line-height: 15px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial; font-size: small;"&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: Arial, Helvetica, 'Nimbus Sans L', sans-serif; line-height: 15px;"&gt;I've used VersionOne, Rally, Mingle, Pivotal Tracker, Kanbanery, ScrumWorks, and a couple of others including Excel spreadsheets.&lt;br /&gt;&lt;br /&gt;For the most part, the tool gets in the way. And people getting started in agile frequently confuse what the tool is capable of (or appears to be capable of) for agile "best practices". If the tool doesn't allow you to add lanes or queues, then you shouldn't be using them. If the tool says to estimate everything in points using Fibonacci, then you shouldn't use t-shirt sizes. If the tool provides reports on personal velocity, then you must need to know personal velocity.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial; font-size: small;"&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: Arial, Helvetica, 'Nimbus Sans L', sans-serif; line-height: 15px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial; font-size: small;"&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: Arial, Helvetica, 'Nimbus Sans L', sans-serif; line-height: 15px;"&gt;I think you get the point.&lt;br /&gt;&lt;br /&gt;I like to start teams off with a simple card wall. Maybe it is a kanban board. Maybe it is a scrum board. Whatever it is, we design it together in a single session where we make broad-stroke decisions about our process.&lt;br /&gt;&lt;br /&gt;We retrospect frequently (regularly) and evaluate if the board is working for us or not. "Does the story wall appropriately tell our story?" Then we make adjustments (or not). Sometimes, we agree to revisit on a set date. Sometimes, we roll with it knowing we can always change it.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial; font-size: small;"&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: Arial, Helvetica, 'Nimbus Sans L', sans-serif; line-height: 15px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial; font-size: small;"&gt;&lt;span class="Apple-style-span" style="font-size: 13px;"&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: Arial, Helvetica, 'Nimbus Sans L', sans-serif; line-height: 15px;"&gt;My advice is to use the wall until you've perfected your process and then select the right tool. I've yet to see a team move to a software tool after a few months of working with cards.&lt;br /&gt;&lt;br /&gt;In the interest of full disclosure, I did work on a multi-million dollar project with teams in various locations around the world. In this instance, I felt an electronic tool was beneficial as it was a good way to communicate work status across all locations. It created a universal card wall. But even then, we kept the implementation of the tool simple and relied primarily on local card walls allowing each team to design and adjust their own specific process.&lt;br /&gt;&lt;br /&gt;The "process" you design must work for your team. Adopting another team's process is an acceptable starting point. Just be certain you adapt and improve as you learn best what works for your unique team in your unique environment. Most tools get in the way of this. All tools offer less flexibility than a blank wall, a roll of painter's tape, and a fist full of index cards.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-3403866245074406464?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/3403866245074406464/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/09/blank-wall-and-fist-full-of-index-cards.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/3403866245074406464'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/3403866245074406464'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/09/blank-wall-and-fist-full-of-index-cards.html' title='A blank wall and a fist full of index cards'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-1334626206698144725</id><published>2010-09-08T17:57:00.001-04:00</published><updated>2010-09-08T17:58:28.323-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Manager'/><category scheme='http://www.blogger.com/atom/ns#' term='Teams'/><category scheme='http://www.blogger.com/atom/ns#' term='How To'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Career'/><title type='text'>Motivating the Unmotivated</title><content type='html'>I read a post recently from &lt;a href="http://twitter.com/teknophyl"&gt;teknophyl&lt;/a&gt; entitled "&lt;a href="http://teknophyl.wordpress.com/2010/08/24/motivating-the-unmotivated/"&gt;Motivating the Unmotivated&lt;/a&gt;". He asked me to read it and give him some feedback. I started a reply in the comments and realized this one was going to take some time.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I encourage you to read his blog entry. I am willing to bet it will resonate with most of you, either as a participant in a similar series of events, or at least as a witness.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The blog entry ends with a question - "what do you do to motivate the person who is seemingly unwilling to be motivated?"&lt;/div&gt;&lt;h4&gt;People are complicated&lt;/h4&gt;&lt;div&gt;I haven't found anything that works every time. People are complex and difficult to understand. That includes you. And that includes me.&lt;br /&gt;&lt;br /&gt;I have a history of failed well intended attempts to motivate people toward goals. But I also have a history of successful attempts to facilitate people's forward progress toward goals.&lt;/div&gt;&lt;h4&gt;Dont' Motivate, Facilitate&lt;/h4&gt;&lt;div&gt;Motivational techniques employed in the typical worker/manager relationship are often nothing more than coercion hiding behind a more palatable name. The distinction between motivation and coercion is small, but significant. Motivation is providing someone with a compelling enough reason to take action. Coercion is compelling one to action through force, authority, or exploitation. In either case, we are attempting to incite someone to clear a hurdle in order to achieve a desired goal. When we facilitate, we remove the hurdle and clear the path to the goal.&lt;/div&gt;&lt;h5&gt;Seek first to understand&lt;/h5&gt;&lt;div&gt;What we perceive as lack of motivation is often fear or lack of confidence. A lack of confidence may be in themselves, leadership, or procedures.&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Find out what their perspective is. How do they see the situation? How do they see you? What do they fear? What are their concerns? What are their beliefs? Your goal here is not to help them see the flaws in their world view. Your goal here is to understand and accept that their perception, no matter how incongruent with your own, is their reality. It is their truth.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is not a comfortable task, but it is not all that difficult. You may need the help of a third party, especially if there is interpersonal tension. In order to truly express their concerns, thoughts, and fears, they need to know there are no repercussions for being honest and open. Allow them to express themselves without countering, defending, or attempting to persuade. Listen intently and with an open mind.&lt;/div&gt;&lt;h5&gt;Acknowledge their views&lt;/h5&gt;&lt;div&gt;Tell them what you heard without judgement or bias. Avoid rephrasing their concerns from your perspective. I've seen people do this exercise and then say things like, "So I heard you say that you don't care to be professional and you don't think you should have to adhere to dress code like the rest of us." when what the person said was, "I am more comfortable in tennis shoes and don't see how footwear matters in the bigger picture." You also need not articulate a punch list of their prior statements. The objective is not to "prove" you listen. The objective is to listen.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;Provide them the opportunity to clarify and elaborate. You want to understand their perspective. You want them to know you understand. Rather than tell them, "I understand", allow them to tell you, "Yes, you understand".&lt;/div&gt;&lt;h5&gt;Assure them of change&lt;/h5&gt;&lt;h6&gt;Interpersonal Issues&lt;/h6&gt;&lt;div&gt;If you wish to alter the behavior of another, start by altering your own behavior. Let's say that your fellow employee feels you are too critical of their work, they feel you see them as inferior as a result, and they resent that feeling. But you don't feel you are too critical. Rather than attempt to alter their perspective, assure them you will try to be less critical and then genuinely try to do so.&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;I'll give you a tip here - when making an effort to adjust your behavior, refrain from prefacing your new behavior with statements that point it out. For example, "I know you want me to try to be less critical, so ..."&amp;nbsp;Simply adopt the new behavior.&lt;/div&gt;&lt;/div&gt;&lt;h6&gt;Organizational Issues&lt;/h6&gt;&lt;div&gt;Perhaps they feel they are not empowered to do what is being asked of them. Process requirements or dependence on others outside of the department impede their ability to do their work effectively. Assure them you will work to change those things you feel you can. Statements like, "I'll get Anita to whip her crew into shape or she'll have to deal with my wrath." are obviously grandstanding and represent you as someone who coerces. This devalues the very process you've just gone through. Let them know, "I'll ask Anita if we can get our groups together to discuss each other's needs and come up with something that works for all of us."&lt;/div&gt;&lt;h5&gt;Don't make promises you can't keep&lt;/h5&gt;&lt;div&gt;Some of what people want cannot or should not be achieved. I do encourage you to question every policy that impedes a team's ability to work more effectively. But sometimes there are valid reasons, be they for safety or legal compliance. If the policy is not based on safety or legal compliance, it is quite likely a placebo for communication.&lt;br /&gt;&lt;br /&gt;If what the team or individual desires is not possible, be clear about it. Don't make empty promises. Be forthright and honest. &lt;/div&gt;&lt;h5&gt;Ask them to change&lt;/h5&gt;&lt;div&gt;Most of us are aware that relationships are multi-dimensional. Knowing we are heard, understood, and supported makes it much easier for us to consent to a little change ourselves. Asking quid pro quo is by no means out of the question. You've agreed to be less critical; ask them to honor core team hours.&lt;/div&gt;&lt;h5&gt;Keep it balanced&lt;/h5&gt;&lt;div&gt;Whatever they ask of you, you should expect of them. Whatever you ask of them, they should expect of you. Of course there are exceptions; roles, gender, responsibilities all come into play. Often, expectations are identical; honor core hours, don't be late to stand-up. Be cognizant of the amount of commitment each party is making and make a sincere effort to keep it in balance.&lt;/div&gt;&lt;h5&gt;Keep your promises&lt;/h5&gt;&lt;div&gt;This is critical.&lt;br /&gt;&lt;br /&gt;Follow through. Remove the hurdles.&lt;br /&gt;&lt;br /&gt;People are skeptical when told "things are going to change around here." Make sure change happens. And make sure it happens quickly. One small change can bring hope and inspiration.&lt;br /&gt;&lt;br /&gt;A lack of action breeds contempt and cynicism. Not only have we failed to make things better, but we've made them worse.&lt;br /&gt;&lt;br /&gt;Involve people in the removal of the hurdles. Empower people to clear their own blocks. Encourage them to set up the meetings and be there to support them.&lt;br /&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/8528631747209969303-1334626206698144725?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/1334626206698144725/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/09/motivating-unmotivated.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/1334626206698144725'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/1334626206698144725'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/09/motivating-unmotivated.html' title='Motivating the Unmotivated'/><author><name>LeanDog Doc</name><uri>http://www.blogger.com/profile/14839073640331050321</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>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-7048333361769940227</id><published>2010-08-14T16:34:00.000-04:00</published><updated>2010-08-14T16:34:07.393-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Teams'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Career'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><category scheme='http://www.blogger.com/atom/ns#' term='User Groups'/><title type='text'>Excellent Developers Are the Best Hires</title><content type='html'>I recently read a &lt;a href="http://www.codeanthem.com/blog/2010/08/the-proof-is-in-the-code-that-is-all/" target="_blank"&gt;post&lt;/a&gt; wherein the author was condoning the hire of excellent programmers with abrasive personalities over bad programmers with cordial personalities. Superficially, I agree with this advice as it is ultimately better to have an individual who does their job well and delivers over an individual who you get along with very well, but who cannot produce.&lt;br /&gt;&lt;h4&gt;A false dichotomy&lt;/h4&gt;The notion that you must choose between great developers with bad personalities or bad developers with great personalities is just plain false. The dynamics involved are far more complex than that, but let's assume for a brief moment, that there are only two criteria any company hires on; raw skill and congeniality.&lt;br /&gt;&lt;br /&gt;The author posits that&amp;nbsp;&lt;em&gt;most&lt;/em&gt; companies do not have the luxury of hiring based on both skill and personality. He suggests Google has this luxury and yet they are always looking for good developers. His conclusion is that there are too few developers who are both excellent at the craft and reasonably compatible with the rest of the human race. I submit that perhaps &lt;a href="http://investor.google.com/financial/tables.html" target="_blank"&gt;Google's growth rate&lt;/a&gt; has contributed to their continual search for developers. I haven't any idea what their turnover rate is, but I do expect it also contributes to the demand.&lt;br /&gt;&lt;br /&gt;Let's not forget there are far more developers in the middle of this continuum than on either end-point. I would&amp;nbsp;surmise&amp;nbsp;the majority of developers fall somewhere comfortably in the middle; decent developers with decent personalities. Neither excellent nor awful. Neither completely congenial nor damagingly dissonant. The choice between only the two extremes is invalid.&lt;br /&gt;&lt;h4&gt;What makes for an excellent developer?&lt;/h4&gt;What are the criteria for excellence when it comes to developers? If we agree that a developer's role is ultimately the consistent delivery of software, then what atributes do we expect an excellent developer to have?&lt;br /&gt;&lt;br /&gt;I think there are many facets to what a developer does, but I think we can all agree on three things an excellent developer must be; Knowledgable, Skilled, and Efficient.&lt;br /&gt;&lt;h5&gt;Knowledgable&lt;/h5&gt;An excellent developer is certainly knowledgable.&lt;br /&gt;&lt;br /&gt;Knowing not only a particular language, but multiple languages. An excellent developer knows that the idioms, extractions, and constructs of one language enrich their ability to write code in all languages.&lt;br /&gt;&lt;br /&gt;An excellent developer knows that they are not an expert in all languages they use; perhaps (and most likely) in none. An excellent developer knows there is always more to learn. An excellent developer knows lessons can come from anywhere, not only from those they hold in high regard.&lt;br /&gt;&lt;br /&gt;An excellent developer is knowledgable in the business domain. An excellent developer can speak with others about the problem at hand in terms everyone is familiar with. An excellent developer knows they should not make unilateral decisions, should not accept decisions from others made in isolation, and should not expect all decisions to be made by committee.&lt;br /&gt;&lt;h5&gt;Skilled&lt;/h5&gt;Equipped with the knowledge there is always more to learn and always room for improvement, an excellent developer hones their skills. An excellent developer practices their craft. Not just working the same problem with the same tools day in and day out, but working different problems with different tools simply for the pleasure of learning.&lt;br /&gt;&lt;br /&gt;An excellent developer does not wait for their employer to approve the budget and time off. An excellent developer takes the initiative and attends conferences, user groups, and weekend gatherings where other practitioners talk, share, and practice.&lt;br /&gt;&lt;br /&gt;An excellent developer practices because they want to. An excellent developer improves themselves a little bit every day.&lt;br /&gt;&lt;h5&gt;Efficient&lt;/h5&gt;For an excellent developer, efficiency is more than writing code quickly. Efficiency is writing code that is easy to maintain in the future. For an excellent developer, efficiency is writing only the code you need today without sacrificing the ability to make alterations tomorrow.&lt;br /&gt;&lt;br /&gt;Efficiency is working in a manner that allows any developer on the team to pick up precisely where you left off and see the work to completion.&lt;br /&gt;&lt;h4&gt;Excellence Precludes Unsociability&lt;/h4&gt;Excellence requires knowledge, skill, and efficiency.&lt;br /&gt;&lt;br /&gt;Knowledge requires open mindedness in that one considers what multiple languages have to offer and recognizes that lessons can come from anywhere.&lt;br /&gt;&lt;br /&gt;Knowledge requires humility in that one knows they are not expert in all tools they use and that lessons can come from anyone, regardless of status.&lt;br /&gt;&lt;br /&gt;Skill requires discipline and commitment in that one must apply themselves not only at work, but outside of work as well; in divergent skills and tools.&lt;br /&gt;&lt;br /&gt;Skill requires initiative. An excellent developer does not wait for training to be scheduled and budgets to be approved.&lt;br /&gt;&lt;br /&gt;Skill requires social interaction for the best lessons come from the social interaction we have with other developers at conferences, user groups, and weekend events.&lt;br /&gt;&lt;br /&gt;Efficiency requires wisdom. The wisdom to know what to build and what not to build. The wisdom to know when the extra effort today is worth the payout of tomorrow and when "good enough" really is.&lt;br /&gt;&lt;br /&gt;Efficiency requires teamwork. Developers working in groups, covering each other's back, and sharing ideas as the solutions unfold before them.&lt;br /&gt;&lt;br /&gt;If an excellent developer is knowledgable, skilled, and efficient, then an excellent developer is open-minded, humble, disciplined, committed, initiative taking, socially engaged, wise, and team-oriented.&lt;br /&gt;&lt;br /&gt;It is, therefor, impossible to hire an excellent developer who has a bad personality.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-7048333361769940227?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/7048333361769940227/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/08/excellent-developers-are-best-hires.html#comment-form' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7048333361769940227'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7048333361769940227'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/08/excellent-developers-are-best-hires.html' title='Excellent Developers Are the Best Hires'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-340233999427083701</id><published>2010-08-10T17:38:00.000-04:00</published><updated>2010-08-10T17:38:28.559-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Manager'/><category scheme='http://www.blogger.com/atom/ns#' term='Teams'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><category scheme='http://www.blogger.com/atom/ns#' term='How To'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><title type='text'>Roshambo Estimating</title><content type='html'>This is a quick post. I just want to share a technique we've been using for initial story estimating. I first used this technique at ThoughtWorks when we were working on a project that required a lot of estimating. I think it came about because 1) we did not have any estimating cards immediately available and 2) that is the kind of place ThoughtWorks is. I later came to discover that the technique is not only fun, but it actually has a few additional benefits.&lt;br /&gt;&lt;br /&gt;My recall is fuzzy, but I believe it was Greg "Hippie" Warren who first suggested it. As many of you know, Robshambo has a bit of a tradition at ThoughtWorks (not normally associated with estimating), so it just seemed natural.&lt;br /&gt;&lt;h4&gt;How it works&lt;/h4&gt;&lt;h5&gt;Set-Up&lt;/h5&gt;Roshambo Estimating requires no special equipment, only your hands and some partners.&lt;br /&gt;&lt;br /&gt;When estimating a story, get a brief overview of the story and acceptance criteria. Ask whatever high-level questions come to mind in order to get a good general sense of the effort required. Do not try to nail down every last detail. It is perfectly acceptable to make some assumptions or leave some unknowns.&lt;br /&gt;&lt;br /&gt;Any team member may ask for an estimate at any time. When the team is comfortable giving a rough estimate, throwing may commence.&lt;br /&gt;&lt;h5&gt;Throwing&lt;/h5&gt;Each team member begins with one hand balled into a fist and resting on the open palm of their other hand. One team member counts to three. At the counts of one and two, team members bang their balled fists into the palm of the open hand. On the three count, all team members "throw" their estimates. Estimates are represented by the number of fingers showing on your hand.&lt;br /&gt;&lt;br /&gt;I prefer a&amp;nbsp;Fibonacci&amp;nbsp;sequence as it appropriately represents the proportionality between estimate size and accuracy. So, for the teams I work with, we usually throw a 1, 2, 3, 5 or a thumb.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/_9BSWFzzwekI/TGG8JPzNKII/AAAAAAAAADI/X8gywlfJor8/s1600/one.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_9BSWFzzwekI/TGG8JPzNKII/AAAAAAAAADI/X8gywlfJor8/s320/one.JPG" /&gt;&lt;/a&gt;&lt;a href="http://1.bp.blogspot.com/_9BSWFzzwekI/TGG8KxDeP1I/AAAAAAAAADQ/V3tkuX-PLqA/s1600/two.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_9BSWFzzwekI/TGG8KxDeP1I/AAAAAAAAADQ/V3tkuX-PLqA/s320/two.JPG" /&gt;&lt;/a&gt;&lt;a href="http://1.bp.blogspot.com/_9BSWFzzwekI/TGG8MXQc8fI/AAAAAAAAADY/vyLW-zTGHfY/s1600/three.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_9BSWFzzwekI/TGG8MXQc8fI/AAAAAAAAADY/vyLW-zTGHfY/s320/three.JPG" /&gt;&lt;/a&gt;&lt;a href="http://4.bp.blogspot.com/_9BSWFzzwekI/TGG8OaQfz_I/AAAAAAAAADg/x9asuhNlbV0/s1600/five.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_9BSWFzzwekI/TGG8OaQfz_I/AAAAAAAAADg/x9asuhNlbV0/s320/five.JPG" /&gt;&lt;/a&gt;&lt;a href="http://1.bp.blogspot.com/_9BSWFzzwekI/TGG8P746bNI/AAAAAAAAADo/yLVM8H4nhgU/s1600/more.JPG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/_9BSWFzzwekI/TGG8P746bNI/AAAAAAAAADo/yLVM8H4nhgU/s320/more.JPG" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;A throw of 1, 2, 3, or 5 indicates the point estimate for the story. A throw of thumb indicates the story is too large to estimate on one hand.&lt;/div&gt;&lt;h5&gt;Evaluation&lt;/h5&gt;&lt;div&gt;If the throws are all the same, you have your estimate; move on to the next story.&lt;br /&gt;&lt;br /&gt;If there is a significant discrepancy, provide each of the outliers an opportunity to briefly explain their thinking. The team then decides to estimate again or continue discussion. If discussion continues, any team member may ask for an estimate at any time.&amp;nbsp;When the team is comfortable giving a new estimate, throwing may commence.&amp;nbsp;&lt;/div&gt;&lt;br /&gt;Typically, the discrepancy is small. Half the team throws a 2 and half the team throws a 3. A quick discussion should resolve this. Often the low estimates round up and the team moves on.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;So... what makes this better?&lt;/h4&gt;This is not significantly different than a number of other estimating techniques already floating around. So why adopt this one?&lt;br /&gt;&lt;br /&gt;In my experience, I've found this to be the fastest and most efficient way to do estimates without sacrificing the quality of the estimates. It can be done at any time, any place. No extra materials required. There is no shuffling of cards, no cheating, no anchoring.&lt;br /&gt;&lt;br /&gt;The idea is to get to an estimate quickly and to put primary focus on stories that have discrepancies, therefor requiring more discussion.&lt;br /&gt;&lt;br /&gt;It is fun and it looks silly.&lt;br /&gt;&lt;br /&gt;This technique implicitly mandates that no stories can be larger than a 5. I recognize every team has their own set of practices around story sizing, but it has been my experience that estimates larger than 5 are significantly less reliable. Effectively, there is&amp;nbsp;minuscule&amp;nbsp;discernible&amp;nbsp;difference between an 8 and a 13 in terms of actual effort required to complete. If I had my way, no stories could be larger than a 3; at which point, we don't need to estimate and can just count cards. - but that is another post for another day.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-340233999427083701?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/340233999427083701/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/08/roshambo-estimating.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/340233999427083701'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/340233999427083701'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/08/roshambo-estimating.html' title='Roshambo Estimating'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_9BSWFzzwekI/TGG8JPzNKII/AAAAAAAAADI/X8gywlfJor8/s72-c/one.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-6684899883001261943</id><published>2010-06-26T11:44:00.010-04:00</published><updated>2010-06-26T19:06:03.522-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Career'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>It's our own damn fault</title><content type='html'>&lt;h4&gt;It ain't easy slinging code&lt;/h4&gt;&lt;div&gt;Over the course of my more than twenty years in the software development industry, I've worked with hundreds if not thousands of developers. Many of the projects I've been involved with have suffered from the same malady; a disconnect between expectations and realistic possibility.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://agilemanifesto.org/"&gt;The Agile Manifesto&lt;/a&gt; attempts to address many of the root causes of this malady. It encourages individuals to interact, collaborate, communicate, and respond to change. These are not easy things to do. Nor do they necessarily ensure quality software.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://manifesto.softwarecraftsmanship.org/"&gt;The Manifesto for Software Craftsmanship&lt;/a&gt; gives a clear nod to the Agile Manifesto and then extends it by addressing the need for quality software. These are not easy things to do.&lt;/div&gt;&lt;h4&gt;The man is always keeping us down&lt;/h4&gt;&lt;div&gt;Many developers look to this inequity and the challenges and realize they are helpless against unrealistic demands. External forces are at play; leadership, management, or sales - no matter. They neither listen nor care. They want it done. They want it all done. And they want it yesterday.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So we cluster together. We lament. We gnash our teeth. We wring our hands. We commiserate. And then we perform our duties in compliance with the demands set upon us.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;It is not our fault. Try as we might, we get no respect. No recognition. No appreciation. If we don't crank fast and put in the long hours, they'll just find somebody who will.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;We have no choice.&lt;/div&gt;&lt;div&gt;We are victims.&lt;/div&gt;&lt;div&gt;And we need only for "them" to understand and allow us to do our jobs well.&lt;/div&gt;&lt;h4&gt;It's our own damn fault&lt;/h4&gt;&lt;div&gt;Where do we get off? Absolving ourselves of responsibility for the quality of our work by blaming others. We rationalize doing a lower quality job in the name of pressures, deadlines, and promises made by others. But it is we who deliver the software. It is we who ultimately make the decision to not test enough, not refactor, put in excessive hours, and not do a quality job.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;And every time we do this. Every single time we say it can't be done but then deliver a steaming pile that closely resembles that which we said couldn't be done; we reinforce the behaviors. Every time we put in excessive hours to be heroes, we set a precedent for the next time. Every time we compromise quality in order to meet unrealistic expectations, we devalue ourselves and the service we provide.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;We haven't the right to complain about the very behaviors we enable.&lt;/div&gt;&lt;h4&gt;Never ask permission...&lt;/h4&gt;&lt;div&gt;If we want to stop this pattern. If we want to improve the reputation of our profession. If we want "them" to understand, then we need to change our behavior. Take a stand. Do your job well regardless of the pressure. A doomed project is doomed whether we compromise on our values or not. The more of us who behave this way; the more of us who insist on quality from ourselves and our teammates, the more evident it will become that this is not only a better way, but the right way - perhaps the only way.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Do your job. The absolute best you can. Keep learning. Keep improving.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Never ask permission to do your job well.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-6684899883001261943?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/6684899883001261943/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/06/its-our-own-damn-fault.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/6684899883001261943'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/6684899883001261943'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/06/its-our-own-damn-fault.html' title='It&apos;s our own damn fault'/><author><name>LeanDog Doc</name><uri>http://www.blogger.com/profile/14839073640331050321</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-8528631747209969303.post-7337571025722490079</id><published>2010-06-08T22:32:00.004-04:00</published><updated>2010-06-08T22:40:47.575-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Teams'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Career'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Value is more than money</title><content type='html'>&lt;h4&gt;This got me thinking&lt;/h4&gt;Michael Nygard &lt;a href="http://twitter.com/mtnygard/status/11878397905"&gt;tweeted&lt;/a&gt; &lt;br /&gt;&lt;blockquote&gt;'The phrase "business value" seems to hide uncertainty behind vagueness. Can we just say "money" instead?'&lt;/blockquote&gt;&lt;b&gt;I disagree.&amp;nbsp;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;Or more accurately, I disagree with what I infer Michael means by this single tweet. I cannot say with any certainty what he meant, much less address the context of or inspiration behind his statement.&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;h4&gt;Greed and Gluttony&lt;/h4&gt;&lt;h5&gt;To say, "We are in business for profit.", is to say "We live to eat."&lt;/h5&gt;This is fundamentally backward. This is beyond misguided for such a perspective is ultimately fatal to any company or person who lives by these respective statements. Undoubtedly, the actions necessary to support the belief will result in a tragic demise, whereby the very thing you identify as your purpose will cause your termination.&lt;br /&gt;&lt;br /&gt;These amount to nothing more than rationalizations for greed and gluttony.&lt;br /&gt;&lt;h5&gt;Paved with Good Intentions&lt;/h5&gt;Of course, it is important that a company generate enough revenue to sustain operations. Without this, the company cannot endure and cannot serve its purpose to humanity, in whatever form that might take. On behalf of every company, therefore, a group, committee, or department must exist whose purpose is oversight of the company's financial wellbeing.&lt;br /&gt;&lt;br /&gt;This group has an awesome responsibility. One I am certain they do not take lightly. One I understand they consider paramount. Should they fail, the company will certainly fail. To best ensure success, they might conclude that their responsibility should be shared among all members of the organization.&lt;br /&gt;&lt;br /&gt;If a company benefits when only a small portion of its employees commit themselves to a focus on profit, &amp;nbsp;surely increasing this focus will increase the resultant benefit.&lt;br /&gt;&lt;h5&gt;Tunnel Vision&lt;/h5&gt;Tunnel Vision impedes an organism's ability to see beyond a restricted range due to flaws in the field of vision. This is, clearly, a dangerous affliction. Those who suffer from tunnel vision have diminished peripheral capabilities making them more prone to accidents and providing them less time to react to threats approaching from outside their line of vision. Metaphorically, a company that focuses a preponderance of staff on the "bottom-line" inadvertently (or perhaps intentionally) creates tunnel vision.&lt;br /&gt;&lt;br /&gt;Staff learns to weigh all decisions based on short-term ROI. As a result, they seek lower cost (and typically lower quality) support services, try to get by on smaller staff without properly streamlining processes, second guess sales and marketing initiatives, and defer investments in facilities and equipment.&lt;br /&gt;&lt;br /&gt;But these efforts result in lower quality products, lower employee satisfaction, and loss of market share. For most companies, these are counter to long-term success.&lt;br /&gt;&lt;h4&gt;Value&lt;/h4&gt;&lt;h5&gt;So if money's not the point, what is?&lt;/h5&gt;I can tell you that for LeanDog, the point is to make the world a better place through better software development.&lt;br /&gt;&lt;br /&gt;I don't know what the point is where you work. Maybe it is to provide people a more convenient solution to a common problem. Maybe it is to ease people's pain, angst, fear, or concerns. Maybe it is to make people feel better, healthier, happier. I don't know. But I am hopeful the point of your company is not to put money in the pockets of the shareholders.&lt;br /&gt;&lt;h5&gt;Story value is in how they serve the purpose&lt;/h5&gt;Don't measure the value of your stories in money. Measure the value of your stories in how well they serve the purpose of the organization. And if you can't see the connection between the stories and the purpose of the organization, I'd say that's a project smell. If we don't know how what we are doing furthers the company in the pursuit of its mission, why do it at all?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-7337571025722490079?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/7337571025722490079/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/06/value-is-more-than-money.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7337571025722490079'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7337571025722490079'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/06/value-is-more-than-money.html' title='Value is more than money'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-7527710383561083256</id><published>2010-05-19T21:19:00.000-04:00</published><updated>2010-05-19T21:19:24.078-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Presentations'/><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='How To'/><category scheme='http://www.blogger.com/atom/ns#' term='Career'/><title type='text'>Take Control of your Development Career</title><content type='html'>I got the opportunity to do a little road-trip with my daughter this past weekend. I had an opportunity to speak at the Carolina Code Camp. They accepted all three of my submissions, so I figured I should make the trip. She spent a couple of semesters at High Point University in North Carolina and was looking forward to seeing some friends, so she offered to come along.&lt;br /&gt;&lt;br /&gt;The trip was great. We had a total of fourteen hours together in the car, which gave us plenty of time to catch up, talk philosophy, talk a little politics, and just hang out. If you think fourteen hours is a lot of time to fill talking, you haven't met my daughter or me. Separated, we are fairly loquacious, but together, we can get into a zone and move from subject to subject with nary a pause.&lt;br /&gt;&lt;br /&gt;The venue was excellent, the weather was beautiful, and the audience very receptive. I gave three presentations; "Introduction to Functional Programming with Scheme", "The Technical Debt Trap", and "Take Control of your Development Career". The last one is brand new. I've included a link to the slide deck.&lt;br /&gt;&lt;br /&gt;&lt;div id="__ss_4159684" style="width: 425px;"&gt;&lt;strong style="display: block; margin: 12px 0 4px;"&gt;&lt;a href="http://www.slideshare.net/DocOnDev/take-control-of-your-development-career" title="Take Control Of Your Development Career"&gt;Take Control Of Your Development Career&lt;/a&gt;&lt;/strong&gt;&lt;object height="355" id="__sse4159684" width="425"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=take-control-of-your-career-100519154628-phpapp02&amp;stripped_title=take-control-of-your-development-career" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed name="__sse4159684" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=take-control-of-your-career-100519154628-phpapp02&amp;stripped_title=take-control-of-your-development-career" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;div style="padding: 5px 0 12px;"&gt;View more &lt;a href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/DocOnDev"&gt;Michael Norton&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;I like this presentation. I absolutely loved it when Joe O'Brien gave a similar talk at Code Mash and I wanted to do something similar (but unique). Frankly, I think this one needs work. I got very positive feedback at the conference, but I feel like it doesn't deliver what I want it to. Look for changes to this talk in the future. And if you've thoughts on what you'd like to see, feel free to let me know. I think this has a lot of potential, I just don't feel I've nailed it yet.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-7527710383561083256?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/7527710383561083256/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/05/take-control-of-your-development-career.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7527710383561083256'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7527710383561083256'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/05/take-control-of-your-development-career.html' title='Take Control of your Development Career'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-1870166541797634246</id><published>2010-05-19T13:32:00.000-04:00</published><updated>2010-05-19T13:32:32.835-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby on Rails'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='User Groups'/><title type='text'>Cleveland Ruby Group</title><content type='html'>Just a quick note:&lt;br /&gt;&lt;br /&gt;I have officially accepted the coordinator position for the Cleveland/North East Ohio Ruby Users Group. Many thanks to Joe and Mike for their years of service. This is a good group of local Rubyists, interested in learning and furthering their craft.&lt;br /&gt;&lt;br /&gt;The leadership team is now Joe Fiorini, Matt Snyder, and me. We've made a couple of small adjustments to the site and Joe recently launched www.clerb.org. We are looking to the existing community to provide ideas and feedback in order to drive our direction and ensure the group meets the needs of its members.&lt;br /&gt;&lt;br /&gt;Visit the &lt;a href="http://www.meetup.com/ClevelandRuby/"&gt;Cleveland/North East Ohio Ruby Users Group&lt;/a&gt; on meetup and make sure you &lt;a href="http://www.clerb.org/"&gt;check out the CleRB.org site&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-1870166541797634246?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.meetup.com/ClevelandRuby/' title='Cleveland Ruby Group'/><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/1870166541797634246/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/05/cleveland-ruby-group.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/1870166541797634246'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/1870166541797634246'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/05/cleveland-ruby-group.html' title='Cleveland Ruby Group'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-804542739884565916</id><published>2010-05-02T10:37:00.102-04:00</published><updated>2010-05-19T21:22:44.751-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Presentations'/><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><category scheme='http://www.blogger.com/atom/ns#' term='Technical Debt'/><title type='text'>The Technical Debt Trap</title><content type='html'>I had the honor of presenting at Chicago Code Camp this week on the topic of technical debt. For those of you who know me, you know this is a topic I feel passionately about. More accurately, I am concerned about the misunderstandings surrounding technical debt and the frequent use of the term to placate any sense of responsibility over writing messy code in pursuit of a deadline.&lt;br /&gt;&lt;br /&gt;&lt;div id="__ss_3937725" style="width: 425px;"&gt;&lt;strong style="display: block; margin: 12px 0 4px;"&gt;&lt;a href="http://www.slideshare.net/DocOnDev/the-technical-debt-trap" title="The Technical Debt Trap"&gt;The Technical Debt Trap&lt;/a&gt;&lt;/strong&gt;&lt;object height="355" id="__sse3937725" width="425"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=the-technical-debt-trap-100502085552-phpapp02&amp;stripped_title=the-technical-debt-trap" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed name="__sse3937725" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=the-technical-debt-trap-100502085552-phpapp02&amp;stripped_title=the-technical-debt-trap" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;div style="padding: 5px 0 12px;"&gt;View more &lt;a href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/DocOnDev"&gt;Michael Norton&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;h5&gt;Ward Cunningham&lt;/h5&gt;I run the risk of looking like a Cunningham Fanboy with this presentation. I effectively stand in front of the audience and say, "Ward Cunningham says..." I don't know Ward personally, but I wouldn't mind meeting him some day. His insights on the development process and our responsibilities as developers are keen, his message is clear, and it is way easier to appeal to authority than to convince people to listen to me.&lt;br /&gt;&lt;br /&gt;&lt;h5&gt;References&lt;/h5&gt;There are a number of references in this slide deck. I've included all of the links along with a brief explanation of each.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://c2.com/doc/oopsla92.html" target="_blank"&gt;OOPSLA '92 Experience Report&lt;/a&gt;&lt;br /&gt;Ward Cunningham's brief on the WyCash Portfolio Management System wherein he likens shipping first time code to going into debt and warns of the potential pitfalls.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://jamesshore.com/Blog/CardMeeting/Voluntary-Technical-Debt.html" target="_blank"&gt;James Shore on Voluntary Technical Debt&lt;/a&gt;&lt;br /&gt;James talks about how a savvy team can use technical debt as a tool to accomplish more than they otherwise would.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://msdn.microsoft.com/en-us/magazine/ee819135.aspx" target="_blank"&gt;David Laribee on Paying Back Technical Debt&lt;/a&gt;&lt;br /&gt;David discusses the burden of Technical Debt on a project team and the use of agile practices to pay the debt down.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://blogs.construx.com/blogs/stevemcc/archive/2007/11/01/technical-debt-2.aspx" target="_blank"&gt;Steve McConnell on Technical Debt&lt;/a&gt;&lt;br /&gt;Steve focuses on an approach to technical debt from a business perspective, looking at decisions to incur debt, how to ensure it is the right kind of debt, and how to service the debt.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.martinfowler.com/bliki/TechnicalDebt.html" target="_blank"&gt;Martin Fowler expands the Metaphor&lt;/a&gt;&lt;br /&gt;Martin has several entries on Technical Debt. In this particular entry, Martin refers to Ward's definition of technical debt and provides a condensed definition that I believe could be the most often referred to definition.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.youtube.com/watch?v=pqeJFYwnkjE&amp;amp;feature=player_embedded" target="_blank"&gt;Ward's Video Statement&lt;/a&gt;&lt;br /&gt;Ward creates a video wherein he discusses the technical debt metaphor and explains his views on messy code as it applies to technical debt.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://twitter.com/WardCunningham/status/3742903303" target="_blank"&gt;Ward Tweets about Technical Debt&lt;/a&gt;&lt;br /&gt;Dirty code is to technical debt as the pawn broker is to financial debt. Don't think you are ever going to get your code back.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.redblack3.com/blog/?p=11" target="_blank"&gt;Continuous Refactoring and ROI&lt;/a&gt;&lt;br /&gt;The team over at Software Management Blog explain how to use continuous refactoring to keep your technical debt down and shows the flaw in scheduling refactoring into large concentrated efforts.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-804542739884565916?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/804542739884565916/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/05/technical-debt-trap.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/804542739884565916'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/804542739884565916'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/05/technical-debt-trap.html' title='The Technical Debt Trap'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-2181886892198446506</id><published>2010-04-20T20:42:00.001-04:00</published><updated>2010-04-20T20:43:32.907-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Teams'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><title type='text'>Optimal pairing</title><content type='html'>&lt;h4&gt;What was all that rambling about Harmonic Mean?&lt;/h4&gt;A while back, I posted a rambling entry about the impact of &lt;a href="http://docondev.blogspot.com/2010/03/harmonic-mean-is-bitch.html"&gt;Harmonic Mean&lt;/a&gt; on a team's performance. The post was actually about pairing. My intention was to put a solid mathematical, albeit only pseudo-scientific, explanation behind my paring recommendation, but I think I lost several people (including myself once or twice) in the math and all the fancy words.&lt;br /&gt;&lt;br /&gt;In short, whenever you pair two people of disparate skill sets, their contribution to production is more heavily influenced by the lesser skilled or experienced of the two. And the impact is significant. The greater the disparity in skill/experience, the more significant the impact.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Pair with people of similar skill and experience&lt;/h4&gt;Maximum performance per pair is achieved when the pairs have identical skills and experience. This is, of course, highly unlikely. It is, however, fairly easy to put together a team with similar skills and experience. This provides us an opportunity to mix pairs, keep things fresh, and disseminate knowledge and experience more rapidly through the team without concern over the impact of mis-matched pairs.&lt;br /&gt;&lt;br /&gt;When putting a team together, it is best to make sure the skill sets are within a few degrees of one another. When this is not possible, work to achieve a fairly even distribution of skill and experience. Avoid large gaps and do your best not to leave anyone isolated at the ends of the scale.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Exceptions to the "rule"?&lt;/h4&gt;The Software Craftsmanship movement encourages us to apprentice people new to software development. To bring them in, take them under our wing, and provide them the opportunity to learn through direct interaction with other developers in a structured and meaningful way.&lt;br /&gt;&lt;br /&gt;&lt;h5&gt;Surely, Doc, you are not suggesting that apprentices should teach one another.&lt;/h5&gt;&lt;br /&gt;Yes, I am.&lt;br /&gt;&lt;br /&gt;First of all, a good apprentice program does not immediately toss the new hire into a high-demand deliverable project. A good program provides the apprentice an environment where they can work on breakable toys designed to help learn fundamental concepts. Each step is a building block to the next, wherein fundamentals in both theory and practice are learned and built upon.&lt;br /&gt;&lt;br /&gt;Under these conditions, who better to pair with than another individual of similar skill and experience? You can discuss, debate, discover, and learn all under the watchful eye and guiding hand of a more experienced journeyman or craftsman. The master cannot and should not devote his entire time to the growth of the apprentice. It is optimal, even as someone brand new to the craft, to pair with another much like yourself.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-2181886892198446506?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/2181886892198446506/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/04/optimal-pairing.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/2181886892198446506'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/2181886892198446506'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/04/optimal-pairing.html' title='Optimal pairing'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-8106789557036550570</id><published>2010-04-19T16:26:00.001-04:00</published><updated>2010-04-19T16:27:05.868-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Event'/><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Clojure'/><title type='text'>Chicago Clojure Group</title><content type='html'>I am new to Clojure, but when I was asked to help with the Chicago Clojure Group, I was certainly willing to give a hand.&lt;br /&gt;&lt;br /&gt;It took me a while to get my act together and whether or not it is entirely together is yet to be seen, but I am happy to announce the re-launch of the Chicago Clojure Group.&lt;br /&gt;&lt;br /&gt;You can find out more about the group and our events on the official meetup site.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.meetup.com/Chicago-Clojure/"&gt;http://www.meetup.com/Chicago-Clojure/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Hope to see you there.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-8106789557036550570?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/8106789557036550570/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/04/chicago-clojure-group.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/8106789557036550570'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/8106789557036550570'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/04/chicago-clojure-group.html' title='Chicago Clojure Group'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-450885262605835891</id><published>2010-04-10T09:57:00.001-04:00</published><updated>2010-04-10T09:58:25.392-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Career'/><category scheme='http://www.blogger.com/atom/ns#' term='Craftsmanship'/><category scheme='http://www.blogger.com/atom/ns#' term='Book Review'/><title type='text'>Apprenticeship Patterns</title><content type='html'>Apprenticeship Patterns is a book of common sense advice derived from years of experience. While it reflects experiences, lessons learned, and patterns derived from the profession of software development, this is really a book about how to craft your own successful career, regardless of chosen vocation.&lt;br /&gt;&lt;br /&gt;Each chapter of the book introduces us to new, related patterns. Patterns progress as if in a timeline from those you will find most valuable starting out to those which foster continued growth and learning for a lifetime. The patterns themselves are atomic so while the progression in the book is logical, it is not necessary to read the book front to back. From the last pattern to the first, each is applicable whether you are just starting or are a seasoned veteran.&lt;br /&gt;&lt;br /&gt;I recommend Apprenticeship Patterns to everyone, not just friends in the computer industry.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-450885262605835891?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/450885262605835891/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/04/apprenticeship-patterns.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/450885262605835891'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/450885262605835891'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/04/apprenticeship-patterns.html' title='Apprenticeship Patterns'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-3135158181145984690</id><published>2010-04-07T15:32:00.001-04:00</published><updated>2011-01-03T09:12:57.953-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><category scheme='http://www.blogger.com/atom/ns#' term='How To'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><title type='text'>Stories are about why; not what or how</title><content type='html'>&lt;h5&gt;Story Fomats&lt;/h5&gt;I've been on numerous Agile projects with varying methods for capturing stories. Quite popular (and purportedly the ThoughtWorks standard) is the "&lt;i&gt;As a, I want, So that&lt;/i&gt;" story format.&lt;br /&gt;&lt;br /&gt;While I have seen teams do well with this format, I think it can be radically improved with a minor change. I prefer to see "&lt;i&gt;So that, as a, I want&lt;/i&gt;" story format.&lt;br /&gt;&lt;br /&gt;My reasoning is quite simple; the emphasis is incorrect in the common story format.&lt;br /&gt;&lt;h5&gt;Same words, different order&lt;/h5&gt;Compare these two statements:&lt;br /&gt;&lt;br /&gt;As A Bank Teller, I Want a name search field, So That I can quickly look up customers.&lt;br /&gt;So That I can quickly look up customers, As A Bank Teller, I Want a name search field.&lt;br /&gt;&lt;br /&gt;These are arguably the same story. The words are precisely the same; merely in a different order. Pick them apart, word by word, and we all agree these requirements are identical.&lt;br /&gt;&lt;h5&gt;Emphasis&lt;/h5&gt;But in planning meetings and even our regular work lives, we don't pick each statement apart word by word. Rather we take in the statement linearly, process it for meaning as we go, draw a conclusion of intent, and act.&lt;br /&gt;&lt;br /&gt;Let me make it visibly clear what is happening in our minds as we process the two statements:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: small;"&gt;As a,&lt;/span&gt;&lt;span style="font-size: x-large;"&gt; I want,&lt;/span&gt;&lt;span style="font-size: xx-small;"&gt; so that&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: x-large;"&gt;So that,&lt;/span&gt;&lt;span style="font-size: small;"&gt; as a,&lt;/span&gt;&lt;span style="font-size: xx-small;"&gt; I want&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;"As a" is always secondary in our mental process. This is, of course, a generalization. If I am an account manager, I am highly attuned to all "As an Account Manager" stories. But on the whole, for whom is a clarifier, not a primary consideration.&lt;br /&gt;&lt;br /&gt;With the common story format, our discussion is likely to be more around what the text field will look like, where it will be on the screen, and how it will function.&lt;br /&gt;&lt;br /&gt;With the common story format, I often see stories devolve to the abbreviated, "As a, I want" form. This is quite dangerous. We are now delivering functionality that serves no expressed purpose.&lt;br /&gt;&lt;h5&gt;Focus on Why (value)&lt;/h5&gt;By placing "So that" at the front of the statement, we've put an emphasis on why the story exists. If we can't say why we are implementing a feature, there is clearly no purpose for the feature. Even when we are certain that the purpose is obvious, it is best to include it. What is clear to the requestor may be opaque to the implementor.&lt;br /&gt;&lt;br /&gt;Our discussions are now focused on value. We may spend no less time discussing specifics of the implementation, but we are first assured we know why we are delivering the story. Our implementation is better guided by why. We are free to explore alternatives that better suite the purpose.&lt;br /&gt;&lt;h5&gt;Put purpose first; literally and figuratively&lt;/h5&gt;It helps to put the purpose of the story at the front of the story form. It places the proper emphasis on why and better frames our discussions. But if the purpose is inadequately stated, we are still likely to have the wrong discussions.&lt;br /&gt;&lt;br /&gt;Take the time to genuinely consider the why of each story. What is the value to the business? How will the customer be able to confidently select this story over another in planning sessions? Consider using&amp;nbsp;&lt;a href="http://agile.dzone.com/news/fixing-cause-effect-trap-user" target="_blank"&gt;Vincent Partington's technique for creating clear stories&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Our original story is better stated as follows:&lt;br /&gt;&lt;br /&gt;So That I can serve customers faster, As A Bank Teller, I Want an efficient way to look up customers.&lt;br /&gt;&lt;br /&gt;We now express the actual value to our client and we do not mandate implementation in the story summary.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-3135158181145984690?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/3135158181145984690/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/04/stories-are-about-why-not-what-or-how.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/3135158181145984690'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/3135158181145984690'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/04/stories-are-about-why-not-what-or-how.html' title='Stories are about why; not what or how'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-7748412778981440408</id><published>2010-03-24T22:04:00.000-04:00</published><updated>2010-03-24T22:04:03.585-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><title type='text'>Making Your Customers Pay for Your Shortcomings</title><content type='html'>This one is a straight-up rant. Because this announcement incenses me.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.macrumors.com/2010/03/24/atandt-set-to-roll-out-nationwide-3g-microcell-availability-beginning-next-month/"&gt;AT&amp;amp;T Set to Roll Out Nationwide 3G MicroCell Availability Beginning Next Month&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.boygeniusreport.com/2010/03/24/att-to-begin-nationwide-rollout-of-3g-microcell-in-mid-april/"&gt;AT&amp;amp;T to begin nationwide rollout of 3G MicroCell in mid-April&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Here is the letter that should accompany this announcement in next month's mailer to all AT&amp;amp;T customers:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: arial; font-size: small;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: 'trebuchet ms', sans-serif;"&gt;Dear consumer:&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: 'trebuchet ms', sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: 'trebuchet ms', sans-serif;"&gt;We know our coverage is severely lacking. We've put a great deal of money into running ads to spin the facts and make it look like we have coverage comparable to our competitors. But that isn't helping because, well, our crappy coverage is a fact, not an opinion.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: 'trebuchet ms', sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: 'trebuchet ms', sans-serif;"&gt;So now we have a new plan that we think you will really like. Rather than investing in our network to provide you the coverage you rightfully expect, we will instead take more of your money in exchange for which we will provide a device that allows you to use somebody else's network. We will, however, continue to charge you for these calls because you are using the micro device you purchased from us. Worry not, we've devised a month to month plan where you can pay us one flat monthly fee to use the device you purchased to make up for the crappy coverage we provided you in the first place.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: 'trebuchet ms', sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: 'trebuchet ms', sans-serif;"&gt;This is what we call a win-win situation. You pay us more money and we give you effectively nothing in exchange for it.&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: 'trebuchet ms', sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: 'trebuchet ms', sans-serif;"&gt;Thank you for your continued patronage and bags of money.&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: 'trebuchet ms', sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: 'trebuchet ms', sans-serif;"&gt;Sincerely,&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: 'trebuchet ms', sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: 'trebuchet ms', sans-serif;"&gt;AT&amp;amp;T&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: 'trebuchet ms', sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: #333333; font-family: 'trebuchet ms', sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-7748412778981440408?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/7748412778981440408/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/03/making-your-customers-pay-for-your.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7748412778981440408'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7748412778981440408'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/03/making-your-customers-pay-for-your.html' title='Making Your Customers Pay for Your Shortcomings'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-2014773094008394459</id><published>2010-03-16T10:27:00.149-04:00</published><updated>2010-03-17T00:30:10.470-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Manager'/><category scheme='http://www.blogger.com/atom/ns#' term='Teams'/><title type='text'>Harmonic Mean is a Bitch</title><content type='html'>&lt;h4&gt;The Theory of the Weakest Link&lt;/h4&gt;&lt;blockquote&gt;A chain is no stronger than its weakest link, and life is after all a chain. - William James&lt;/blockquote&gt;A chain is no stronger than its weakest link. Metaphorically, this applies to teams. But in actuality, this is simply not the case. Humans have not only tenacity, but the ability to countervail one another. This is a quality that inanimate objects simply do not possess. We can and will compensate for one another for the good of the team. Links in a chain are incapable of sharing their strength. No other link can compensate for the weakest.&lt;br /&gt;&lt;br /&gt;The key is knowing how to compensate.&lt;br /&gt;&lt;h4&gt;Applying Averages&lt;/h4&gt;&lt;h5&gt;Quantifying Ability&lt;/h5&gt;So perhaps the weakest link theory does not apply. But you can't argue with math, right? Quantify each team members ability, average them together, and you get the normalized ability of the team.&lt;br /&gt;&lt;br /&gt;On a scale of 1 to 10 in some arbitrary (but extremely meaningful and accurate) quantitive skill measurement:&lt;br /&gt;&lt;pre&gt;Name   Ability&lt;br /&gt;Alex       7&lt;br /&gt;Casey      3&lt;br /&gt;Chris     10&lt;br /&gt;Jessie     4&lt;br /&gt;Leslie     8&lt;br /&gt;Logan      2&lt;br /&gt;Pat        8&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The &lt;a href="http://en.wikipedia.org/wiki/Arithmetic_mean" target="_blank"&gt;Arithmetic Mean&lt;/a&gt; (Average) for the team is 6. Assume our scale is congruent with percentiles where 5 is average. We have a team that contains a clear prodigy and three above average individuals, yet the team's ability is barely above average.&lt;br /&gt;&lt;h5&gt;Quantifying Delivery&lt;/h5&gt;&lt;blockquote&gt;I don't have a lot of respect for talent. Talent is genetic. It's what you do with it that counts. - Martin Ritt&lt;/blockquote&gt;This scale means nothing to us. Average ability? How does that map to work completed? Making it happen is where it's at, baby.&lt;br /&gt;&lt;br /&gt;Let's assume for a second that our ability scale conveniently transfers to points per week completed.&lt;br /&gt;&lt;pre&gt;Name   Points/Week&lt;br /&gt;Alex       7&lt;br /&gt;Casey      3&lt;br /&gt;Chris     10&lt;br /&gt;Jessie     4&lt;br /&gt;Leslie     8&lt;br /&gt;Logan      2&lt;br /&gt;Pat        8&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Again, the Arithmetic Mean for the team is 6. Nothing changed. What's your point, Doc?&lt;br /&gt;&lt;br /&gt;Fair enough. There is no difference. But wait, there's more!&lt;br /&gt;&lt;h4&gt;Accounting for Counter-vailing&lt;/h4&gt;We discussed earlier in the theory of the weakest link that man is capable of compensating for one another, thereby raising the strength of the weakest point in the group. Something a chain can never do. And this is a beautiful characteristic. But is it enough? And how does it work?&lt;br /&gt;&lt;br /&gt;To be fair, we should assume that in covering for someone else, we diminish our own performance. If I assist you in completing a point, I sacrifice some of my own delivery rate. While I can certainly work a few extra hours to make it up, that pace is not sustainable.&lt;br /&gt;&lt;br /&gt;We adjust the points per week. Our top performer is now our team lead. The top performer contributes two points to the others and our other high performers provide one each. The new scale looks like this:&lt;br /&gt;&lt;pre&gt;Name   Points/Week&lt;br /&gt;Alex       6&lt;br /&gt;Casey      5&lt;br /&gt;Chris      8&lt;br /&gt;Jessie     5&lt;br /&gt;Leslie     7&lt;br /&gt;Logan      4&lt;br /&gt;Pat        7&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And our average for the team is still 6.&lt;br /&gt;&lt;br /&gt;This sure would be swell, Wally. But their just ain't no way. I think something is wrong with the Beaver....&lt;br /&gt;&lt;br /&gt;If we are pairing people up and one of the members has to effectively carry the other, there has to be some loss of velocity. If, however, we don't pair, we end up with a lot of re-work and lower performers stay lower performers for much longer. If you are in the camp who believes pairing is a bad practice, you will likely find significant ammunition in this article. I, however, do believe pairing is a fantastic practice. The dividends of pairing are significant and outside the scope of this article.&lt;br /&gt;&lt;h4&gt;Getting the math right&lt;/h4&gt;Each developer is capable of completing a single point in some period of time. We can extrapolate that to points per week. When two developers share the work, we average the rates together. But now we have an interesting twist. We are trying to determine how long it will take these two developers to complete a single point, assuming they evenly share the load of that point between the two of them. This average is not determined by Arithmetic Mean, but by &lt;a href="http://en.wikipedia.org/wiki/Harmonic_mean" target="_blank"&gt;Harmonic Mean&lt;/a&gt;.&lt;br /&gt;&lt;h5&gt;Digression into Harmonic Mean&lt;/h5&gt;Let me see if I can explain this.&lt;br /&gt;&lt;br /&gt;You drive from your home to the store, which is exactly one mile, in exactly 4 minutes.&lt;br /&gt;1 mile in 4 minutes is .25 miles per minute, which is 15 miles per hour.&lt;br /&gt;You drove to the store at 15 miles per hour.&lt;br /&gt;&lt;br /&gt;You return from the store along the exact same route, but this time it takes exactly 3 minutes.&lt;br /&gt;1 mile in 3 minutes is .333 miles per minute, which is 20 miles per hour.&lt;br /&gt;You drove back home at 20 miles per hour.&lt;br /&gt;&lt;br /&gt;For the complete round trip, you drove 2 miles in 7 minutes.&lt;br /&gt;2 miles in 7 minutes is .2857 miles per minute, which is 17.143 miles per hour.&lt;br /&gt;&lt;br /&gt;Your average speed is not 17.5 miles/hour, but 17.143 miles/hour.&lt;br /&gt;&lt;br /&gt;&lt;h5&gt;Back to our developers&lt;/h5&gt;This applies similarly to our developers.&lt;br /&gt;&lt;br /&gt;Chris delivers one point in .5 days, which is 10 points/week.&lt;br /&gt;Logan delivers one point in 2.5 days, which is 2 points/week.&lt;br /&gt;Together, they complete 2 points in 3 days, which is 3.33 points/week.&lt;br /&gt;&lt;br /&gt;As long as Chris and Logan are paired with Chris compensating for Logan as opposed to each of them augmenting the other, their average rate is 3.33 points/week. So we drop one of them from the Arithmetic Mean calculation.&lt;br /&gt;&lt;br /&gt;So what does this do?&lt;br /&gt;&lt;pre&gt;Name   Points/Week&lt;br /&gt;Alex       7&lt;br /&gt;Casey      4&lt;br /&gt;Chris   3.33&lt;br /&gt;Jessie     4&lt;br /&gt;Leslie     7&lt;br /&gt;&lt;br /&gt;Pat        7&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The average for the team is now 5.39&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Harmonic Mean is a Bitch&lt;/h4&gt;Harmonic mean lessens the impact of higher outliers, while emphasizing the impact of the lower numbers, especially as compared to Arithmetic Mean. So Harmonic mean favors the lower numbers. If this is true, doesn't it make more sense to have one of our slightly above average developers help train Logan instead?&lt;br /&gt;&lt;br /&gt;Let's ask Alex to do it.&lt;br /&gt;&lt;br /&gt;Alex can complete 1 point in 1.4 days.&lt;br /&gt;Logan can complete 1 point in 2.5 days.&lt;br /&gt;Together they complete 2 points in 3.9 days.&lt;br /&gt;&lt;br /&gt;They have an average of 2.56 points/week.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;Name   Points/Week&lt;br /&gt;Alex    2.56&lt;br /&gt;Casey      4&lt;br /&gt;Chris     10&lt;br /&gt;Jessie     4&lt;br /&gt;Leslie     7&lt;br /&gt;&lt;br /&gt;Pat        7&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The average for the team is now 5.76&lt;br /&gt;&lt;br /&gt;It does make more sense to have Alex pair with Logan. Theoretically, we could improve even more if we ask Casey or Jessie to pair with Logan. But now we are pairing all of our lesser performers together. Probably not a good idea.&lt;br /&gt;&lt;h4&gt;Work Together&lt;/h4&gt;While my explanation may be a bit complex, my point is simple. You get a better return when everyone on the team pitches in and helps out. And you get a better return if you focus on pulling up the bottom numbers without significantly dropping the top numbers.&lt;br /&gt;&lt;br /&gt;I am not advocating that you should only hire "top performers". If you do not grow your team from within, you fail to establish a sense of connection and purpose. And you set yourself up for huge salaries, huge egos, and ultimately high turn-over.&lt;br /&gt;&lt;br /&gt;I am not suggesting you should silo your top performers and do not allow anyone to "bother" them. Not only will you have ego issues, but you will have established a cast class for the developers that will be difficult to break out of.&lt;br /&gt;&lt;br /&gt;Most organizations take the top performers and put them in leadership roles where they are able to mentor and guide others. A single performer is expected to assist the entire team. Inevitably, those who require the most assistance, get it. We see an improvement as we pull the bottom up, but it is not nearly as significant an improvement as when each level pulls the one beneath it.&lt;br /&gt;&lt;br /&gt;Don't blindly put your top performer in charge of the team. Odds are, they will not enjoy the role and your return will be less than optimal. Have the team work together. Encourage pairs with low performance disparity. Make sure your best performers pair with the next level down and so on.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-2014773094008394459?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/2014773094008394459/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/03/harmonic-mean-is-bitch.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/2014773094008394459'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/2014773094008394459'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/03/harmonic-mean-is-bitch.html' title='Harmonic Mean is a Bitch'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-1154925410981581299</id><published>2010-03-10T00:37:00.003-05:00</published><updated>2010-03-11T20:21:23.632-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Teams'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Metrics'/><title type='text'>Caution: Metrics change behavior</title><content type='html'>&lt;h4&gt;Measuring and reporting are important&lt;/h4&gt;&lt;div class="left w50"&gt;I've often heard said, "That which you cannot measure, you cannot improve." And while I do believe this is a general truth, I think it fails to tell the entire story. It is not just about what we can measure, but what we actually do measure that is significant; "That which is reported, will improve."&lt;/div&gt;&lt;div class="right w50"&gt;&lt;br /&gt;&lt;blockquote&gt;What is not measurable, make measurable.&amp;nbsp;--&amp;nbsp;Galileo Galilei 1564-1642.&lt;/blockquote&gt;&lt;/div&gt;&lt;div style="clear:right; height:45px;"&gt;&lt;/div&gt;&lt;h4&gt;Measuring and reporting influence behavior&lt;/h4&gt;Metrics give us feedback. Metrics show a measure of progress toward our goals. Metrics remind us what is most important. Visible metrics, ala &lt;a href="http://www.agilealliance.org/show/733"&gt;Big Visible Charts&lt;/a&gt;, help to focus the team on what is most important.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;...if I have quick access to key metrics every day, my creativity stays within certain bounds – my ideas all center on how to achieve our goals.&amp;nbsp;--&amp;nbsp;&lt;a href="http://www.paulallen.net/2006/10/10/domino-rally-business-models/"&gt;Paul B. Allen&lt;/a&gt;&lt;/blockquote&gt;&lt;br /&gt;Access to key metrics provides an individual or a team a quick means of assessing progress and focusing their minds on what is most important. These can be excellent tools for influencing a team toward a desired goal or level of performance.&lt;br /&gt;&lt;br /&gt;But the outcome is not always what we intend.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;The Hawthorne Effect&lt;/h4&gt;There is a now famous study that was done in the early 1900s. Hawthorne Works commissioned a study of the effects of ambient lighting on worker productivity. The results of the test were perplexing. Essentially, worker throughput seemed to increase despite the level of light. High, low, medium; with each change, throughput increased. Once the study was concluded, levels quickly fell back to "normal".&lt;br /&gt;&lt;br /&gt;The are several criticisms of this particular study, but the phenomenon has been repeated under different circumstances since.&lt;br /&gt;&lt;br /&gt;The conclusion; that which was measured, improved. Effectively, because people were aware their throughput was being measured, it increased. In similar studies, people's throughput increased when they were knowingly observed but received no guidance or feedback. So they &lt;em&gt;assumed&lt;/em&gt; throughput was the objective.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Rock On! Where is my plotter?&lt;/h4&gt;So this is pretty awesome, huh? Just let people know you are watching them and their productivity will soar! Throw up a few charts and you've got yourself a high-functioning team.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;You wish&lt;/h4&gt;So here's the rub. An increase in throughput is not necessarily a good thing.&lt;br /&gt;&lt;br /&gt;&lt;h5&gt;Why Not?&lt;/h5&gt;Do you believe your employees are slackers?&lt;br /&gt;Do you think they lollygag about all morning, marking time until lunch and then perhaps featherbed it to 5pm before they skedaddle out the door?&lt;br /&gt;&lt;br /&gt;If you do, then you have a significant problem. A problem that a few charts and some good old fashioned micro-management probably won't solve. But, hey, it is worth a try....&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Our employees suck less than that&lt;/h4&gt;Good. So you have a reliable, forthright, responsible team of people. If this is the case, then you might do well to be a bit leery of easy increases in throughput. I'm not saying it is a bad thing, but that extra throughput had to originate somewhere. Perhaps it is less time spent in needless meetings. Perhaps it is better attention to priority items. If so...&lt;br /&gt;&lt;br /&gt;&lt;blockquote class="green"&gt;Huzzah for metrics!&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;BUT...&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;You've been warned&lt;/h4&gt;That which you measure and report will improve.&lt;br /&gt;&lt;br /&gt;If what you track and report is one-sided, your results will be one-sided.&lt;br /&gt;&lt;br /&gt;When you are on an agile team and all of your metrics are about velocity, you send a clear message to the team.&lt;br /&gt;&lt;br /&gt;&lt;blockquote class="red"&gt;Go Faster! &lt;span style="color: #999; font-size: x-small;"&gt;quality ain't all that important and value don't matter&lt;/span&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;h4&gt;Goodhart's Law&lt;/h4&gt;Goodhart's Law is a principle first defined in 1975 in a paper by Charles Goodhart, chief economic advisor to the Bank of England. Goodhart's basic premise is that economic indicators made into targets for the purpose of conducting economic policy, thereby lose their ability to serve in the desired capacity.&lt;br /&gt;&lt;br /&gt;More succinctly put - When a measure becomes a target, it ceases to be a good measure.&lt;br /&gt;&lt;br /&gt;Goodhart's law is applicable to both economics and sociology. It is a proven fact (law) that when you take an indicator such as velocity and you make it a target, you thereby eliminate it as a valid indicator.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Good Metrics&lt;/h4&gt;Measure value, not throughput. How many of the high-value stories were delivered, regardless of points.&lt;br /&gt;&lt;br /&gt;Focus on your customer's determination of value. How do your metrics tie directly to their single highest priority?&lt;br /&gt;&lt;br /&gt;Study trends, not moments in time.&lt;br /&gt;&lt;br /&gt;Use metrics as a diagnostic tool. When a problem is identified, devise one or two metrics that will help diagnose and monitor the health of the issue. When resolved, stop measuring.&lt;br /&gt;&lt;br /&gt;Do not record or report metrics for reporting sake.&lt;br /&gt;&lt;br /&gt;Do not set targets for your metrics.&lt;br /&gt;&lt;br /&gt;If you must report velocity, report only team velocity.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-1154925410981581299?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/1154925410981581299/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/03/caution-metrics-change-behavior.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/1154925410981581299'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/1154925410981581299'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/03/caution-metrics-change-behavior.html' title='Caution: Metrics change behavior'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-5150818970049710974</id><published>2010-02-26T19:03:00.005-05:00</published><updated>2010-03-08T23:21:22.132-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='How To'/><title type='text'>Contributing to a project you find on GitHub</title><content type='html'>For the purpose of this article, I assume you have &lt;a href="http://git-scm.com/"&gt;git&lt;/a&gt; installed, have a &lt;a href="https://github.com/"&gt;GitHub&lt;/a&gt; account, and are fundamentally familiar git.&lt;br /&gt;&lt;br /&gt;You've been &lt;a href="http://github.com/explore"&gt;exploring GitHub&lt;/a&gt; and have discovered a project you want to contribute to. Let's say it is&lt;a href="http://github.com/DocOnDev/functional-koans"&gt; my fork of the Functional Koans&lt;/a&gt;. You want to add some flair to the Python Koans in particular.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Fork the DocOnDev project&lt;/h4&gt;&lt;br /&gt;To create a fork, press the "fork" button on the project's page.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_9BSWFzzwekI/S4hjdTsYV3I/AAAAAAAAACM/ejnK8Kk2Zbs/s1600-h/GitHub-Fork.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_9BSWFzzwekI/S4hjdTsYV3I/AAAAAAAAACM/ejnK8Kk2Zbs/s320/GitHub-Fork.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;When the fork is complete, you will have a copy of the project in your repositories listing.&lt;br /&gt;&lt;div class="separator" style="text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/_9BSWFzzwekI/S4g62TlElSI/AAAAAAAAAB0/f51RnhnmSKA/s1600-h/GitHub-Fork-New-Repo.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/_9BSWFzzwekI/S4g62TlElSI/AAAAAAAAAB0/f51RnhnmSKA/s320/GitHub-Fork-New-Repo.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;h4&gt;Clone your project&lt;/h4&gt;Now you need to clone your fork. Make sure you use the “Your Clone URL” and not the “Public Clone URL”. You want to be able to push changes back to your own repository.&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;pre class="brush: bash"&gt;$ git clone git@github.com:[your-github-account]/functional-koans.git&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Once the clone is complete your repo will have a remote named “origin” that points to your fork on github. You will use "origin" for your own regular activities.&lt;br /&gt;&lt;h4&gt;Get the source&lt;/h4&gt;Let's make sure we have the python source.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: bash"&gt;$ cd functional-koans&lt;br /&gt;$ git checkout -b python&lt;br /&gt;$ git pull origin python&lt;br /&gt;From git@github.com:[your-github-account]/functional-koans&lt;br /&gt; * branch            python    -&amp;gt; FETCH_HEAD&lt;br /&gt;Auto-merging README.markdown&lt;br /&gt;CONFLICT (add/add): Merge conflict in README.markdown&lt;br /&gt;Automatic merge failed; fix conflicts and then commit the result.&lt;/pre&gt;&lt;br /&gt;Ugh. File conflict. No worries, open the file and edit it to look like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: text"&gt;# Functional Koans&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;### About the Koans&lt;br /&gt;&lt;br /&gt;There are several functional languages that have contributed their own&lt;br /&gt;versions of the koans.  Each language has it's own branch with&lt;br /&gt;detailed instructions on how to get started.&lt;br /&gt;&lt;br /&gt;### Getting Started&lt;br /&gt;&lt;br /&gt;To get the koans for a particular language, simply clone the repo and&lt;br /&gt;checkout the branch:&lt;br /&gt;&lt;br /&gt;'git clone git://github.com/relevance/functional-koans.git' &lt;br /&gt;'git checkout branch -b [branch_name]'&lt;br /&gt;'git pull origin [branch_name]'&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;where [branch_name] is the name of the branch (language) you want to&lt;br /&gt;work on.  To get a list of all branches run:&lt;br /&gt;&lt;br /&gt;'git branch -a'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now add the changed file to the python branch and check it in&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: bash"&gt;$ git add README.markdown&lt;br /&gt;$ git commit -m'Fixed README conflict'&lt;/pre&gt;&lt;h4&gt;Add a remote to the original project&lt;/h4&gt;First, switch back to the master branch locally.&lt;br /&gt;&lt;pre class="brush: bash"&gt;$ git checkout master&lt;/pre&gt;Then let's take a look at all of our branches.&lt;br /&gt;&lt;pre class="brush: bash"&gt;$ git branch -a&lt;br /&gt;* master&lt;br /&gt;  python&lt;br /&gt;  origin/FSharp&lt;br /&gt;  origin/HEAD&lt;br /&gt;  origin/clojure&lt;br /&gt;  origin/master&lt;br /&gt;  origin/scala&lt;/pre&gt;We see that the origin (your repository) has all of the branches, but our local repository only has master and python. The asterisk next to master indicates this is our active branch.&lt;br /&gt;&lt;br /&gt;Let's add another remote that points to the source you originally forked from. You can call this remote anything you want. I suggest you use something that makes sense to you. In GitHub's examples, they use the name "upstream", but that I find that to be too general. I tend to name this remote after the original account I forked from. So for the sake of this example, we will use my convention:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: bash"&gt;$ git remote add DocOnDev git://github.com/DocOnDev/functional-koans.git&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You may have noticed that we used the public clone URL for DocOnDev. Truth is, he probably won't give you access to push changes directly to his repository anyway. I heard he's a real jerk about that stuff. And if he had given you access to push directly to his repo, why did you create a fork...?&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Just to be sure...&lt;/h4&gt;Ok, so we just forked the code, but let's make sure we have the absolute latest version from DocOnDev before we start hacking away. We are going to fetch the latest from DocOnDev. Fetch grabs the latest source from all branches in DocOnDev's functional-koans repo and brings them down to us.&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: bash"&gt;$ git fetch DocOnDev&lt;br /&gt;From git://github.com/DocOnDev/functional-koans&lt;br /&gt; * [new branch]      FSharp     -&amp;gt; DocOnDev/FSharp&lt;br /&gt; * [new branch]      clojure    -&amp;gt; DocOnDev/clojure&lt;br /&gt; * [new branch]      master     -&amp;gt; DocOnDev/master&lt;br /&gt; * [new branch]      python     -&amp;gt; DocOnDev/python&lt;br /&gt; * [new branch]      scala      -&amp;gt; DocOnDev/scala&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now if we take another look at the branches...&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush: bash"&gt;$ git branch -a&lt;br /&gt;* master&lt;br /&gt;  python&lt;br /&gt;  origin/FSharp&lt;br /&gt;  origin/HEAD&lt;br /&gt;  origin/clojure&lt;br /&gt;  origin/master&lt;br /&gt;  origin/python&lt;br /&gt;  origin/scala&lt;br /&gt;  DocOnDev/FSharp&lt;br /&gt;  DocOnDev/clojure&lt;br /&gt;  DocOnDev/master&lt;br /&gt;  DocOnDev/python&lt;br /&gt;  DocOnDev/scala&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h4&gt;Make your changes&lt;/h4&gt;You are now free to make your changes and updates. You can add functionality, refactor, whatever it was that inspired you to contribute to this project in the first place.&lt;br /&gt;&lt;br /&gt;Make sure you are cognizant of the various branches. Don't make changes in python branch, switch to master branch, and commit unless you absolutely intend to add the file to the master branch. Check in early and often. And of course, write your tests first. ;)&lt;br /&gt;&lt;br /&gt;Check in every so often and fetch (or pull) any changes DocOnDev may have committed.&lt;br /&gt;&lt;pre class="brush: bash"&gt;$ git checkout python&lt;br /&gt;$ git fetch DocOnDev python&lt;br /&gt;From git://github.com/DocOnDev/functional-koans&lt;br /&gt; * branch            python     -&amp;gt; FETCH_HEAD&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h4&gt;Request a Pull&lt;/h4&gt;You've completed your changes and you'd like DocOnDev to take a look at them and consider them for addition to the project. Simply navigate to your fork and use the "Pull Request" button. You can explain your changes to DocOnDev as a part of the request.&lt;br /&gt;&lt;div class="separator" style="text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_9BSWFzzwekI/S4hgxKyUYWI/AAAAAAAAAB8/pkreZr2aWPk/s1600-h/GitHub-Pull-Request.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_9BSWFzzwekI/S4hgxKyUYWI/AAAAAAAAAB8/pkreZr2aWPk/s320/GitHub-Pull-Request.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;And that's the basics of it. It may take a while to get used to working on a project with multiple branches and multiple committers. I know I hozed my repo more than once before I got the hang of it.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;tweetmeme_url = 'http://docondev.blogspot.com/2010/02/contributing-to-project-you-find-on.html';&lt;/script&gt;&lt;br /&gt;&lt;script src="http://tweetmeme.com/i/scripts/button.js" type="text/javascript"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;digg_bgcolor = '#53abd5';digg_skin = 'compact';digg_window = 'new';digg_title = 'Contributing to a project you find on GitHub';digg_url = 'http://docondev.blogspot.com/2010/02/contributing-to-project-you-find-on.html';digg_topic = 'Programming';&lt;/script&gt;&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-5150818970049710974?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/5150818970049710974/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/02/contributing-to-project-you-find-on.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/5150818970049710974'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/5150818970049710974'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/02/contributing-to-project-you-find-on.html' title='Contributing to a project you find on GitHub'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_9BSWFzzwekI/S4hjdTsYV3I/AAAAAAAAACM/ejnK8Kk2Zbs/s72-c/GitHub-Fork.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-5860248958873767203</id><published>2010-02-09T19:37:00.003-05:00</published><updated>2010-02-09T22:31:26.495-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><category scheme='http://www.blogger.com/atom/ns#' term='How To'/><category scheme='http://www.blogger.com/atom/ns#' term='Kata'/><category scheme='http://www.blogger.com/atom/ns#' term='Python'/><title type='text'>Python String Calculator Kata - Step by Step</title><content type='html'>&lt;h4&gt;Background&lt;/h4&gt;For the past week, I have been working on the &lt;a href="http://osherove.com/tdd-kata-1/" target="_blank"&gt;String Calculator Kata&lt;/a&gt; in Python. I watched &lt;a href="http://vimeo.com/8569257" target="_blank"&gt;Gary Bernhardt's version&lt;/a&gt; of it and then set out to tackle it myself. Not surprisingly, &lt;a href="http://github.com/DocOnDev/python-StringCalculator" target="_blank"&gt;my solution&lt;/a&gt; was much like Gary's.&lt;br /&gt;&lt;br /&gt;Of course, watching a master was a bit of a cheat. I hadn't really figured it out. I just saw what he did and mimicked it. I certainly understood what he was doing and I understood the solution I subsequently developed, but I skipped a very important part of the process; the discovery and real learning.&lt;br /&gt;&lt;br /&gt;My wife has taken an interest in software development and is considering a possible career change. Along with reading books like "&lt;a href="http://www.amazon.com/Apprenticeship-Patterns-Guidance-Aspiring-Craftsman/dp/0596518382/" target="_blank"&gt;Apprenticeship Patterns&lt;/a&gt;", "&lt;a href="http://www.amazon.com/Inmates-Are-Running-Asylum-Products/dp/0672326140/" target="_blank"&gt;The Inmates are Running The Asylum&lt;/a&gt;", and "&lt;a href="http://www.amazon.com/Hackers-Painters-Big-Ideas-Computer/dp/0596006624/" target="_blank&amp;quot;"&gt;Hackers and Painters&lt;/a&gt;", she is learning Python.&lt;br /&gt;&lt;br /&gt;I decided that the String Calculator Kata would be a good exercise for us to pair on. I could show her some tricks and help her along. This would be a great learning exercise for the both of us.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Kata&lt;/h4&gt;&lt;h5&gt;Take One&lt;/h5&gt;Our first attempt was over the phone with a screen share. I did all the talking and typing while she watched, listened, and provided me with the&amp;nbsp;occasional, "uh-huh" to let me know she was still there. All in all, I'd say it was a fair experience at best. In my opinion, I had shown her quite a bit, but had actually taught her nothing. She wasn't going to benefit from doing a Kata by rote. She needed to understand how the moves came to be and why they were being done.&lt;br /&gt;&lt;br /&gt;This was going to take more time.&lt;br /&gt;&lt;h5&gt;Take Two&lt;/h5&gt;Our second attempt was in person, side by side, sharing a single computer. I still did most of the talking and all of the typing, but the dynamic was very different. Jennifer was able to ask questions, point at the screen, and interact unlike with the screen share. And I took a much more deliberate approach to the Kata. Making no assumptions about the language; acting as if I were learning it all for the first time as well.&lt;br /&gt;&lt;br /&gt;This was a good learning experience for both of us. I learned new things about Python and I felt connected to the developer I once was; the guy who would explore a language for the best way to do something; the guy who would spend hours on the same few lines of code in an effort to get them perfect. I've been doing Kata on and off for about a year with a recent deliberateness. But it wasn't until I used it to teach someone else that I achieved the next level of enlightenment.&lt;br /&gt;&lt;br /&gt;After some more thought, I decided to recount the entire experience on my blog. I've already discussed Kata in a couple of posts. The string calculator can be found in Scheme and Python on my &lt;a href="http://github.com/DocOnDev" target="_blank"&gt;github&lt;/a&gt;. But none of these capture my thought process. I am not saying my thought process is right. Hell, I have no idea. But I think sharing it and soliciting feedback can't hurt.&lt;br /&gt;&lt;h5&gt;The full experience&lt;/h5&gt;We start, of course, with a single test.&lt;br /&gt;&lt;h6&gt;calc_test.py&lt;/h6&gt;&lt;pre class="brush: python"&gt;import nose.tools&lt;br /&gt;from calc import add&lt;br /&gt;&lt;br /&gt;def test_empty_string_is_0():&lt;br /&gt;    assert 0 == add('')&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This fails as expected. And we write our add method.&lt;br /&gt;&lt;h6&gt;calc.py&lt;/h6&gt;&lt;pre class="brush: python"&gt;def add(input_string):&lt;br /&gt;    return 0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;We add the next test&lt;br /&gt;&lt;h6&gt;calc_test.py&lt;/h6&gt;&lt;pre class="brush: python"&gt;import nose.tools&lt;br /&gt;from calc import add&lt;br /&gt;&lt;br /&gt;def test_empty_string_is_0():&lt;br /&gt;    assert 0 == add('')&lt;br /&gt;&lt;br /&gt;def test_single_number_returns_value():&lt;br /&gt;    assert 1 == add('1')&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Which forces the change:&lt;br /&gt;&lt;h6&gt;calc.py&lt;/h6&gt;&lt;pre class="brush: python"&gt;def add(string):&lt;br /&gt;    if string:&lt;br /&gt;        return 1&lt;br /&gt;    else:&lt;br /&gt;        return 0&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;But this doesn't cover any single number, it covers a particular single number. So let's update the test.&lt;br /&gt;&lt;h6&gt;calc_test.py&lt;/h6&gt;&lt;pre class="brush: python"&gt;import nose.tools&lt;br /&gt;from calc import add&lt;br /&gt;&lt;br /&gt;def test_empty_string_is_0():&lt;br /&gt;    assert 0 == add('')&lt;br /&gt;&lt;br /&gt;def test_single_number_returns_value():&lt;br /&gt;    assert 1 == add('1')&lt;br /&gt;    assert 10 == add('10')&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;Our code fails again and we need to figure out a way to return the value of a string. Naturally, I asked &lt;a href="http://www.google.com/search?q=python+get+numeric+value+of+a+string" target="_blank"&gt;the googles&lt;/a&gt;. They don't know anything themselves, but they always know somebody who knows something.&lt;br /&gt;&lt;br /&gt;A tiny bit of poking around, and I found there is a string.&lt;b&gt;atoi&lt;/b&gt;(s[, base]) function, but it was deprecated in verison 2.0 in favor of the built-in &lt;i&gt;&lt;b&gt;int()&lt;/b&gt;&lt;/i&gt; function. This is what we are looking for:&lt;br /&gt;&lt;h6&gt;calc.py&lt;/h6&gt;&lt;pre class="brush: python"&gt;def add(string):&lt;br /&gt;    if string:&lt;br /&gt;        return int(string)&lt;br /&gt;    else:&lt;br /&gt;        return 0&lt;br /&gt;&lt;/pre&gt;Now the test passes, but I want to get cute. I want to eliminate the if/else. I happen to know Python has lambda capability. So I do some research and refactor to:&lt;br /&gt;&lt;h6&gt;calc.py&lt;/h6&gt;&lt;pre class="brush: python"&gt;def add(string):&lt;br /&gt;    return string and int(string) or 0&lt;br /&gt;&lt;/pre&gt;Cute. Yep.&lt;br /&gt;&lt;br /&gt;Back to business. We've covered the first couple of criteria, but we now need to handle more than one item. So we write the test (of course).&lt;br /&gt;&lt;h6&gt;calc_test.py&lt;/h6&gt;&lt;pre class="brush: python"&gt;import nose.tools&lt;br /&gt;from calc import add&lt;br /&gt;&lt;br /&gt;def test_empty_string_is_0():&lt;br /&gt;    assert 0 == add('')&lt;br /&gt;&lt;br /&gt;def test_single_number_returns_value():&lt;br /&gt;    assert 1 == add('1')&lt;br /&gt;    assert 10 == add('10')&lt;br /&gt;&lt;br /&gt;def test_multiple_numbers_returns_sum():&lt;br /&gt;    assert 3 == add('1,2')&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The familiar taste of failure leads us in search of an answer. How do we get the values out of a string? As it turns out, str is a &lt;a href="http://docs.python.org/library/stdtypes.html#sequence-types-str-unicode-list-tuple-buffer-xrange" target="_blank"&gt;sequence type&lt;/a&gt; in Python. So we can refer to its elements fairly easily.&lt;br /&gt;&lt;h6&gt;calc.py&lt;/h6&gt;&lt;pre class="brush: python"&gt;def add(string):&lt;br /&gt;    return string and _sum_string(string) or 0&lt;br /&gt;&lt;br /&gt;def _sum_string(string):&lt;br /&gt;    return int(string[0]) + int(string[2])&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;This gives a string index out of range error on our earlier passing tests. This won't do. We need to refer to the individual values only if there is a comma in the string. Looking back at our reference for sequence types, we find the &lt;b&gt;&lt;i&gt;in&lt;/i&gt;&lt;/b&gt; operator, which is perfect for this case.&lt;br /&gt;&lt;h6&gt;calc.py&lt;/h6&gt;&lt;pre class="brush: python"&gt;def add(string):&lt;br /&gt;    return string and _sum_string(string) or 0&lt;br /&gt;&lt;br /&gt;def _sum_string(string):&lt;br /&gt;    if ',' in string:&lt;br /&gt;        return int(string[0]) + int(string[2])&lt;br /&gt;    else:&lt;br /&gt;        return int(string)&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;This works. Let's see how far we can get using lambda expressions (for fun). Refactor to lambda:&lt;br /&gt;&lt;h6&gt;calc.py&lt;/h6&gt;&lt;pre class="brush: python"&gt;def add(string):&lt;br /&gt;    return string and _sum_string(string) or 0&lt;br /&gt;&lt;br /&gt;def _sum_string(string):&lt;br /&gt;    return ',' in string and int(string[0]) + int(string[2]) or int(string)&lt;br /&gt;&lt;/pre&gt;But what happens when the integers are more than a single digit? This calls for a new test.&lt;br /&gt;&lt;h6&gt;calc_test.py&lt;/h6&gt;&lt;pre class="brush: python"&gt;import nose.tools&lt;br /&gt;from calc import add&lt;br /&gt;&lt;br /&gt;def test_empty_string_is_0():&lt;br /&gt;    assert 0 == add('')&lt;br /&gt;&lt;br /&gt;def test_single_number_returns_value():&lt;br /&gt;    assert 1 == add('1')&lt;br /&gt;    assert 10 == add('10')&lt;br /&gt;&lt;br /&gt;def test_multiple_numbers_returns_sum():&lt;br /&gt;    assert 3 == add('1,2')&lt;br /&gt;    assert 15 == add('10,5')&lt;br /&gt;&lt;/pre&gt;This fails with a ValueError. It appears to be trying to get the int() value of a comma. So our hard-coded string offsets won't do. Then what else can we do here?&lt;br /&gt;&lt;br /&gt;Perusal of the standard string methods, leads us to the built-in &lt;b&gt;&lt;i&gt;partition&lt;/i&gt;&lt;/b&gt; method that was added in version 2.5. If it was recently added, it must be what we need....&lt;br /&gt;&lt;h6&gt;calc.py&lt;/h6&gt;&lt;pre class="brush: python"&gt;def add(string):&lt;br /&gt;    return string and _sum_string(string) or 0&lt;br /&gt;&lt;br /&gt;def _sum_string(string):&lt;br /&gt;    return ',' in string and _sum_delimited_string(string) or int(string)&lt;br /&gt;&lt;br /&gt;def _sum_delimited_string(string):&lt;br /&gt;    string_parts = string.partition(',')&lt;br /&gt;    return int(string_parts[0]) + int(string_parts[2])&lt;br /&gt;&lt;/pre&gt;And the tests pass. But my wife points out this won't work for strings with more than two digits.&lt;br /&gt;Hmmmm....&lt;br /&gt;Let's confirm the assumption.&lt;br /&gt;&lt;h6&gt;calc_test.py&lt;/h6&gt;&lt;pre class="brush: python"&gt;import nose.tools&lt;br /&gt;from calc import add&lt;br /&gt;&lt;br /&gt;def test_empty_string_is_0():&lt;br /&gt;    assert 0 == add('')&lt;br /&gt;&lt;br /&gt;def test_single_number_returns_value():&lt;br /&gt;    assert 1 == add('1')&lt;br /&gt;    assert 10 == add('10')&lt;br /&gt;&lt;br /&gt;def test_multiple_numbers_returns_sum():&lt;br /&gt;    assert 3 == add('1,2')&lt;br /&gt;    assert 15 == add('10,5')&lt;br /&gt;    assert 25 == add('10,3,12')&lt;br /&gt;&lt;/pre&gt;She was right. We get another ValueError. This time we are trying to get the int() of '3,12'. I see an immediate solution that should work. A little recursion and we are good to go.&lt;br /&gt;&lt;h6&gt;calc.py&lt;/h6&gt;&lt;pre class="brush: python"&gt;def add(string):&lt;br /&gt;    return string and _sum_string(string) or 0&lt;br /&gt;&lt;br /&gt;def _sum_string(string):&lt;br /&gt;    return ',' in string and _sum_delimited_string(string) or int(string)&lt;br /&gt;&lt;br /&gt;def _sum_delimited_string(string):&lt;br /&gt;    string_parts = string.partition(',')&lt;br /&gt;    return int(string_parts[0]) + _sum_string(string_parts[2])&lt;br /&gt;&lt;/pre&gt;And once again, our tests pass.&lt;br /&gt;&lt;br /&gt;At this point, I am actively holding myself back. I don't like this form of recursion. If I'm going to do it, I want it all contained in a single function. I really want to use split(), map(), and sum(), but I must remember that we've not discovered these yet. We are solving the problem with what we currently "know".&lt;br /&gt;&lt;br /&gt;Roy's first two requirements down, now we move on to custom delimiters; starting with a new-line as a delimiter.&lt;br /&gt;&lt;br /&gt;&lt;h6&gt;calc_test.py&lt;/h6&gt;&lt;pre class="brush: python"&gt;import nose.tools&lt;br /&gt;from calc import add&lt;br /&gt;&lt;br /&gt;def test_empty_string_is_0():&lt;br /&gt;    assert 0 == add('')&lt;br /&gt;&lt;br /&gt;def test_single_number_returns_value():&lt;br /&gt;    assert 1 == add('1')&lt;br /&gt;    assert 10 == add('10')&lt;br /&gt;&lt;br /&gt;def test_multiple_numbers_returns_sum():&lt;br /&gt;    assert 3 == add('1,2')&lt;br /&gt;    assert 15 == add('10,5')&lt;br /&gt;    assert 25 == add('10,3,12')&lt;br /&gt;&lt;br /&gt;def test_newline_is_a_delimiter():&lt;br /&gt;    assert 6 == add('1\n2,3')&lt;br /&gt;&lt;/pre&gt;Now we get a ValueError on an attempt to get int() for '1\n2'. Let's update the code to get this to pass.&lt;br /&gt;&lt;h6&gt;calc.py&lt;/h6&gt;&lt;pre class="brush: python"&gt;def add(string):&lt;br /&gt;    return string and _sum_string(string) or 0&lt;br /&gt;&lt;br /&gt;def _sum_string(string):&lt;br /&gt;    return ',' in string and _sum_delimited_string(string) or int(string)&lt;br /&gt;&lt;br /&gt;def _sum_delimited_string(string):&lt;br /&gt;    string = _normalize_delimiters(string)&lt;br /&gt;    string_parts = string.partition(',')&lt;br /&gt;    return int(string_parts[0]) + _sum_string(string_parts[2])&lt;br /&gt;&lt;br /&gt;def _normalize_delimiters(string):&lt;br /&gt;    return string.replace('\n', ',')&lt;br /&gt;&lt;/pre&gt;We are back to green. We are moving on to the fourth requirement; custom delimiters. This requirement reads as follows:&lt;br /&gt;&lt;ol start="4"&gt;&lt;li&gt;Allow the Add method to handle a different delimiter:&lt;/li&gt;&lt;ol&gt;&lt;li&gt;to change a delimiter, the beginning of the string will contain a separate line that looks like this:   “//[delimiter]\n[numbers…]” for example “//;\n1;2” should return three where the default delimiter is ‘;’ .&lt;/li&gt;&lt;li&gt;the first line is optional. all existing scenarios should still be supported&lt;/li&gt;&lt;/ol&gt;&lt;/ol&gt;First the test.&lt;br /&gt;&lt;h6&gt;calc_test.py&lt;/h6&gt;&lt;pre class="brush: python"&gt;import nose.tools&lt;br /&gt;from calc import add&lt;br /&gt;&lt;br /&gt;def test_empty_string_is_0():&lt;br /&gt;    assert 0 == add('')&lt;br /&gt;&lt;br /&gt;def test_single_number_returns_value():&lt;br /&gt;    assert 1 == add('1')&lt;br /&gt;    assert 10 == add('10')&lt;br /&gt;&lt;br /&gt;def test_multiple_numbers_returns_sum():&lt;br /&gt;    assert 3 == add('1,2')&lt;br /&gt;    assert 15 == add('10,5')&lt;br /&gt;    assert 25 == add('10,3,12')&lt;br /&gt;&lt;br /&gt;def test_newline_is_a_delimiter():&lt;br /&gt;    assert 6 == add('1\n2,3')&lt;br /&gt;&lt;br /&gt;def test_allow_custom_delimiter():&lt;br /&gt;    assert 3 == add('//;\n1;2')&lt;br /&gt;&lt;/pre&gt;And now the code.&lt;br /&gt;&lt;h6&gt;calc.py&lt;/h6&gt;&lt;pre class="brush: python"&gt;def add(string):&lt;br /&gt;    return string and _sum_string(string) or 0&lt;br /&gt;&lt;br /&gt;def _sum_string(string):&lt;br /&gt;    return ',' in string and _sum_delimited_string(string) or int(string)&lt;br /&gt;&lt;br /&gt;def _sum_delimited_string(string):&lt;br /&gt;    string = _normalize_delimiters(string)&lt;br /&gt;    string_parts = string.partition(',')&lt;br /&gt;    return int(string_parts[0]) + _sum_string(string_parts[2])&lt;br /&gt;&lt;br /&gt;def _normalize_delimiters(string):&lt;br /&gt;    if string.startswith('//'):&lt;br /&gt;        string_parts = string.partition('\n')&lt;br /&gt;        delimiter = string_parts[0]&lt;br /&gt;        delimiter = delimiter[2:]&lt;br /&gt;        string = string_parts[2].replace(delimiter, ',')&lt;br /&gt;    return string.replace('\n', ',')&lt;br /&gt;&lt;/pre&gt;This fails, a bit unexpectedly. What went wrong here? The custom delimiter is not being parsed.&lt;br /&gt;&lt;br /&gt;A little inspection and we realize that _sum_string() is to blame. Or more accurately, we see that we need to normalize the delimiters earlier in the process. So we move that call from _sum_delimited_string() into _sum_string(), which seems to make more sense anyway.&lt;br /&gt;&lt;h6&gt;calc.py&lt;/h6&gt;&lt;pre class="brush: python"&gt;def add(string):&lt;br /&gt;    return string and _sum_string(string) or 0&lt;br /&gt;&lt;br /&gt;def _sum_string(string):&lt;br /&gt;    string = _normalize_delimiters(string)&lt;br /&gt;    return ',' in string and _sum_delimited_string(string) or int(string)&lt;br /&gt;&lt;br /&gt;def _sum_delimited_string(string):&lt;br /&gt;    string_parts = string.partition(',')&lt;br /&gt;    return int(string_parts[0]) + _sum_string(string_parts[2])&lt;br /&gt;&lt;br /&gt;def _normalize_delimiters(string):&lt;br /&gt;    if string.startswith('//'):&lt;br /&gt;        string_parts = string.partition('\n')&lt;br /&gt;        delimiter = string_parts[0]&lt;br /&gt;        delimiter = delimiter[2:]&lt;br /&gt;        string = string_parts[2].replace(delimiter, ',')&lt;br /&gt;    return string.replace('\n', ',')&lt;br /&gt;&lt;/pre&gt;We are green again, but I don't think I can take it anymore. Look at all those [n] references in the code. And while I am not terribly concerned about it, the recursion could give us trouble on huge strings. There has to be a better way to do this.&lt;br /&gt;&lt;br /&gt;So let's go back to the documentation and see if there is anything else we can use to assist us along. One of our problems is the partition breaks the string into three chunks. Maybe something that gives us just the values and strips out the delimiter. Or maybe something that breaks it into multiple chunks.&lt;br /&gt;&lt;br /&gt;We discover &lt;i&gt;&lt;b&gt;&lt;a href="http://homepage.mac.com/s_lott/books/python/html/p02/p02c02_strings.html?highlight=str.split#str.split" target="_blank"&gt;split()&lt;/a&gt;&lt;/b&gt;&lt;/i&gt;. This appears to have some promise. It can chunk up the entire string into a list. That's nice. Maybe we can ditch the recursive call.&lt;br /&gt;&lt;br /&gt;First round, let's get rid of the &lt;i&gt;partition()&lt;/i&gt; call and replace it with &lt;i&gt;split()&lt;/i&gt;.&lt;br /&gt;&lt;h6&gt;calc.py&lt;/h6&gt;&lt;pre class="brush: python"&gt;def add(string):&lt;br /&gt;    return string and _sum_string(string) or 0&lt;br /&gt;&lt;br /&gt;def _sum_string(string):&lt;br /&gt;    string = _normalize_delimiters(string)&lt;br /&gt;    return ',' in string and _sum_delimited_string(string) or int(string)&lt;br /&gt;&lt;br /&gt;def _sum_delimited_string(string):&lt;br /&gt;    string_parts = string.split(',', 1)&lt;br /&gt;    return int(string_parts[0]) + _sum_string(string_parts[1])&lt;br /&gt;&lt;br /&gt;def _normalize_delimiters(string):&lt;br /&gt;    if string.startswith('//'):&lt;br /&gt;        delimiter, string = string.split('\n', 1)&lt;br /&gt;        delimiter = delimiter[2:]&lt;br /&gt;        string = string.replace(delimiter, ',')&lt;br /&gt;    return string.replace('\n', ',')&lt;br /&gt;&lt;/pre&gt;But this didn't seem to do anything for us. The code doesn't really look any better. And it still "feels" messy. We've two different functions that both claim to sum a string, but only one of them actually does. And these functions call one another. Let's push the responsibility back into a single function and see if we can clean this up.&lt;br /&gt;&lt;h6&gt;calc.py&lt;/h6&gt;&lt;pre class="brush: python"&gt;def add(string):&lt;br /&gt;    return string and _sum_string(string) or 0&lt;br /&gt;&lt;br /&gt;def _sum_string(string):&lt;br /&gt;    string = _normalize_delimiters(string)&lt;br /&gt;    if ',' in string:&lt;br /&gt;        string_parts = string.split(',', 1)&lt;br /&gt;        return int(string_parts[0]) + _sum_string(string_parts[1])&lt;br /&gt;    else:&lt;br /&gt;        return int(string)&lt;br /&gt;&lt;br /&gt;def _normalize_delimiters(string):&lt;br /&gt;    if string.startswith('//'):&lt;br /&gt;        delimiter, string = string.split('\n', 1)&lt;br /&gt;        delimiter = delimiter[2:]&lt;br /&gt;        string = string.replace(delimiter, ',')&lt;br /&gt;    return string.replace('\n', ',')&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;That is better. But isn't that recursive call really just iterating over the list and converting everything to an int() and then adding them up? Looks a bit like a Scheme function with string_parts[0] and string_parts[1] in place of car and cdr. I know this is crying out for a map, but how do I explain this to Jennifer? How do we naturally stumble upon the solution?&lt;br /&gt;&lt;br /&gt;So we focus in on the &lt;i&gt;split()&lt;/i&gt; function. &amp;nbsp;What does this do? It returns a list of the words in a string. So we dig into lists a bit to learn what they are all about. And we find there are a few functions that are very useful with lists: &lt;i&gt;&lt;a href="http://docs.python.org/library/functions.html#filter" target="_blank"&gt;filter()&lt;/a&gt;, &lt;a href="http://docs.python.org/library/functions.html#map" target="_blank"&gt;map()&lt;/a&gt;, and &lt;a href="http://docs.python.org/library/functions.html#reduce" target="_blank"&gt;reduce()&lt;/a&gt;&lt;/i&gt;. Of these, &lt;i&gt;map()&lt;/i&gt; and &lt;i&gt;reduce()&lt;/i&gt; look like they might do us some good.&lt;br /&gt;&lt;br /&gt;We can use &lt;i&gt;map()&lt;/i&gt; to convert our list of strings to a list of integers. Then, we can use &lt;i&gt;reduce()&lt;/i&gt;&amp;nbsp;to add them all up. Sound good? Yes. Yes it does. But when we check the syntax on &lt;i&gt;reduce()&lt;/i&gt;, we see a note that says to use the &lt;i&gt;&lt;a href="http://docs.python.org/library/functions.html#sum" target="_blank"&gt;sum()&lt;/a&gt;&lt;/i&gt; function for adding items in a list.&lt;br /&gt;&lt;br /&gt;And we've arrived at our intended destination.&lt;br /&gt;&lt;h6&gt;calc.py&lt;/h6&gt;&lt;pre class="brush: python"&gt;def add(string):&lt;br /&gt;    return string and _sum_string(string) or 0&lt;br /&gt;&lt;br /&gt;def _sum_string(string):&lt;br /&gt;    string = _normalize_delimiters(string)&lt;br /&gt;    if ',' in string:&lt;br /&gt;        return sum(map(int, string.split(',')))&lt;br /&gt;    else:&lt;br /&gt;        return int(string)&lt;br /&gt;&lt;br /&gt;def _normalize_delimiters(string):&lt;br /&gt;    if string.startswith('//'):&lt;br /&gt;        delimiter, string = string.split('\n', 1)&lt;br /&gt;        delimiter = delimiter[2:]&lt;br /&gt;        string = string.replace(delimiter, ',')&lt;br /&gt;    return string.replace('\n', ',')&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;That looks a little better. And all tests still pass. Now, let's refactor some more to make it a bit more terse.&lt;br /&gt;&lt;h6&gt;calc.py&lt;/h6&gt;&lt;pre class="brush: python"&gt;def add(string):&lt;br /&gt;    return string and _sum_string(string) or 0&lt;br /&gt;&lt;br /&gt;def _sum_string(string):&lt;br /&gt;    string = _normalize_delimiters(string)&lt;br /&gt;    return ',' in string and sum(map(int, string.split(','))) or int(string)&lt;br /&gt;&lt;br /&gt;def _normalize_delimiters(string):&lt;br /&gt;    if string.startswith('//'):&lt;br /&gt;        delimiter, string = string.split('\n', 1)&lt;br /&gt;        string = string.replace(delimiter[2:], ',')&lt;br /&gt;    return string.replace('\n', ',')&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;We decided this was a good breaking point for the session. We'd covered a lot of new material in a relatively short period of time.&lt;br /&gt;&lt;br /&gt;Tonight, we do it again, starting over from scratch. And I suspect we will skip some of the steps as we already know map() is our desired route.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;tweetmeme_url = 'http://docondev.blogspot.com/2010/02/python-string-calculator-kata-step-by.html';&lt;/script&gt;&lt;br /&gt;&lt;script src="http://tweetmeme.com/i/scripts/button.js" type="text/javascript"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;digg_bgcolor = '#558866';digg_skin = 'compact';digg_window = 'new';digg_title = 'Python String Calculator Kata';digg_url = 'http://docondev.blogspot.com/2010/02/python-string-calculator-kata-step-by.html';digg_topic = 'Programming';&lt;/script&gt;&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-5860248958873767203?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/5860248958873767203/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/02/python-string-calculator-kata-step-by.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/5860248958873767203'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/5860248958873767203'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/02/python-string-calculator-kata-step-by.html' title='Python String Calculator Kata - Step by Step'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-7156111166131911943</id><published>2010-01-17T17:50:00.005-05:00</published><updated>2010-05-19T21:23:02.888-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Presentations'/><category scheme='http://www.blogger.com/atom/ns#' term='Functional Programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Scheme'/><category scheme='http://www.blogger.com/atom/ns#' term='Kata'/><title type='text'>Introduction To Functional Programming with Scheme</title><content type='html'>I had the honor of presenting at CodeMash 2.0.1.0 this year on Functional Programming in Scheme. Given I picked up Scheme only a few months ago, I thought it best I do an introduction. Hopefully, I will have opportunity to do more presentations on Scheme, Lisp, and Clojure.&lt;br /&gt;&lt;br /&gt;As you can see by the slide deck, I have more than 60 slides to get through in no more than 60 minutes. The idea was a relatively fluid presentation where the slides continued to change as I spoke.&amp;nbsp;I had some technical difficulties, which I admittedly did not handle as well as I could have. The audience was patient with me and we were able to cover all of the material including some Q&amp;amp;A within the allotted one hour.&lt;br /&gt;&lt;br /&gt;I do hope the session was of value to those in attendance. I had to leave immediately after the presentation to make it to a ThoughtWorks event and I am not aware of a FeedBack mechanism for the speakers other than twitter activity.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;&lt;span style="font-family: 'trebuchet ms', sans-serif; font-size: large; font-weight: normal;"&gt;Slide Deck&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;div id="__ss_2936394" style="text-align: left; width: 425px;"&gt;&lt;a href="http://www.slideshare.net/DocOnDev/introduction-to-functional-programming-with-scheme" style="display: block; font: 14px Helvetica,Arial,Sans-serif; margin: 12px 0 3px 0; text-decoration: underline;" title="Introduction to Functional Programming with Scheme"&gt;Introduction to Functional Programming with Scheme&lt;/a&gt;&lt;object height="355" style="margin: 0px;" width="425"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=codemash-2-0-1-0-100117160418-phpapp01&amp;stripped_title=introduction-to-functional-programming-with-scheme" /&gt;&lt;param name="allowFullScreen" value="true"/&gt;&lt;param name="allowScriptAccess" value="always"/&gt;&lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=codemash-2-0-1-0-100117160418-phpapp01&amp;stripped_title=introduction-to-functional-programming-with-scheme" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;div style="font-family: tahoma,arial; font-size: 11px; height: 26px; padding-top: 2px;"&gt;View more &lt;a href="http://www.slideshare.net/" style="text-decoration: underline;"&gt;presentations&lt;/a&gt; from &lt;a href="http://www.slideshare.net/DocOnDev" style="text-decoration: underline;"&gt;Michael Norton&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;&lt;span style="font-family: 'Trebuchet MS', sans-serif;"&gt;&lt;span style="font-family: 'trebuchet ms', sans-serif; font-size: large;"&gt;Code Samples&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Thank you to everyone who gave me permission to use their code samples in my presentation.&lt;br /&gt;&lt;br /&gt;The Kata in the presentation is a variation on &lt;a href="http://osherove.com/tdd-kata-1/"&gt;Roy Osherove's String Calculator Kata&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;You can find the &lt;a href="http://github.com/DocOnDev/CodeMash-2010"&gt;Scheme Kata results&lt;/a&gt; presented in the slide deck on &lt;a href="http://github.com/DocOnDev"&gt;my github&lt;/a&gt;.&lt;br /&gt;&lt;b&gt;&lt;span style="font-weight: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: arial, sans-serif; font-size: 13px;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;div&gt;&lt;span style="font-family: 'trebuchet ms', sans-serif; font-size: medium;"&gt;Scheme Implementation Links&lt;/span&gt;&lt;br /&gt;&lt;div&gt;&lt;a href="http://www.gnu.org/software/mit-scheme/" rel="nofollow" style="color: #0000cc;"&gt;MIT Scheme Page (Download/Installation Instructions)&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.plt-scheme.org/" rel="nofollow" style="color: #0000cc;"&gt;Dr. Scheme&lt;/a&gt;&amp;nbsp;(aka PLT Scheme)&lt;br /&gt;&lt;a href="http://www-inst.eecs.berkeley.edu/~scheme/precompiled/OSX/" rel="nofollow" style="color: #0000cc;"&gt;UCB Scheme&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.gnu.org/software/guile/guile.html" rel="nofollow" style="color: #0000cc;"&gt;Guile&lt;/a&gt;&amp;nbsp;(GNU's Embeddable Scheme)&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-family: 'trebuchet ms', sans-serif;"&gt;&lt;span style="font-size: medium;"&gt;Development Environment Setup&lt;/span&gt;&lt;/div&gt;&lt;a href="http://xtalk.msk.su/~ott/en/writings/emacs-devenv/EmacsScheme.html" rel="nofollow" style="color: #0000cc;"&gt;Overview of various Emacs Scheme implementations&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: medium;"&gt;&lt;span style="font-family: 'trebuchet ms', sans-serif;"&gt;SICP Course Materials&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;a href="http://ocw.mit.edu/OcwWeb/Electrical-Engineering-and-Computer-Science/6-001Spring-2005/CourseHome/index.htm" rel="nofollow" style="color: #0000cc;"&gt;SICP Course Page&lt;/a&gt;&lt;br /&gt;&lt;a href="http://icampustutor.csail.mit.edu/6.001-public/" rel="nofollow" style="color: #0000cc;"&gt;MIT Tutor (for problem sets listed in MIT Opencourseware 6.001)&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://mitpress.mit.edu/sicp/" rel="nofollow" style="color: #0000cc;"&gt;SICP Book Info&lt;/a&gt;&lt;/div&gt;&lt;a href="http://www.youtube.com/watch?v=k6U-i4gXkLM" rel="nofollow" style="color: #0000cc;"&gt;First videos of the SICP replacement course at MIT&lt;/a&gt;&amp;nbsp;via @mfeathers&lt;br /&gt;&lt;div&gt;&lt;a href="http://mitpress.mit.edu/sicp/full-text/book/book.html" rel="nofollow" style="color: #0000cc;"&gt;SICP in HTML&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://web.mit.edu/alexmv/6.001/sicp.pdf" rel="nofollow" style="color: #0000cc;"&gt;SICP in PDF&lt;/a&gt;&amp;nbsp;(direct to pdf link)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href="http://benmabey.com/downloads/sicp.pdf" rel="nofollow" style="color: #0000cc;"&gt;Another version with different formatting&lt;/a&gt;&amp;nbsp;(direct PDF link)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;a href="http://www.sendspace.com/file/yy3xjc" rel="nofollow" style="color: #0000cc;"&gt;Yet another PDF version with much nicer typesetting&lt;/a&gt;&amp;nbsp;(not direct PDF link. courtesy Kevin Taylor)&lt;/div&gt;&lt;div&gt;&lt;a href="http://cloud.github.com/downloads/twcamper/sicp-kindle/sicp.mobi" rel="nofollow" style="color: #0000cc;"&gt;SICP in MOBI&lt;/a&gt;&amp;nbsp;(Reflowable / resizable for the little Kindle)&lt;/div&gt;&lt;div&gt;&lt;a href="http://groups.csail.mit.edu/mac/classes/6.001/abelson-sussman-lectures/" rel="nofollow" style="color: #0000cc;"&gt;SICP Lectures&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.archive.org/details/mit_ocw_sicp" rel="nofollow" style="color: #0000cc;"&gt;SICP Lecture Videos&lt;/a&gt;&amp;nbsp;(alternate source)&lt;br /&gt;&lt;a href="http://www.codepoetics.com/wiki/index.php?title=Topics:SICP_in_other_languages" rel="nofollow" style="color: #0000cc;"&gt;SICP In Other Languages&lt;/a&gt;&lt;span style="font-family: 'trebuchet ms', sans-serif; font-size: medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://deimos3.apple.com/WebObjects/Core.woa/Browse/berkeley.edu.1621506930.02398579566" rel="nofollow" style="color: #0000cc;"&gt;UC Berkeley's Lecture Series on SICP on ITunesU&lt;/a&gt;&amp;nbsp;(requires ITunes on Windows or Mac)&lt;/div&gt;&lt;h2 style="font-family: arial, sans-serif; font-weight: normal;"&gt;&lt;span style="font-size: x-small;"&gt;&lt;span style="font-size: medium;"&gt;&lt;span style="font-family: 'trebuchet ms', sans-serif;"&gt;SICP Solutions&lt;/span&gt;&lt;/span&gt;&lt;i&gt;Here are some links to some (incomplete) SICP solutions.&lt;/i&gt;&lt;br /&gt;&lt;/span&gt;&lt;/h2&gt;&lt;a href="http://wiki.drewhess.com/wiki/Category:SICP_solutions" rel="nofollow" style="color: #0000cc;"&gt;http://wiki.drewhess.com/wiki/Category:SICP_solutions&lt;/a&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;a href="http://www.kendyck.com/solutions-to-sicp/" rel="nofollow" style="color: #0000cc;"&gt;http://www.kendyck.com/solutions-to-sicp/&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;a href="http://community.schemewiki.org/?SICP-Solutions" rel="nofollow" style="color: #0000cc;"&gt;http://community.schemewiki.org/?SICP-Solutions&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;a href="http://sicp.org.ua/sicp" rel="nofollow" style="color: #0000cc;"&gt;http://sicp.org.ua/sicp&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;a href="http://eli.thegreenplace.net/category/programming/lisp/sicp/" rel="nofollow" style="color: #0000cc;"&gt;One persons detailed journey through SICP&lt;/a&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;h2 style="font-family: arial, sans-serif; font-weight: normal;"&gt;&lt;span style="font-size: x-small;"&gt;&lt;span style="font-size: medium;"&gt;&lt;span style="font-family: 'trebuchet ms', sans-serif;"&gt;Additional Scheme Resources&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;&lt;/div&gt;&lt;a add_date="1263234029338000" href="http://www.cs.berkeley.edu/~bh/ss-toc2.html"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;span style="font-size: small;"&gt;Simply Scheme: Introducing Computer Science&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a add_date="1263233887253000" href="http://www.gigamonkeys.com/book/"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;span style="font-size: small;"&gt;Practical Common Lisp&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a add_date="1262185052571000" href="http://www.htdp.org/2003-09-26/"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;span style="font-size: small;"&gt;How to Design Programs&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a add_date="1263233987723000" href="http://docs.plt-scheme.org/more/"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;span style="font-size: small;"&gt;More: Systems Programming with PLT Scheme&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a add_date="1262186328039000" href="http://www.ccs.neu.edu/home/dorai/t-y-scheme/t-y-scheme-Z-H-1.html"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;span style="font-size: small;"&gt;Teach Yourself Scheme in Fixnum Days&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a add_date="1263233999181000" href="http://docs.plt-scheme.org/guide/"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;span style="font-size: small;"&gt;Guide: PLT Scheme&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a add_date="1262274289906000" href="http://www.cs.drexel.edu/~kschmidt/CS360/Lectures/11.html"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;span style="font-size: small;"&gt;Lecture 11: Introduction to Functional Programming and Scheme&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a add_date="1262272585959632" href="http://www.ccs.neu.edu/scheme/pubs/#jfp2004-fffk"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;span style="font-size: small;"&gt;Scheme Materails - NU PLT&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a add_date="1262186298078000" href="ftp://ftp.cs.utexas.edu/pub/garbage/cs345/schintro-v14/schintro_toc.html"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;span style="font-size: small;"&gt;An Introduction to Scheme and its Implementation - Table of Contents&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a add_date="1262185575281000" href="http://www.cs.sjsu.edu/faculty/pearce/scheme/"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;span style="font-size: small;"&gt;Programming and Meta Programming in Scheme&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a add_date="1262185829935000" href="http://programming-musings.org/2009/12/23/scheme-lectures-mostly/"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;span style="font-size: small;"&gt;Scheme lectures, mostly « programming musings&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;a add_date="1262273495210000" href="http://en.wikipedia.org/wiki/Scheme_(programming_language)"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;span style="font-size: small;"&gt;Scheme (programming language) - Wikipedia, the free encyclopedia&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;tweetmeme_url = 'http://docondev.blogspot.com/2010/01/introduction-to-functional-programming.html';&lt;/script&gt;&lt;br /&gt;&lt;script src="http://tweetmeme.com/i/scripts/button.js" type="text/javascript"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;digg_bgcolor = '#558866';digg_skin = 'compact';digg_window = 'new';digg_title = 'Introduction to Functional Programming with Scheme';digg_url = 'http://docondev.blogspot.com/2010/01/introduction-to-functional-programming.html';digg_topic = 'Programming';&lt;/script&gt;&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-7156111166131911943?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/7156111166131911943/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/01/introduction-to-functional-programming.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7156111166131911943'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7156111166131911943'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/01/introduction-to-functional-programming.html' title='Introduction To Functional Programming with Scheme'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-134892778523300958</id><published>2010-01-17T16:46:00.000-05:00</published><updated>2010-01-17T16:46:18.557-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Event'/><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><title type='text'>CodeMash 2010 Review</title><content type='html'>CodeMash 2.0.1.0 was a genuine success.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Complaints&lt;/b&gt;&lt;br /&gt;There were a couple of issues with the communication of session schedules and the WiFi was problematic. But the event coordinators made sure the schedule updates were communicated quickly through the API, allowing the mobile apps we were all using to inform us of the changes. And the Kalahari resort tried to give us the best WiFi experience they could by segmenting us off on our own subnet and providing us a separate pipe from the rest of the resort guests. Hopefully they will be more prepared next year. I suspect attendance will continue to increase. If they can't support the bandwidth demand, the event may need to consider another venue. One final complaint -&amp;nbsp;AT&amp;amp;T coverage was spotty at best, but if you have used AT&amp;amp;T and travelled even the slightest, you know this is common-place.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Accolades&lt;/b&gt;&lt;br /&gt;The rest of the event was fantastic. There were a number of great sessions covering a broad range of topics. Joe O'Brien did a great session on Refactoring the Programmer, Jim Weirich gave a good presentation on a&amp;nbsp;fictitious&amp;nbsp;source management system that had a great deal in common with git, &amp;nbsp;and Chris Smith's talk on F# was downright&amp;nbsp;hilarious. These are a mere few of the &lt;a href="http://codemash.org/Sessions"&gt;many excellent sessions&lt;/a&gt; available this year.&lt;br /&gt;&lt;br /&gt;The Open Space, run my Steven "Doc" List was also very successful. I personally participated in a good discussion on TDD/BDD with Functional Languages which lead to a new movement to create the Ruby Koans for F#, Scala, Clojure, Scheme, etc.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Dollar for dollar, this is the best conference I've experienced. I sincerely recommend this one to anybody interested in software development; beginner, intermediate, or advanced.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-134892778523300958?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/134892778523300958/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/01/codemash-2010-review.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/134892778523300958'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/134892778523300958'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/01/codemash-2010-review.html' title='CodeMash 2010 Review'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-2356563979431505133</id><published>2010-01-02T11:31:00.002-05:00</published><updated>2010-03-09T01:07:49.088-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><category scheme='http://www.blogger.com/atom/ns#' term='Kata'/><title type='text'>What if no one reads it?</title><content type='html'>&lt;h4&gt;You should favor readability&lt;/h4&gt;Among the books I am currently making my way through is "Exploring Computer Science with Scheme" by Oliver Grillmeyer. The publish date on this particular book is 1998. No matter how often it happens, I feel a twinge of despair for our profession when I read sound advice from a decade or more ago that has yet to be widely adopted; or worse is still hotly contested.&lt;br /&gt;&lt;br /&gt;Grillmeyer contrasts a couple different functions that accomplish the same end. One terse, but obfuscated; One verbose, but transparent. In conclusion, Grillmeyer states, "In a tradeoff between readability and length of code, you should favor readability."&lt;br /&gt;&lt;br /&gt;&lt;blockquote class='yellow'&gt;Damn straight.&lt;/blockquote&gt;&lt;br /&gt;Sure, you can use some Ruby-fu and get those four lines in the controller down to one. Yes, you can in-line the whole damn method call. But to what end? For what purpose? Why are you reducing the lines of code? What is your objective?&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Favoring line count&lt;/h4&gt;I once completed the Bowling Kata in Ruby. It was approximately twenty five lines of code. It was readable. Each method had a clear and singular intent. I asked a non-developer friend to look at it and tell me what it did. It took him no more than 60 seconds to figure it out. I then told a Ruby developer about the Kata and without even looking at the code he said, "You should be able to do that in seven lines of Ruby."&lt;br /&gt;&lt;br /&gt;So I set out to refactor the code down to seven lines. And it was an interesting exercise. I managed to get the code down to about twelve lines; I had cut the code in half. But then I stopped. The intent was no longer clear. One had to interpret the code in order to discern what was happening. My tests were a mess; I could not test behaviors in isolation.&lt;br /&gt;&lt;br /&gt;&lt;blockquote class='blue'&gt;I had sacrificed clarity at the altar of line count. And I was ashamed.&lt;/blockquote&gt;&lt;br /&gt;&lt;h4&gt;A (very brief) twitter discussion&lt;/h4&gt;So after reading the line from Grillmeyer, &lt;a href="http://twitter.com/DocOnDev/status/7203910473" target="_blank"&gt;I tweeted it&lt;/a&gt;. Moments later, &lt;a href="http://bit.ly/5wipzv" target="_blank"&gt;a buddy responded&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;What if no one reads it?&lt;/h4&gt;Interesting question.&lt;br /&gt;&lt;br /&gt;So you're working on a pet project; something that only you will ever work on. No other developer will ever see this code. And you're working on a feature where the desired behavior is so well known and immutable that you too will never, ever, under any circumstances need to change it. And the language and platform are absolutes; they too will never change - no new libraries, no change in any of your dependencies; not even a revision tick. You are certain that no one will read it; not even you.&lt;br /&gt;&lt;br /&gt;And you can either write it in a terse manner, or a readable manner (but not both). Which is better?&lt;br /&gt;&lt;br /&gt;Good code is efficient. Good code is testable. Good code displays an attention to detail. Good code has singular purpose and lacks duplication. Good code is expressive. Good code is written by developers who care.&amp;nbsp;Good code is pleasing to read. Good Code is &lt;a href="http://blog.objectmentor.com/articles/2008/04/08/clean-code-whew"&gt;Clean Code&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Having worked on a system that manages over one hundred thousand purchases per day, I do not believe there are many situations which absolutely mandate performance at the cost of readability. So while I expect the argument, I believe it to be an outlier at best, if not completely fictional.&lt;br /&gt;&lt;br /&gt;Given the definition of good code and the&amp;nbsp;likelihood&amp;nbsp;that what we are working on does not require obfuscated code for performance gains, there is no other possible consideration.&lt;br /&gt;&lt;br /&gt;Code must be written for readability. If it is not; it is not good code.&lt;br /&gt;&lt;br /&gt;Certainly, one can opt to knowingly write bad code, but I cannot comprehend the motive.&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;tweetmeme_url = 'http://docondev.blogspot.com/2010/01/what-if-no-one-reads-it.html';&lt;/script&gt;&lt;br /&gt;&lt;script src="http://tweetmeme.com/i/scripts/button.js" type="text/javascript"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;digg_bgcolor = '#558866';digg_skin = 'compact';digg_window = 'new';digg_title = 'What if no one reads it?';digg_url = 'http://docondev.blogspot.com/2010/01/what-if-no-one-reads-it.html';digg_topic = 'Programming';&lt;/script&gt;&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-2356563979431505133?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/2356563979431505133/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/01/what-if-no-one-reads-it.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/2356563979431505133'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/2356563979431505133'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/01/what-if-no-one-reads-it.html' title='What if no one reads it?'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-8856802541498546356</id><published>2010-01-01T12:22:00.002-05:00</published><updated>2010-01-01T12:59:13.544-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Retrospectives'/><title type='text'>Retrospective 2009</title><content type='html'>&lt;h4&gt;Look back to learn, not lament&lt;/h4&gt;Life is full of moments; some wonderful, some tragic. Sometimes, you can't assess the quality of the moment until long after it has passed. Not until you've had the opportunity to live in the shadow of the moment and realize the true impact.&lt;br /&gt;&lt;br /&gt;I have, for many years, believed that our lives are not governed by the events that occur, but by our chosen responses to those events.&lt;br /&gt;&lt;br /&gt;Our inability to accurately asses the quality of a moment, whilst simultaneously being required to chose a response that will certainly alter the course of our lives forever is a fearsome proposition. Yet, however fearsome, I choose this belief every day. I choose it over the notion that all is random and I am a mote of dust blowing in the winds of fate; without cause and without choice and without effect. I choose it over the notion that all is predetermined and I am merely following a foreseen path; without choice and without effect.&lt;br /&gt;&lt;br /&gt;With this belief, I march forward. Looking back only to learn lessons that better equip me for my next decision. There is no purpose or value to lament the past. The decisions I make right now alter my future course. And as a result, I know that decisions in the past need affect only my past.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;2009 Timeline&lt;/h4&gt;&lt;h5&gt;First Quarter&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;Working at The Samara Group (subsidiary of Wayne-Dalton)&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Parent Company is suffering and is not committed to success of TSG&lt;/li&gt;&lt;li&gt;Work situation is extremely poor; low trust, no autonomy.&lt;/li&gt;&lt;li&gt;Suspect we are being shut down&lt;/li&gt;&lt;li&gt;Feel obliged to my co-workers and employees.&lt;/li&gt;&lt;li&gt;Concerned how "failure" will look to others.&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Losing faith in my technical/leadership abilities.&lt;/li&gt;&lt;li&gt;Negligent of personal health&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Running very little&lt;/li&gt;&lt;li&gt;Not lifting&lt;/li&gt;&lt;li&gt;Eating habits are poor&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;h5&gt;Second Quarter&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;TSG is Closed by Parent Company&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Laid off&lt;/li&gt;&lt;li&gt;Self-esteem very low&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Decide not to rush into next job&lt;/li&gt;&lt;li&gt;Need to figure out what makes me happy&lt;/li&gt;&lt;li&gt;Pick up side jobs&lt;/li&gt;&lt;li&gt;Focus on Ruby and Development&lt;/li&gt;&lt;li&gt;Start working with LeanDog and Pillar on job in Detroit&lt;/li&gt;&lt;li&gt;Get calls from ThoughtWorks and several others to interview&lt;/li&gt;&lt;li&gt;Join running club and Men's group&lt;/li&gt;&lt;li&gt;Re-building my self-esteem&lt;/li&gt;&lt;li&gt;Personal Health gets attention&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Run daily&lt;/li&gt;&lt;li&gt;Lift daily&lt;/li&gt;&lt;li&gt;Eat right&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;h5&gt;Third Quarter&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;Start at ThoughtWorks&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Planning to stay for six months at most&lt;/li&gt;&lt;li&gt;Discussing emergent opportunities in Cleveland with LeanDog&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Move in with my brother Rick&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Sleeping on air mattress in his home office&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Side Jobs get no attention&lt;/li&gt;&lt;li&gt;Start Scheme Study Group&lt;/li&gt;&lt;li&gt;Personal Health good&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Running almost exclusively&lt;/li&gt;&lt;li&gt;Some lifting&lt;/li&gt;&lt;li&gt;Experience mild back pain&lt;/li&gt;&lt;li&gt;Ease up on strict eating habits&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Enjoying life, but miss my family&lt;/li&gt;&lt;ul&gt;&lt;li&gt;ThoughtWorks pays for flights home and back so I can see family (WOW)&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;h5&gt;Fourth Quarter&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;Decide to stay with ThoughtWorks for as long as they'll have me&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Like so many things about the company&lt;/li&gt;&lt;li&gt;Feel "at home" for first time in over a decade&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Get (much needed) help with side projects&lt;/li&gt;&lt;li&gt;Moved into Corporate Housing&lt;/li&gt;&lt;li&gt;Personal Health Suffering&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Back Pain is chronic&lt;/li&gt;&lt;li&gt;Running limited&lt;/li&gt;&lt;li&gt;Lift very infrequently&lt;/li&gt;&lt;li&gt;Eating habits are poor&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;br /&gt;&lt;h4&gt;Starfish for 2010&lt;/h4&gt;&lt;h5&gt;Do More&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;Communicate with Family and Friends&lt;/li&gt;&lt;li&gt;Show Appreciation to Others&lt;/li&gt;&lt;li&gt;Active participation in family finances&lt;/li&gt;&lt;li&gt;Work Out - run, yoga, lift&lt;/li&gt;&lt;li&gt;Study / Learn / Teach&lt;/li&gt;&lt;li&gt;Blog Posts&lt;/li&gt;&lt;li&gt;Ruby and fun languages&lt;/li&gt;&lt;li&gt;Eat Well&lt;/li&gt;&lt;/ul&gt;&lt;h5&gt;Do Less&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;Java&lt;/li&gt;&lt;li&gt;Side Jobs&lt;/li&gt;&lt;li&gt;Consuming Alcohol&lt;/li&gt;&lt;/ul&gt;&lt;h5&gt;Start&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;Daily Journal&lt;/li&gt;&lt;li&gt;Help Wife with Career&lt;/li&gt;&lt;li&gt;Join 401k at work (saving)&lt;/li&gt;&lt;/ul&gt;&lt;h5&gt;Stop&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;Working long hours&lt;/li&gt;&lt;li&gt;Worrying about what others think&lt;/li&gt;&lt;/ul&gt;&lt;h5&gt;Continue&lt;/h5&gt;&lt;ul&gt;&lt;li&gt;Involvement in Technical Community&lt;/li&gt;&lt;li&gt;Building Personal Brand&lt;/li&gt;&lt;li&gt;Working on relationship with Family&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-8856802541498546356?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/8856802541498546356/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2010/01/retrospective-2009.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/8856802541498546356'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/8856802541498546356'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2010/01/retrospective-2009.html' title='Retrospective 2009'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-1587894032838636831</id><published>2009-12-24T11:15:00.000-05:00</published><updated>2009-12-24T11:15:58.133-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Teams'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><title type='text'>My experience at ThoughtWorks (so far)</title><content type='html'>I came across &lt;a href="http://damana.blogspot.com/2009/12/if-shoe-fits.html"&gt;a post written by a former ThoughtWorker&lt;/a&gt; and was intrigued by what I read. I've long known that two people can enter a small party and have two completely different experiences based on where they focus their attentions. The larger the party, the more likely the experiences will differ. More significant, however, is how the people themselves differ.&lt;br /&gt;&lt;br /&gt;Damana talks of the ThoughtWorks I've come to love; A team of intelligent, talented, motivated individuals working together in an environment that encourages diversity, provides rich individual attention, encourages community involvement, and pushes each of us to continue to grow.&lt;br /&gt;&lt;br /&gt;Damana also talks of another ThoughtWorks; A team of ego-driven elitists who lack compassion and fundamental social skills. Intellectual bullies who prefer manipulation over trust and who value the client far less then they do the elegant perfection of software.&lt;br /&gt;&lt;br /&gt;I believe both ThoughtWorks exist. I know there are ego-driven elitists. I know there are bullies who prefer manipulation over trust. And I know there are those who value the elegant perfection of software over the needs of the client. I've met all of them at ThoughtWorks. I've worked with each of them. &amp;nbsp;But from my vantage-point, these people are in the minority. They certainly do not make up 75% of the people I've worked with; not even 10%.&lt;br /&gt;&lt;br /&gt;In terms of changing the world, I know of no other software company who has "Social Responsibility" as a key part of their &lt;a href="http://www.thoughtworks.com/who-we-are/our-culture.html"&gt;corporate values&lt;/a&gt; and employs an active "Director of Social Engagement". This individual's role is to get TW more involved in world events; to find ways to leverage our skills and strengths to make the world a better place. ThoughtWorkers volunteered their time to work on software that helps distribute aid in third-world countries. ThoughtWorks hosts events such as &lt;a href="http://www.siliconindia.com/shownews/ThoughtWorks_to_Host_Pangea_Day_in_Bangalore_and_Pune-nid-41842.html"&gt;Pangea Day&lt;/a&gt; and is actively involved in &lt;a href="http://nijel.org/blog/?p=179"&gt;other significant events around the world&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;ThoughtWorks is, hands down, the best place I've ever worked. We are a diverse crowd. We come from all over the world with wildly different backgrounds and experiences. One should anticipate some tension amidst diversity, but ThoughtWorks is conscientious in their hiring practices and is intolerant of intolerance.&lt;br /&gt;&lt;br /&gt;Damana and I spent time at the same party. We had significantly different experiences. And we are both right. For neither of us can articulate the "truth". Each of us can only share our perception; our interpretation.&lt;br /&gt;&lt;br /&gt;There is one more thing Damana and I surely agree on:&lt;br /&gt;"If you ever get to work at a company like ThoughtWorks then don't accept another job[...] it will change your life, your career and your soul."&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;tweetmeme_url = 'http://docondev.blogspot.com/2009/12/my-experience-at-thoughtworks-so-far.html';&lt;/script&gt;&lt;br /&gt;&lt;script src="http://tweetmeme.com/i/scripts/button.js" type="text/javascript"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;digg_bgcolor = '#558866';digg_skin = 'compact';digg_window = 'new';digg_title = 'My experience at ThoughtWorks (so far)';digg_url = 'http://docondev.blogspot.com/2009/12/my-experience-at-thoughtworks-so-far.html';digg_topic = 'Programming';&lt;/script&gt;&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-1587894032838636831?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/1587894032838636831/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2009/12/my-experience-at-thoughtworks-so-far.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/1587894032838636831'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/1587894032838636831'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2009/12/my-experience-at-thoughtworks-so-far.html' title='My experience at ThoughtWorks (so far)'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-2861506339162260049</id><published>2009-12-07T23:59:00.002-05:00</published><updated>2009-12-08T00:07:44.556-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><title type='text'>Business Value is not the only reason to adopt Agile</title><content type='html'>Agile Rob posted a column a few days ago entitled, &lt;a href="http://blog.adsdevshop.com/2009/12/03/if-you-dont-focus-on-business-value-dont-adopt-agile/"&gt;"If You Don’t Focus on Business Value, Don’t Adopt Agile."&lt;/a&gt; He tweeted it out and after reading it, I replied that I did not entirely agree. Rob asked that I post a comment on his blog. The following is an extended/modified version of that reply.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I read two articles today, &lt;a href="http://www.leadingagile.com/2009/12/adopting-agile-isnt-point.html"&gt;"Adopting Agile Isn't The Point"&lt;/a&gt;, by Mike Cottmeyer and &lt;a href="http://blog.adsdevshop.com/2009/12/03/if-you-dont-focus-on-business-value-dont-adopt-agile/"&gt;"If You Don’t Focus on Business Value, Don’t Adopt Agile."&lt;/a&gt;, by Robert Dempsey. Rob's posting is an expression of agreement with Mike's.&lt;br /&gt;&lt;br /&gt;Mike's basic point is that we can lose the sight of our actual goal when we phrase our efforts in terms of task rather than objective. "When we allowed ourselves to define our work in terms of our activities, we risked losing focus on the desired outcome of the project."&lt;br /&gt;&lt;br /&gt;He then applies this to Agile adoptions. The goal is not to have a Scrum master or to do TDD. "Those things are the stuff we do to get the desired business outcome."&lt;br /&gt;&lt;br /&gt;You can analogously extend this to other areas of your life. I am a runner. I've set a 5k goal time for myself. In order to get there, I've laid out a plan that includes certain tasks on certain days. My goal is not to run 30+ miles per week. My goal is not to do 8 weeks of hill training. My goal is to run the 5k faster than a certain pace. If I need to adjust the tasks, so be it. If I focus on the tasks, I lose sight of the goal. I may very well finish 8 weeks of hill training and find myself injured.&lt;br /&gt;&lt;br /&gt;I agree with Mike.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Rob takes this fundamental premise and extends it to say, "If you don't focus on business value, don't adopt agile."&lt;br /&gt;&lt;br /&gt;This I do not entirely agree with.&lt;br /&gt;&lt;br /&gt;This, to me, is similar to, "If you don't focus on cardio-vascular health, don't take up running." While cardio-vascular health is a significant and worthy objective, it is not the only reason to run. Fortunately, it is a common and beneficial side effect.&lt;br /&gt;&lt;br /&gt;I might adopt agile to improve code quality, to deliver in smaller increments, or to improve communication. These are also valuable and worthy objectives. They are likely to add value to the business as a common and beneficial side effect. Just as a goal of a certain time in the 5k can result in improved cardio-vascular health.&lt;br /&gt;&lt;br /&gt;The point is that we know our true goals and objectives. That we know why we are performing certain tasks. And that we not confuse the tasks with the desired outcome. This is not the same as saying there is only one true desired outcome.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Adopting agile isn't the point. Business value doesn't have to be either.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;tweetmeme_url = 'http://docondev.blogspot.com/2009/12/business-value-is-not-only-reason-to.html';&lt;/script&gt;&lt;br /&gt;&lt;script src="http://tweetmeme.com/i/scripts/button.js" type="text/javascript"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;digg_bgcolor = '#558866';digg_skin = 'compact';digg_window = 'new';digg_title = 'Business Value is not the only reason to adopt agile';digg_url = 'http://docondev.blogspot.com/2009/12/business-value-is-not-only-reason-to.html';digg_topic = 'Programming';&lt;/script&gt;&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-2861506339162260049?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/2861506339162260049/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2009/12/business-value-is-not-only-reason-to.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/2861506339162260049'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/2861506339162260049'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2009/12/business-value-is-not-only-reason-to.html' title='Business Value is not the only reason to adopt Agile'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-6152393389899467131</id><published>2009-10-15T17:51:00.006-04:00</published><updated>2009-10-15T20:51:21.395-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><category scheme='http://www.blogger.com/atom/ns#' term='Kata'/><title type='text'>Karate Chop Kata in Ruby</title><content type='html'>I have to admit, this was a lot more difficult than I originally anticipated. A binary sort seems simple enough. This is 101 stuff, right?&lt;br /&gt;&lt;br /&gt;But my first couple of runs resulted in relatively long procedures with a lot of boundary checking. While my specs were passing, the smell of the code was really bothering me.&lt;br /&gt;&lt;br /&gt;I found a reference implementation and gave it a run, but discovered that it failed my specs. After a double-check of the specs to confirm I didn't have something messed up, I decided to dump the RI and try it again.&lt;br /&gt;&lt;br /&gt;Finally, the pieces fell together and I could see where most of the boundary checking fell out of the method as I changed the sequence of events.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;The Code&lt;/h4&gt;&lt;pre class="brush: ruby"&gt;class Chop&lt;br /&gt;  def self.find(lookFor, lookIn, start_index=nil, end_index=nil)&lt;br /&gt;    start_index ||= 0&lt;br /&gt;    end_index ||= lookIn.length&lt;br /&gt;    middle = (start_index + end_index)/2&lt;br /&gt;    &lt;br /&gt;    return middle if lookFor == lookIn[middle]&lt;br /&gt;    return -1 if ((middle == start_index) || (middle == end_index))&lt;br /&gt;    return find(lookFor, lookIn, start_index, middle) if lookFor &amp;lt; lookIn[middle]&lt;br /&gt;    return find(lookFor, lookIn, middle, end_index) if lookFor &amp;gt; lookIn[middle]&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;The Specs&lt;/h4&gt;&lt;pre class="brush: ruby"&gt;require "spec"&lt;br /&gt;require "karate_chop"&lt;br /&gt;&lt;br /&gt;describe Chop do&lt;br /&gt;  context "with an empty sorted array" do&lt;br /&gt;    it "indicates item not found" do&lt;br /&gt;      Chop.find(1, []).should == -1&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  context "with search target not in array" do&lt;br /&gt;    it "indicates item not found" do&lt;br /&gt;      Chop.find(1, [0,2,3]).should == -1&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  context "with search target in array" do&lt;br /&gt;    it "provides the index of the located item when in the middle of the array" do&lt;br /&gt;      Chop.find(1, [0,1,2,3]).should == 1&lt;br /&gt;      Chop.find(4, [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21]).should == 4&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    it "provides the index of the located item when it is last in the array" do&lt;br /&gt;      Chop.find(20, [5, 10, 15, 20]).should == 3&lt;br /&gt;    end&lt;br /&gt;&lt;br /&gt;    it "provides the index of the located item when it is first in the array" do&lt;br /&gt;      Chop.find(20, [20,40,60,80]).should == 0&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;  context "with a large array" do&lt;br /&gt;    it "locates the item" do&lt;br /&gt;      search_in = Array(0..900)&lt;br /&gt;      Chop.find(100, search_in).should == 100&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I am looking for feedback on these. Please, feel free to let me know how I could improve my code or specs. Or share links to your own solutions.&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;tweetmeme_url = 'http://docondev.blogspot.com/2009/10/karate-chop-kata-in-ruby.html';&lt;/script&gt;&lt;br /&gt;&lt;script src="http://tweetmeme.com/i/scripts/button.js" type="text/javascript"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;digg_bgcolor = '#558866';digg_skin = 'compact';digg_window = 'new';digg_title = 'Karate Chop Ruby Kata';digg_url = 'http://docondev.blogspot.com/2009/10/karate-chop-kata-in-ruby.html';digg_topic = 'Programming';&lt;/script&gt;&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-6152393389899467131?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/6152393389899467131/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2009/10/karate-chop-kata-in-ruby.html#comment-form' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/6152393389899467131'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/6152393389899467131'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2009/10/karate-chop-kata-in-ruby.html' title='Karate Chop Kata in Ruby'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-2978554972162234893</id><published>2009-10-14T12:13:00.003-04:00</published><updated>2010-05-02T10:38:39.607-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><category scheme='http://www.blogger.com/atom/ns#' term='How To'/><category scheme='http://www.blogger.com/atom/ns#' term='Technical Debt'/><title type='text'>Martin Fowler on Technical Debt</title><content type='html'>&lt;a href="http://martinfowler.com/bliki/TechnicalDebtQuadrant.html"&gt;Martin Fowler just posted an article on Technical Debt&lt;/a&gt; in which he discusses the Technical Debt Metaphor. Fowler argues that the metaphor should (and does) include messy code. He talks about deliberate and inadvertent debt as well as reckless and prudent debt. Prudent and Deliberate is the most desirable. While Reckless and Inadvertent is the least desirable. He published the following quadrant to help explain his concept.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://martinfowler.com/bliki/techDebtQuadrant.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://martinfowler.com/bliki/techDebtQuadrant.png" /&gt;&lt;/a&gt;He concludes with a statement about the risks of using the debt metaphor for messy code; "However a problem with using the debt metaphor for this is   that I can't conceive of a parallel with taking on a   prudent-inadvertent financial debt. As a result I would think it   would be difficult to explain to managers why this debt appeared. My   view is this kind of debt is inevitable and thus should be   expected. Even the best teams will have debt to deal with as a   project goes on - even more reason not to recklessly overload it   with crummy code."&lt;br /&gt;&lt;br /&gt;I would argue that the worst form of debt under this definition is in fact Reckless and Deliberate. This has been the motivation behind my assertion that Messy Code should not be considered Technical Debt. It allows teams to hide messy code behind a comfortable metaphor. We, as programmers, need to hold our standards high. Our goal needs to be a clean code standard.&lt;br /&gt;&lt;br /&gt;While I recognize that Messy Code happens inadvertently, I don't think it should happen deliberately without very clear communication to the customer. And when this conversation takes place, I think you need to say, "In order to meet the deadline, we need to write messy code that will cause us problems from here forth until it is cleaned up." rather than saying, "In order to meet the deadline, we need to take on some technical debt."&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;tweetmeme_url = 'http://docondev.blogspot.com/2009/10/martin-fowler-on-technical-debt.html';&lt;/script&gt;&lt;br /&gt;&lt;script src="http://tweetmeme.com/i/scripts/button.js" type="text/javascript"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;digg_bgcolor = '#558866';digg_skin = 'compact';digg_window = 'new';digg_title = 'Martin Fowler on Technical Debt';digg_url = 'http://docondev.blogspot.com/2009/10/martin-fowler-on-technical-debt.html';digg_topic = 'Programming';&lt;/script&gt;&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-2978554972162234893?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/2978554972162234893/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2009/10/martin-fowler-on-technical-debt.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/2978554972162234893'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/2978554972162234893'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2009/10/martin-fowler-on-technical-debt.html' title='Martin Fowler on Technical Debt'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-2486919936185631110</id><published>2009-10-14T08:52:00.000-04:00</published><updated>2009-10-14T08:52:36.477-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><category scheme='http://www.blogger.com/atom/ns#' term='Kata'/><title type='text'>Practicing Your Craft Through Code Kata</title><content type='html'>I assume most of you are aware of &lt;a href="http://codekata.pragprog.com/"&gt;code kata&lt;/a&gt;. For those who are not; a kata is a simple code exercise. The idea is to perform these exercises in a practice session with no interruptions and no pressure where you can try each as many times as necessary. The goal is to learn and to build the muscle memory necessary to perform these tasks flawlessly in pressure situations.&lt;br /&gt;&lt;br /&gt;I am putting together a series of kata for your consideration. I will be certain to give attribution for each as most (if not all) will be exercises found on that thar InterWeb, written by others and &lt;strike&gt;plagiarized&lt;/strike&gt; highlighted here.&lt;br /&gt;&lt;br /&gt;For my first few, I plan to draw from the series available on the Pragmatic Programmer's site where, to date, &lt;a href="http://codekata.pragprog.com/"&gt;Prag Dave has listed 21 kata&lt;/a&gt;. &lt;br /&gt;For all kata, I will follow a Pomodoro style, using &lt;a href="http://tomatoi.st/docondev"&gt;tomatoi.st&lt;/a&gt; as my timer. I will attempt to complete each exercise in a single 25 minute pomodoro. Most kata are achievable in this amount of time, but not necessarily on the first attempt.&lt;br /&gt;&lt;br /&gt;I will post code snippets and might even get gutsy and put up a few screen casts if I get proficient enough at some of them. It is my intention to complete all kata in Ruby. I may opt to work them in Java, Scheme, C#, or javascript as well.&lt;br /&gt;&lt;br /&gt;I welcome your feedback and constructive criticisms. I am looking to improve my craft through kata. If you see something I could be doing more efficiently or effectively, please let me know.&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;tweetmeme_url = 'http://docondev.blogspot.com/2009/10/practicing-your-craft-through-code-kata.html';&lt;/script&gt;&lt;br /&gt;&lt;script src="http://tweetmeme.com/i/scripts/button.js" type="text/javascript"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;digg_bgcolor = '#558866';digg_skin = 'compact';digg_window = 'new';digg_title = 'Practicing Your Craft Through Code Kata';digg_url = 'http://docondev.blogspot.com/2009/10/practicing-your-craft-through-code-kata.html';digg_topic = 'Programming';&lt;/script&gt;&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-2486919936185631110?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/2486919936185631110/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2009/10/practicing-your-craft-through-code-kata.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/2486919936185631110'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/2486919936185631110'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2009/10/practicing-your-craft-through-code-kata.html' title='Practicing Your Craft Through Code Kata'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-6750596534838255300</id><published>2009-10-11T20:53:00.002-04:00</published><updated>2009-10-11T21:09:27.310-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Event'/><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><title type='text'>SDTConf Day Two</title><content type='html'>Day two started with another quick planning session. This one went a lot faster. We had fewer topics suggested and everyone was more familiar with the format. This allowed the first sessions of the day to get started a bit early. Of course, following the Rules of Open Space, "Whenever it starts is the right time." So I suppose everything started precisely on time.&lt;br /&gt;&lt;br /&gt;I started the day with a session on refactoring. This was a good session; well attended and well presented, but I was in the mood for a little more interaction, so I followed the rule of two feet and wandered into a discussion on introducing Agile in a Hostile Environment. Right up my alley. I failed at this numerous times before my first successes, so I had plenty of experience to draw upon. The attendees were primarily developers and leads who were sold on Agile, but found it difficult to introduce into their teams. I could empathize with them. Each of their attempts was met with a lot of resistance.&lt;br /&gt;&lt;br /&gt;We discussed approaches that involved avoiding too many buzz words, identifying one likely ally, or simply leading by example. But the best advice had little to do with Agile and more to do with simple human nature. Listen to your team. Get to understand their personal pain. And then help them relieve that pain. While you may genuinely believe that TDD will solve a lot of problems for the team, if their immediate pain is with the build, then get CI stood up first. People are usually far less resistant to change than we give them credit for. The problem is often that they are already uncomfortable. Sweeping change is too big, too vague, and too risky.&lt;br /&gt;&lt;br /&gt;I do have another piece of advice for those we are struggling in environments that are highly resistant to change. Leave. Sometimes it is better to change the people you are around rather than try to change the people around you. I am not suggesting we all quit at the first sign of resistance. But sometimes there comes a point when one realizes they are merely tilting at windmills.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;My next session was on User Experience and User Centered Design (UX/UCD) in an Agile environment. My objective for the discussion was to find practices that served UX/UCD well and mapped to iterations. The predominant thinking is that UX/UCD is an up-front activity that must be complete prior to development. I'd like us to continue to challenge that thinking.&lt;br /&gt;&lt;br /&gt;A great deal of the early discussion was around Contextual Inquiry as a part of requirements gathering and User Testing during the development cycle. We shared stories of success, stories of near success, and stories of sheer frustration. But we struggled to come up with additional techniques or insights. I was enjoying the discussion, but felt the session was coming to an early end. We were covering the same ground with no new insight.&lt;br /&gt;&lt;br /&gt;And then Jeff Patton spoke. Quiet. Unassuming. Jeff stated that there are essentially three facets to the user experience. He drew a pyramid and separated it into three horizontal sections. At the base, he wrote "Utility" and explained that this is what the system does. Contextual Inquiry helps us define this. In the center section, he wrote the word "Usability" and explained that this is how the system is used. User interviews help us define this. Finally, at the top he wrote "Aesthetics" and explained this is presentation. It is important to understand the practices and how and where they apply.&lt;br /&gt;&lt;br /&gt;You need to have Utility covered first. This does not make it the most important, but if the application cannot perform the intended function, it is a failure. It does not matter how usable or pleasing it is. &lt;br /&gt;&lt;br /&gt;You need to have usability covered next. If an application is capable of performing the task, but is difficult to use, you will have less success. If users have alternatives, you risk losing them to something easier to use. If your users are a captive audience, you will see increased costs in training and re-work or they will do everything they can to avoid using the software.&lt;br /&gt;&lt;br /&gt;Finally, you need aesthetics. This is where the psychological aspect is most significant. If people are pleased with the interface, they may actually tolerate a lack of usability. Jeff used Apple as an example. Design (aesthetics) are very important at Apple. While their products are not always easier to use, you do not mind the minor inconvenience. You are pleased to use the iPhone. It is ok that you have to scroll over three pages to find the app. The WAY you scroll the pages is kinda fun.&lt;br /&gt;&lt;br /&gt;There are plenty of applications that prove Utility and Usability are sufficient. Craig's List is so anti-aesthetically conscious, it seems the lack of design IS the design. People don't care that it is plain; it does exactly what they want and it is easy to use.&lt;br /&gt;&lt;br /&gt;Jeff's points resonated with me. I knew these things, yet failed to consider them as I was looking for techniques that could be mapped to iterations. If you don't understand how the practice applies and why you're doing it then it doesn't much matter if you do it before, after, or during an iteration. You're probably going to get it wrong. Figure out what you're trying to achieve, then figure out how.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I really enjoy conferences like these. Low ceremony, high value.&lt;br /&gt;&lt;br /&gt;There are three ways to learn; push, pull, and share.&lt;br /&gt;&lt;br /&gt;Push is where you sit in a class or session and someone walks you through a lesson or seminar. This is typically low signal to noise. You are going to get a lot of information, only some of which you are currently interested in or can use.&lt;br /&gt;&lt;br /&gt;Pull is where you seek out the data and gather it for yourself. This is better signal to noise. You can control the flow of information and can target the information to your specific interest or need.&lt;br /&gt;&lt;br /&gt;Share is where two or more people freely exchange ideas. This is my favorite form of learning. Everyone learns and if the conversation is truly a balanced and free exchange, there is all signal and no noise.&lt;br /&gt;&lt;br /&gt;SDTConf and other open spaces are Share learning.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;tweetmeme_url = 'http://docondev.blogspot.com/2009/10/sdtconf-day-two.html';&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;script src="http://tweetmeme.com/i/scripts/button.js" type="text/javascript"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;digg_bgcolor = '#558866';digg_skin = 'compact';digg_window = 'new';digg_title = 'Simple Design and Testing Conference - Day Two';digg_url = 'http://docondev.blogspot.com/2009/10/sdtconf-day-two.html';digg_topic = 'Programming';&lt;/script&gt;&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-6750596534838255300?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/6750596534838255300/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2009/10/sdtconf-day-two.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/6750596534838255300'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/6750596534838255300'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2009/10/sdtconf-day-two.html' title='SDTConf Day Two'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-6811623088748762580</id><published>2009-10-11T10:22:00.002-04:00</published><updated>2009-10-11T21:01:56.037-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Event'/><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><title type='text'>SDTConf Day One</title><content type='html'>I really like the open space format. Simple rules. Maximum value.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Whoever shows up is the right group of people.&lt;/li&gt;&lt;li&gt;Whatever happens is the only thing that could have.&lt;/li&gt;&lt;li&gt;Whenever it starts is the right time.&lt;/li&gt;&lt;li&gt;When It is over, it is over.&lt;/li&gt;&lt;/ol&gt;We started the day with a round of introductions and then did a light-weight scheduling exercise to get the sessions for the day arranged. I was so enthralled with the other potential topics, that I pushed UX/UCD and how they map to Agile to on-deck for day two. I hope I don't regret that decision. Some folks are here for the one day.&lt;br /&gt;&lt;br /&gt;The rule of two feet is a beautiful thing. This is not an explicit open space rule, but it certainly exists. The rule of two feet simply rephrased is, "You have two feet. If the session does not serve you, walk." It is not considered rude to leave a session in progress. To some extent, this is encouraged. It is considered rude to break wind and yell, "F you guys, I'm outta here!" I learned that the hard way.&lt;br /&gt;&lt;br /&gt;I attended a number of excellent sessions today and participated in several very good hallway discussions as well.&lt;br /&gt;&lt;br /&gt;We discussed the pros and cons of taking advantage of "others' code"; from frameworks to libraries to gems to simple copy/paste. We shared stories of pain and stories of success. In the end the general consensus was that frameworks are usually painful where libraries and more discrete items are easier to leverage with minimal risk. Ultimately, we agreed that the more discrete the component, the better the API, and the greater the intent of reuse, the more likely you are to be successful.&lt;br /&gt;&lt;br /&gt;We evaluated roles and the sequence of steps in the overall development cycle. One conclusion drawn was that all involved in the delivery of software should be called developers. You may (or may not) have roles such as BA, programmer, and QA. But ALL of them are responsible for the successful development of code. There was lengthy discussion around the stages of development and while we all agreed that putting creation of tests in front of development of code, we also agreed that it is a complex cultural shift and will take time. We're not talking about just unit tests here. Acceptance tests; the specific criteria by which the story will be evaluated need to happen before code is written.&lt;br /&gt;&lt;br /&gt;We discussed learning and the intimidating amount of knowledge a developer really needs to have in order to be a master in their domain. Hell , the intimidating amount of knowledge a developer really need to have in order to be a novice in their domain. How do we create a path to guide new developers? Are there a simple set of one dozen patterns, practices, and/or principles that every new developer should learn first? Is there a single pattern or principle (there can be only ONE) from which all others can be derived? It was a very good conversation and I look forward to the results of the discussion.&lt;br /&gt;&lt;br /&gt;Dinner conversation was as interesting and educational as the conference discussions. At my end of the table, we discussed (among several topics), the long-term value of XP practices in a mature shop. Do highly skilled and experienced developers need to follow these practices or do they have enough experience that they no longer need the safety and guidance provided? Do these practices actually impede delivery once you've achieved a certain level of skill and proficiency?&lt;br /&gt;&lt;br /&gt;While it was an interesting conversation, it concerned me, much like Spolsky's Duct Tape Programmer post. Let's assume the assertion is true. Developers reach a level of excellence where they no longer need to follow some of the practices that got them there. Here's my primary concern - How do you honestly know you are so good, you no longer need the safety net for performance? Our profession is riddled with a strong ignorance to ego cohesion. I hear story after story of developer who was absolutely certain they were awesome and correct in everything they did and they then stumbled (or were dragged kicking and screaming) into TDD and had an "aha" moment. Prior to the "aha" moment, the developer &lt;i&gt;&lt;b&gt;knew&lt;/b&gt;&lt;/i&gt; they were excellent and did not need those West Coast, touchy feely, hippie, group hug concepts&lt;sup&gt;&lt;a href="http://www.blogger.com/post-create.g?blogID=8528631747209969303#TB"&gt;1&lt;/a&gt;&lt;/sup&gt;. There are far too many developers who are prior to their own "aha" moment. They may read the Duct Tape post or get involved in these conversations and conclude that they are one of those excellent developers who need not concern themselves with the "overhead" necessary only for lesser mortals.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I am looking forward to day two. It is a fantastic experience to spend time with professionals interested in their craft; those who see value in taking a weekend and spending time (and some money) on developing a deeper understanding and challenging their own current views.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;&lt;a href="http://www.blogger.com/post-edit.g?blogID=8528631747209969303&amp;amp;postID=6811623088748762580" name="TB"&gt;1&lt;/a&gt; - Special thanks to TB for this expressive description of Agile. I suspect TB is still sitting alone in his cubicle somewhere cranking out amazingly complex modules full of features nobody asked for, but he is absolutely confident they will need someday. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;tweetmeme_url = 'http://docondev.blogspot.com/2009/10/sdtconf-day-one.html';&lt;/script&gt;&lt;br /&gt;&lt;script src="http://tweetmeme.com/i/scripts/button.js" type="text/javascript"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;digg_bgcolor = '#558866';digg_skin = 'compact';digg_window = 'new';digg_title = 'Simple Design and Testing Conference - Day One';digg_url = 'http://docondev.blogspot.com/2009/10/sdtconf-day-one.html';digg_topic = 'Programming';&lt;/script&gt;&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-6811623088748762580?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/6811623088748762580/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2009/10/sdtconf-day-one.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/6811623088748762580'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/6811623088748762580'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2009/10/sdtconf-day-one.html' title='SDTConf Day One'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-5540813313437000773</id><published>2009-10-07T18:39:00.008-04:00</published><updated>2009-10-07T18:48:03.613-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><title type='text'>Craftsmanship</title><content type='html'>I have the profound and intimidating honor of being the fifth person to make note in &lt;a href="http://www.nexwerk.com/the_wandering_book"&gt;the Wandering Book&lt;/a&gt;. To be honest, I'd hoped to be later in line. I'd hoped I could read numerous entries and ponder all the wisdom before it came my turn to write. As the fifth, I have to admit there is already a great deal of wisdom in the book. The four before me are remarkable people. And those who will follow me are surely remarkable as well.&lt;br /&gt;&lt;br /&gt;Corey Haines talks about practice and learning. He talks about the path to mastery and ultimately, the role of the master as teacher.&lt;br /&gt;&lt;br /&gt;Jason Gorman explains that Craftsmanship is not about practices or membership. It is about caring, learning, and practicing.&lt;br /&gt;&lt;br /&gt;Dave Hoover ties the two prior entries together and stresses the need for more people to commit themselves to mastery.&lt;br /&gt;&lt;br /&gt;Eric Smith tells a personal story of how the craftsmanship movement rekindled his passion for software development.&lt;br /&gt;&lt;br /&gt;I've pondered these stories; these lessons; these words of wisdom. I've thought about my own journey. I've considered what it is that drives me. What it is that inspires me. Why I choose to be a software developer and what is important to me about my craft.&lt;br /&gt;&lt;br /&gt;There is a simple, poignant, common thread throughout the book already. Learning, Practicing, and Sharing. Craftsmanship is about continual improvement. Craftsmanship is about applying the craft. Craftsmanship is about being your best and helping others to be their best. Craftsmanship is about the free exchange of ideas. &lt;br /&gt;&lt;br /&gt;My journey has been long. I've been in the industry for over 20 years now. And I feel as though I am only at the beginning. But throughout the years, the most rewarding experiences have always been those where I worked closely with an open and honest team. And consistently, it is from those experiences that I learned the most and was able to share the most knowledge with others.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Craftsmanship is Learning, Practicing, and Sharing.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;tweetmeme_url = 'http://docondev.blogspot.com/2009/10/craftsmanship.html';&lt;/script&gt;&lt;br /&gt;&lt;script src="http://tweetmeme.com/i/scripts/button.js" type="text/javascript"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;digg_bgcolor = '#558866';digg_skin = 'compact';digg_window = 'new';digg_title = 'Craftsmanship';digg_url = 'http://docondev.blogspot.com/2009/10/craftsmanship.html';digg_topic = 'Programming';&lt;/script&gt;&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-5540813313437000773?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/5540813313437000773/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2009/10/craftsmanship.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/5540813313437000773'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/5540813313437000773'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2009/10/craftsmanship.html' title='Craftsmanship'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-7572354911086294225</id><published>2009-10-01T08:32:00.001-04:00</published><updated>2009-10-01T08:34:09.192-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><title type='text'>Running Developers Unite! - Update</title><content type='html'>I received a lot of positive response from the initial posts about getting a running group for developers started. After a bit of research, it seemed the fastest way to get something going, was to take advantage of www.dailymile.com and start a group.&lt;br /&gt;&lt;br /&gt;I started the group about one week ago and we have 9 members so far. If you are interested, please visit the group and join us. There is no obligation. It's just a bunch of developer-types who also happen to run, whether it be casual, for fitness, or competitive.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.dailymile.com/groups/595-test-code-run"&gt;http://www.dailymile.com/groups/595-test-code-run&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;tweetmeme_url = 'http://docondev.blogspot.com/2009/10/running-developers-unite-update.html';&lt;/script&gt;&lt;br /&gt;&lt;script src="http://tweetmeme.com/i/scripts/button.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-7572354911086294225?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/7572354911086294225/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2009/10/running-developers-unite-update.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7572354911086294225'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7572354911086294225'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2009/10/running-developers-unite-update.html' title='Running Developers Unite! - Update'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-2764745802464939067</id><published>2009-09-25T20:45:00.002-04:00</published><updated>2009-10-01T08:22:38.700-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><title type='text'>I'd rather be in last place</title><content type='html'>I joined the cross country team my freshman year of high school. I knew nothing about the team and little about the sport, but I figured running wasn't too difficult and was certainly less dangerous than football.&lt;br /&gt;&lt;br /&gt;It turns out the team was one of the best in the state. They had a legacy of excellence for well over a decade. They consistently won their league, placed in districts and regionals and sent at least individuals, if not the entire team to state.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;These guys were good. And I was terrible; slow, gangly, poor form, clumsy.... I had limited natural talent for running (or sports in general it would seem).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I was determined to get better. I was determined to letter my freshman year. So I hung out with the junior varsity and varsity whenever I could. I would run with them for as long as I could endure before falling off the pace. I got obliterated every day in practice and I finished "last."&lt;br /&gt;&lt;br /&gt;Some of my team mates made fun of me. "Norton, why do you run with those guys? You finish last every day. Run with us. Don't be a moron."&lt;br /&gt;&lt;br /&gt;But I lettered as a freshman. I went on to do fairly well. I lettered all four years. I ran varsity for a couple of years and rounded out my senior year as team captain.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I am much older now. And I still run. And I still remember the lessons from my freshman year.&lt;br /&gt;&lt;br /&gt;Software isn't a competition. But like cross country, it is an individual task executed as a team. And the entire team relies on each individual; from the top runner to the seventh. On any given day, one team member's performance can suffer and it is up to the rest of the team to make up the difference.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;If you want to improve, surround yourself with people who are better than you. Push yourself every day to meet their mark. And if you finish last, come back the next day and try again.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I'd rather be in last place among the lead pack than first place among the second-string.&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;tweetmeme_url = 'http://docondev.blogspot.com/2009/09/id-rather-be-in-last-place.html';&lt;/script&gt;&lt;br /&gt;&lt;script type="text/javascript" src="http://tweetmeme.com/i/scripts/button.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-2764745802464939067?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/2764745802464939067/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2009/09/id-rather-be-in-last-place.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/2764745802464939067'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/2764745802464939067'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2009/09/id-rather-be-in-last-place.html' title='I&apos;d rather be in last place'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-7840161027298278656</id><published>2009-09-25T15:07:00.002-04:00</published><updated>2009-10-01T08:25:10.267-04:00</updated><title type='text'>Running Developers Unite!</title><content type='html'>&lt;b&gt;Update&lt;/b&gt;:&lt;br /&gt;I started a group on &lt;a href="http://www.dailymile.com/groups/595-test-code-run"&gt;Daily Mile&lt;/a&gt;. Make sure to sign up!&lt;br /&gt;&lt;br /&gt;This is a quick post to get things started. I will get a more formal site up and running in due time.&lt;br /&gt;&lt;br /&gt;There are a lot of developers out there who run, have recently taken up running, or are thinking about it.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I thought it would be cool to get a group of running geeks together. Nothing too formal, just a "club" for us running developers. We can get events together like &lt;a href="http://chadfowler.com/2009/9/25/unofficial-rubyconf-5k"&gt;Chad Fowler's RuyConf 5k&lt;/a&gt;. We can share stories. And we can help to keep each other motivated and informed.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I am currently looking for a fitting name for the club.&lt;br /&gt;&lt;br /&gt;Leave a comment indicating your interest. If you have name suggestions, include them in the comment.&lt;br /&gt;&lt;br /&gt;Alternatively, you can send a message to michael [at] docondev.com with "Running Developer" in the title.&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;tweetmeme_url = 'http://docondev.blogspot.com/2009/09/running-developers-unite.html';&lt;/script&gt;&lt;br /&gt;&lt;script type="text/javascript" src="http://tweetmeme.com/i/scripts/button.js"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-7840161027298278656?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/7840161027298278656/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2009/09/running-developers-unite.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7840161027298278656'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7840161027298278656'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2009/09/running-developers-unite.html' title='Running Developers Unite!'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-7604222397860245102</id><published>2009-08-31T21:09:00.012-04:00</published><updated>2010-05-02T10:39:15.833-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Technical Debt'/><title type='text'>Messy Code is not Technical Debt</title><content type='html'>Technical Debt is a common topic these days. How is it incurred? How should we track it? When should we pay it down?&lt;br /&gt;&lt;br /&gt;It is a metaphor commonly understood. Our customers get it. While they may not like it, they do understand. Technical Debt is incurred today and needs to be paid down; preferably sooner rather than later what with compound interest and all that.&lt;br /&gt;&lt;br /&gt;Technical Debt is accepted by many as a natural part of the development process. Frankly, I agree. I think Technical Debt is a good thing to take on for short periods of time. Perhaps it is even unavoidable in some cases. Therefor we should expect it and deal with it accordingly.&lt;br /&gt;&lt;br /&gt;But there is something insidious going on here. In many cases, perhaps even most cases, what developers are really talking about is code that is not Clean.&lt;br /&gt;&lt;br /&gt;And Messy Code is not Technical Debt.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;What is Technical Debt?&lt;/h4&gt;&lt;br /&gt;Ward Cunningham coined the phrase &lt;a href="http://c2.com/doc/oopsla92.html"&gt;Technical Debt&lt;/a&gt;.&lt;br /&gt;&lt;blockquote&gt;"Shipping first time code is like going into debt. A little debt speeds development so long as it is paid back promptly with a rewrite. Objects make the cost of this transaction tolerable. The danger occurs when the debt is not repaid. Every minute spent on not-quite-right code counts as interest on that debt. Entire engineering organizations can be brought to a stand-still under the debt load of an unconsolidated implementation, object- oriented or otherwise."&lt;/blockquote&gt;&lt;object align="right" height="265" hspace="10" vspace="10" width="320"&gt;&lt;param name="movie" value="http://www.youtube.com/v/pqeJFYwnkjE&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/pqeJFYwnkjE&amp;hl=en&amp;fs=1&amp;rel=0&amp;color1=0x2b405b&amp;color2=0x6b8ab6" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="320" height="265" align="right" hspace="10" vspace="10"&gt;&lt;/embed&gt;&lt;/object&gt;As he clarifies later in a You-Tube video, Ward was specifically talking about design decisions made in the course of developing software that allowed for more rapid delivery. Rapid delivery not for the sake of meeting a deadline. Rapid delivery to illicit quick feedback, thereby providing the data necessary to adjust the design to be more congruent with actual needs. The object design should change to reflect your current understanding of the domain, even if that understanding is partial.  Technical debt is payed back through code refactoring as our understanding of the domain matures.&lt;br /&gt;&lt;br /&gt;Ward clearly states, "&lt;i&gt;The ability to pay back debt [...] depends upon you writing code that is clean enough to be able to refactor as you come to understand your problem.&lt;/i&gt;"&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Misunderstandings about Technical Debt&lt;br /&gt;&lt;/h4&gt;&lt;br /&gt;Ward's original description was vague. His clarification which later followed may have come too late. Many had already taken the phrase and added their own flavor to it.&amp;nbsp; &lt;a href="http://martinfowler.com/bliki/TechnicalDebt.html"&gt;Martin Fowler discusses Technical Debt&lt;/a&gt; and even refers to Ward's definitions, but then goes on to say "&lt;i&gt;doing things the quick and dirty way sets us up with technical debt&lt;/i&gt;". Jeff Atwood also allows the phrase "&lt;i&gt;quick and dirty&lt;/i&gt;" to creep into &lt;a href="http://www.codinghorror.com/blog/archives/001230.html"&gt;his explanation of Technical Debt&lt;/a&gt;. And in an &lt;a href="http://software.intel.com/en-us/blogs/2009/05/29/agile-best-practice-3-of-10-measure-and-frequently-repay-technical-debt/"&gt;Intel posting&lt;/a&gt;, the definition is expanded to:&lt;br /&gt;&lt;blockquote&gt;"Technical Debt is loosely defined as the volume of poorly written lines of code, poorly refactored, not following coding standards, not supported with sufficient unit tests, and the amount of code duplication."&lt;/blockquote&gt;This seems to be the common definition of Technical Debt today. And it is most unfortunate.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Messes are not Technical Debt&lt;br /&gt;&lt;/h4&gt;&lt;br /&gt;Poorly written code, lack of standards, lack of tests, code duplication, multiple responsibility, complex interfaces, large classes, poor/insufficient error handling, and opaque intent are all messes. Not a one of them is Technical Debt. And as such, none of them should be categorized as Technical Debt. For a comprehensive listing of messes, see &lt;a href="http://search.barnesandnoble.com/Clean-Code/Robert-C-Martin/e/9780132350884"&gt;Robert Martin's Clean Code&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Messes Preclude Technical Debt&lt;/h4&gt;&lt;br /&gt;Technical Debt is paid back through refactoring as our understanding of the domain matures. "&lt;i&gt;The ability to pay back debt [...] depends upon you writing code that is clean enough to be able to refactor as you come to understand your problem.&lt;/i&gt;"&lt;br /&gt;&lt;br /&gt;Clean Code is actually a prerequisite for Technical Debt. If you don't have Clean Code, you cannot expect to pay the debt back. If you have a mess, you cannot reasonably incur Technical Debt. In fact, you are not incurring debt, you are merely adding to the existing mess.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Messes are not Acceptable&lt;br /&gt;&lt;/h4&gt;&lt;br /&gt;&lt;a href="http://twitter.com/unclebobmartin/status/3111623316"&gt;Uncle Bob has stated&lt;/a&gt;, "There aren't any reasons to make a mess."&lt;br /&gt;&lt;br /&gt;I don't entirely agree with Bob on his point. I think there aren't any reasons to &lt;i&gt;leave&lt;/i&gt; a mess. TDD encourages us to take tiny steps. Some of these steps result in small messes. Messes that we will clean up in very short order. But we've made a mess nonetheless. And there is no shame in having done so. To leave the mess for any significant period of time or to allow more mess to accumulate is, however, unacceptable.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Stop calling messy code "Technical Debt"&lt;/h4&gt;&lt;br /&gt;Stop hiding behind the term Technical Debt. If you have messy code, clean it up. Implement the Boy Scout Rule and get it taken care of. &lt;br /&gt;&lt;br /&gt;Most important - don't treat the permeation of mess into your system as something natural and acceptable.&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;digg_bgcolor = '#558866';digg_skin = 'compact';digg_window = 'new';digg_title = 'Messy Code is not Technical Debt';digg_url = 'http://docondev.blogspot.com/2009/08/messy-code-is-not-technical-debt.html';digg_topic = 'Programming';&lt;/script&gt;&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-7604222397860245102?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/7604222397860245102/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2009/08/messy-code-is-not-technical-debt.html#comment-form' title='17 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7604222397860245102'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7604222397860245102'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2009/08/messy-code-is-not-technical-debt.html' title='Messy Code is not Technical Debt'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>17</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-3764183157360802029</id><published>2009-08-28T23:07:00.004-04:00</published><updated>2011-01-17T12:17:16.371-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Manager'/><category scheme='http://www.blogger.com/atom/ns#' term='Teams'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><title type='text'>Create a Culture of Integrity</title><content type='html'>My friend &lt;a href="http://patrickwilsonwelsh.com/"&gt;Patrick Wilson-Welsh&lt;/a&gt; once asked me if I knew the key distinction between Accountability and Integrity. I said I did, but then found myself struggling for an answer.&lt;br /&gt;&lt;br /&gt;Today, I think I get it. Perhaps I should check with Patrick.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Accountability and Integrity&lt;/h3&gt;&lt;h4&gt;Accountability&lt;/h4&gt;Accountability is enforced externally; it is a requirement or expectation to justify actions and decisions. A person can be accountable to or accountable for, but cannot be simply accountable. Accountability requires another party.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Integrity&lt;/h4&gt;Integrity is enforced from within; it is a quality of honesty and morality. It exists regardless of accountability. A person has integrity (or does not). Integrity does not require another party.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;A key difference&lt;/h4&gt;Accountability is flawed. There are numerous issues, from the "it's not wrong if I don't get caught" mentality to the "that is how the boss wants it done" escape clause. Accountability can be unreliable. If expectations are not clear, if the boss is away, if people feel dis-empowered (which is likely), or if people "suck up" to the boss, the outcome may not be what is desired or expected. As a result, morale can deteriorate and lead to more issues. Ultimately, accountability of subordinate to superior creates an environment of distrust and dysfunction; this cannot scale.&lt;br /&gt;&lt;br /&gt;Integrity does not require external enforcement. Integrity does not have escape clauses. Integrity is consistent. Integrity cannot be "sucked up" to. Integrity is reliable. And integrity scales.&lt;br /&gt;&lt;br /&gt;Some will argue that integrity is adherence to a moral and ethical standard, but is independent of the nature of that standard. This is true. Integrity in not synonymous with morality, rather it is one's ability to be true to their own morality. This makes integrity no less desirable.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Creating a culture of integrity&lt;/h3&gt;So how do we create a culture of integrity?&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Have integrity&lt;/h4&gt;Leadership sets the tone. Hypocrisy will not beget integrity. If you make promises, but don't keep them; If you expect full disclosure, but hold back data; If you promote autonomy, but punish "mistakes"; If you preach teamwork, but practice espionage; you had best expect to be surrounded by people adept at surviving in such an environment.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Hire better&lt;/h4&gt;It is quite likely you are hiring based on the wrong criterion. Typically, candidates are first filtered based on credentials and experience. Do they have the requisite degree/certification? Have they used our target tools for the requisite length of time? Then, they are interviewed to certify the proclaimed credentials and experience. Finally, in more progressive environments, the preferred candidate meets the team to make sure there is good chemistry; a quick check to ensure nobody resorts to fisticuffs.&lt;br /&gt;&lt;br /&gt;Invert the selection process. Don't hire based on experience and credentials. Hire based on aptitude and attitude. Aptitude - can they learn what you need them to know? Attitude - are they a fit for your team and your company? Put the time and effort into making sure the candidate is capable of learning, willing to learn, and has values that fit for your organization. If they have the pedigree too - Hey, that's swell.&lt;br /&gt;&lt;br /&gt;Why invert the process? Smart people easily learn new skills. Selfish people don't easily develop empathy.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Communicate expectations&lt;br /&gt;&lt;/h4&gt;Produce a values statement. Publish it. Share it. Use it in the selection process.&lt;br /&gt;&lt;br /&gt;Develop a code of conduct. What is expected of employees in and out of work? Keep it general. Trust your employees to apply the guidelines rather than providing a tome of situational requirements.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Model specific behavior&lt;/h4&gt;We've covered that you should have integrity, which is paramount. Modeling the specifically desired behaviors reinforces the expectations and encourages voluntary adherence. If team members perceive a lack of integrity in leadership or among their peers, they are less likely to exhibit integrity themselves. This is not to say they will lack integrity, but they may not openly show it. An environment of deception encourages the righteous to be cautious.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Integrity Endures&lt;/h3&gt;Accountability works, but it is ultimately the coercion of good behavior through fear of repercussion, no matter how gentle. If you want success that endures; create a culture of integrity.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-3764183157360802029?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/3764183157360802029/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2009/08/create-culture-of-integrity.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/3764183157360802029'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/3764183157360802029'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2009/08/create-culture-of-integrity.html' title='Create a Culture of Integrity'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-3654383899237608861</id><published>2009-08-28T15:32:00.008-04:00</published><updated>2009-09-03T10:04:21.682-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='How To'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Retrospectives'/><title type='text'>Keep Retrospectives Fresh</title><content type='html'>Retrospectives are an important (and frequently poorly done) practice. They provide an opportunity for discussion, learning, and adaptation. Without retrospectives, a team is likely to fall into a soothing rhythm and fail to recognize early the need for change.&lt;br /&gt;&lt;br /&gt;But retrospectives themselves can become common and numbing. The same moderator, the same three questions, in the same room, at the same time .... (yawn).&lt;br /&gt;&lt;br /&gt;Here are a few tips on keeping your retrospectives fresh.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Change Venues and Schedule&lt;/span&gt;&lt;br /&gt;Hold iterations in different rooms. Move them to the afternoon before or the morning after their regularly scheduled time. You'll get a different energy and perhaps a different perspective.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Change Moderators&lt;/span&gt;&lt;br /&gt;Not only can changing the moderator change the pace and style of the discussion, but it can change the way people communicate. Allow each team member who is interested the opportunity to moderate retrospectives.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Change Styles&lt;/span&gt;&lt;br /&gt;We're all familiar with the standard three-question, moderator as scribe format for retrospectives. Mix it up. Use the &lt;a href="http://www.thekua.com/rant/2006/03/the-retrospective-starfish/"&gt;starfish&lt;/a&gt; or &lt;a href="http://www.stevenlist.com/blog/2009/02/15/circle-of-questions/"&gt;circle of questions&lt;/a&gt;. Have people write their own suggestions on index cards, have a third-party collect them and write them on the board. Find new ways of soliciting input and you will get new input.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Change Focus&lt;/span&gt;&lt;br /&gt;Hold retrospectives with a broader focus. Rather than discussing the last iteration and the next iteration, discuss the last several weeks or months and the next few months. Allow the team to not only discuss the tactical, but the strategic. With a new focus comes new perspective and new insight.&lt;br /&gt;&lt;br /&gt;Retrospectives are about learning and adapting. They are critical to the long-term success of an Agile team. If you're not doing them; start now. If you are, make sure you keep them fresh to get maximum value from them.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;script type="text/javascript"&gt;digg_bgcolor = '#558866';digg_skin = 'compact';digg_window = 'new';digg_title = 'Keep Retrospectives Fresh';digg_url = 'http://docondev.blogspot.com/2009/08/keep-retrospectives-fresh.html';digg_topic = 'Programming';&lt;/script&gt;&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-3654383899237608861?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/3654383899237608861/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2009/08/keep-retrospectives-fresh.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/3654383899237608861'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/3654383899237608861'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2009/08/keep-retrospectives-fresh.html' title='Keep Retrospectives Fresh'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-6847989690588919420</id><published>2009-06-26T17:21:00.003-04:00</published><updated>2009-06-26T18:00:50.970-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Metrics'/><title type='text'>Visible Metrics with Corey Haines</title><content type='html'>&lt;script type="text/javascript"&gt;digg_bgcolor = '#558866';digg_skin = 'compact';digg_window = 'new';digg_title = 'Visible Metrics with Corey Haines';digg_url = 'http://docondev.blogspot.com/2009/06/visible-metrics-with-corey-haines.html';digg_topic = 'Programming';&lt;/script&gt;&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;We've been discussing Metrics in the Software Craftsmanship Group and I just posted some notes on the topic yesterday. Today, I had an opportunity to watch Corey's "Road Thoughts" on Visible Metrics.&lt;br /&gt;&lt;br /&gt;&lt;object width="400" height="300"&gt;&lt;param name="allowfullscreen" value="true"&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;param name="movie" value="http://vimeo.com/moogaloop.swf?clip_id=5334658&amp;amp;server=vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=00ADEF&amp;amp;fullscreen=1"&gt;&lt;embed src="http://vimeo.com/moogaloop.swf?clip_id=5334658&amp;amp;server=vimeo.com&amp;amp;show_title=1&amp;amp;show_byline=1&amp;amp;show_portrait=0&amp;amp;color=00ADEF&amp;amp;fullscreen=1" type="application/x-shockwave-flash" allowfullscreen="true" allowscriptaccess="always" width="400" height="300"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;p&gt;&lt;a href="http://vimeo.com/5334658"&gt;Road Thoughts - Visible Metrics&lt;/a&gt; from &lt;a href="http://vimeo.com/coreyhaines"&gt;Corey Haines&lt;/a&gt; on &lt;a href="http://vimeo.com/"&gt;Vimeo&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;And I like where Corey is headed with this. The measurements discussed are related to code quality. They apply to a code base written by one or by a team of hundreds. These metrics can and should be used for good. Developers can monitor their improvement or ensure their quality does not slide.&lt;br /&gt;&lt;br /&gt;Corey takes this concept to a new level; comparative metrics. Metrics that are gathered about your code base, but are devoid of any specific intellectual property. These metrics are then shared, perhaps publicly or perhaps anonymously, for collective comparison. So not only can you then monitor your own quality, but you can compare against others. How do you mark against the industry as a whole? How do you mark against companies of similar size in your regional location? How do you compare against individuals around the world in your language of choice?&lt;br /&gt;&lt;br /&gt;With courage, what can we as a community do to help each other learn and grow?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-6847989690588919420?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/6847989690588919420/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2009/06/visible-metrics-with-corey-haines.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/6847989690588919420'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/6847989690588919420'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2009/06/visible-metrics-with-corey-haines.html' title='Visible Metrics with Corey Haines'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-75465963954468284</id><published>2009-06-25T20:43:00.006-04:00</published><updated>2009-06-25T22:41:05.485-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><category scheme='http://www.blogger.com/atom/ns#' term='Metrics'/><title type='text'>Metrics in Software Development</title><content type='html'>&lt;script type="text/javascript"&gt;digg_bgcolor = '#558866';digg_skin = 'compact';digg_window = 'new';digg_title = 'Metrics in Software Development';digg_url = 'http://docondev.blogspot.com/2009/06/metrics-in-software-development.html';digg_topic = 'Programming';&lt;/script&gt;&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Today I posted an entry on the Google Software Craftsmanship Board. In the posting, I asked if anyone had experience with individual velocity metrics on an Agile project. I posted a similar (but more brief) inquiry on Twitter as well.&lt;br /&gt;&lt;br /&gt;The responses were varied and the discussion was good. But I was a bit surprised by the overall quality of the responses.&lt;br /&gt;&lt;br /&gt;First of all, I had to rephrase the question more than once before anyone answered it. I received many vague and prescriptive responses stating it should not be done. But most folks never indicated if they had personal experience with it. "That's not the agile way" seemed to be a satisfactory argument. No additional support required.&lt;br /&gt;&lt;br /&gt;Only one respondent directly stated they had experience with using individual velocity metrics. They also described a disastrous outcome; a complete breakdown of trust, quality, and throughput. All of which, were attributed to the collection of a single data point. Seems to me a project that crashes and burns that hard has issues beyond collection of a metric. Perhaps the collection (or use) of the metric was an indicator of a greater problem, but I doubt it was THE problem. In other words, the team was likely to suffer the same fate whether or not personal velocity data was gathered. More likely, the motivation behind the collection and use of the data was the real issue.&lt;br /&gt;&lt;br /&gt;As the discussion progressed, there seemed to be a dangerous general consensus; metrics that apply to individuals are bad and metrics that apply to groups are good. While the discussion started with velocity, it took a winding path through all forms of data points; code coverage, cyclomatic complexity, estimation accuracy, etc. The danger here is the generalization of good and bad based on individual or group respectively.&lt;br /&gt;&lt;br /&gt;Good points were also made. Many spoke of the need to understand the purpose of the metric. As one individual put it:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;(1) you need to be aware of what question you are asking and what situation you are trying to change; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt; (2) you need to understand what the relationship between a given metric and a given property is; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt; (3) you need to [be] clear under what circumstances the metric will cease to be relevant. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Anthony Broad-Crawford said it very well:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;As a manager myself the primary goal of metrics is to simply create a "check engine light".  Meaning, when the light comes on, it doesn't necessarily mean anything is wrong.  What it means, is you should "pop open the hood" and start asking some questions to figure out if something really is in fact wrong.  For example, if you did track individual velocity metrics, and someone did report a very low number for the iteration, a check engine light should come on.  It doesn't mean the developer did anything wrong or sub-par.  It could be for any number of good things (pair programming, design sessions, training, etc).  However, if a goose egg is thrown, and they didn't participate in anything that would account for the goose egg (extensive pairing, design sessions, training, etc) something may be wrong and you as the manager should find out.&lt;/span&gt;&lt;div style="font-style: italic;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-style: italic;"&gt;I do agree if management simply looks at the spreadsheet and makes assumptions (good or bad) based on some threshold it will be problematic.  Metrics, must like everything else, are not black and white.  A good manager (IMO) will realize that metrics are shades of gray and act accordingly.&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;The discussion was primarily about the need for individual velocity metrics. And the general consensus (on Google and on twitter) was that individual metrics are bad while group metrics are good.&lt;br /&gt;&lt;br /&gt;But metrics, whether individual or collective, can be used for good or evil. They can result in improved or hindered performance. They can tell a valuable story or they can completely mislead.&lt;/div&gt;  &lt;div&gt; &lt;/div&gt; &lt;div&gt;To categorically dismiss all metrics related to individuals is almost as dangerous as categorically accepting all metrics that apply to groups.&lt;/div&gt; &lt;div&gt; &lt;/div&gt; &lt;div&gt;We need to recognize that metrics without a clear and expressed purpose are noise at best and are quite likely dangerous. And the metrics are merely indicators; they don't tell the complete story. I like the "check engine light" analogy. Metrics let you know that you need to look into it further.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-75465963954468284?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/75465963954468284/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2009/06/metrics-in-software-development.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/75465963954468284'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/75465963954468284'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2009/06/metrics-in-software-development.html' title='Metrics in Software Development'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-8409417121879987644</id><published>2009-05-25T09:28:00.006-04:00</published><updated>2009-05-25T10:39:23.033-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby on Rails'/><title type='text'>Altering your Session Key in Rails 2.3</title><content type='html'>I am working on a 'toy' application that I started a couple of Rails releases ago. When I ran my test suite, I received the following warning:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:arial;"&gt;DEPRECATION WARNING: Disabling sessions for a single controller has been deprecated. Sessions are now lazy loaded. So if you don't access them, consider them off. You can still modify the session cookie options with request.session_options.. (called from /Users/docondev/[...]/app/controllers/application_controller.rb:9)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The line in question follows:&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;session :session_key =&gt; '_docondev_session_id' &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I learned this technique from several RoR books written only a couple of years ago, but there is a better way to alter the session key.&lt;br /&gt;&lt;br /&gt;Although I could have altered the line in application_controller.rb, I decided to put the settings in a more appropriate location. I removed the line from the application-controller entirely. I then altered the config/initializers/session_store.rb file.&lt;br /&gt;&lt;br /&gt;The changes should be fairly obvious, but note that :session_key and been changed to :key. I alter the secret by replacing the end of the string with my application name. This is really not necessary, but it is a habit I've established, it does no harm, and it keeps my key and secret visually coupled.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;ActionController::Base.session = {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;  :key         =&gt; '_docondev_store_session',&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;  :secret      =&gt; '005000374cbcd1[...]docondev'&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;}&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-8409417121879987644?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/8409417121879987644/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2009/05/altering-your-session-key-in-rails-23.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/8409417121879987644'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/8409417121879987644'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2009/05/altering-your-session-key-in-rails-23.html' title='Altering your Session Key in Rails 2.3'/><author><name>DocOnDev</name><uri>http://www.blogger.com/profile/17064897772691908215</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://4.bp.blogspot.com/_9BSWFzzwekI/Soss0c95XgI/AAAAAAAAAAM/wN6wSY9qcaQ/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-1123408027031918949</id><published>2009-04-15T19:38:00.003-04:00</published><updated>2009-04-15T20:42:21.058-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><title type='text'>I disagree with Uncle Bob on this one</title><content type='html'>I am reading &lt;a href="http://search.barnesandnoble.com/Clean-Code/Robert-C-Martin/e/9780132350884"&gt;Bob Martin's "Clean Code - A handbook of Agile Software Craftsmanship"&lt;/a&gt; again. For the most part, I am really digging it. It reminds me a bit of &lt;a href="http://search.barnesandnoble.com/Code-Complete/Steve-McConnell/e/9780735619678/?itm=1"&gt;Steve McConnell's Code Complete&lt;/a&gt;. I still have the original version of McConnell's book around here somewhere. But I digress (and show my age).&lt;br /&gt;&lt;br /&gt;In Chapter 9, Martin covers unit tests. In listings 9-3 and 9-4, Martin shows the "simplification" of a unit test. Listing 9-3 makes two method calls followed by five assertions. Each assertion checks a specific state. Each state is clearly identified. I do not particularly like the five assertions. But this is not the point that Bob makes. This is not the correction he covers. Instead, he condenses all five assertions into a single assertion by introducing a string of seemingly arbitrary characters.&lt;br /&gt;&lt;br /&gt;We go from:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    assertTrue(hw.heaterState()); &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    assertTrue(hw.blowerState()); &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    assertFalse(hw.coolerState()); &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    assertFalse(hw.hiTempAlarm()); &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    assertTrue(hw.loTempAlarm()); &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;To:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    assertEquals("HBchL", hw.getState());&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;He goes on to explain that each character in our string represents a possible state; Capital is true, Lower is false. He follows up with, "Notice, once you know the meaning, your eyes glide across that string and you can quickly interpret the results. Reading the test becomes almost a pleasure."&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;WHAT?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;"Once you know the meaning"? This is not from a solution domain. This is not from the problem domain. This removes clarity under the guise of improved readability. How, pray tell, am I to know the meaning? Is there a comment in the code to explain the meaning? Is he really suggesting that a blatant code smell is better than methods that clearly indicate the intended behavior? And what happens when getState needs to also return the humidifier State? How much code breaks? I should be able to introduce a new behavior without these issues.&lt;br /&gt;&lt;br /&gt;I have to disagree with Uncle Bob on this one. This is NOT a better solution. It does NOT make the code more readable. I am suprised to see this recommendation and I bet it does not appear in the Second Edition.&lt;br /&gt;&lt;br /&gt;Break each assertion out into their own test within the class, put them all into their own test class with a shared setup and tear-down, or use a Template Method pattern. Frankly, you could just leave them all in a single test given they all test the same single concept. But this string of place-holders with case representing on or off state is a fart in a garden of beautiful code. It just smells bad.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-1123408027031918949?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/1123408027031918949/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2009/04/i-disagree-with-uncle-bob-on-this-one.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/1123408027031918949'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/1123408027031918949'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2009/04/i-disagree-with-uncle-bob-on-this-one.html' title='I disagree with Uncle Bob on this one'/><author><name>DocLogic</name><uri>http://www.blogger.com/profile/09149149882666714621</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://3.bp.blogspot.com/_rTMzO9gHrhM/Sd0iXzZQY8I/AAAAAAAAABE/OpHqxzM9EN4/S220/Profile_Picture.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-3831827829525163076</id><published>2009-04-11T18:36:00.003-04:00</published><updated>2009-04-11T19:21:13.458-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby on Rails'/><category scheme='http://www.blogger.com/atom/ns#' term='How To'/><title type='text'>Ruby on Rails - Basic Authentication</title><content type='html'>In this post, we are going to cover a very simple way to implement authentication in your application. This is not an appropriate technique for securing a commercial application in production. I use this technique to quickly "secure" an application while in User Acceptance. It allows me to put the application out on the internet and give it a single user name and password. This technique can also be used for easy REST authentication.&lt;br /&gt;&lt;br /&gt;Let's assume your intention is to secure the entire application. Add the following to your application controller:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class AdminController &lt; ApplicationController&lt;br /&gt; before_filter :authenticate&lt;br /&gt;&lt;br /&gt;private&lt;br /&gt; def authenticate&lt;br /&gt;   authenticate_or_request_with_http_basic do |username, password|&lt;br /&gt;     username == 'UserName' &amp;amp;&amp;amp; password == 'SecretPassword'&lt;br /&gt;   end&lt;br /&gt; end&lt;br /&gt;end  &lt;/pre&gt;&lt;br /&gt;This will "secure" the entire application under a single account.&lt;br /&gt;&lt;br /&gt;If you prefer not to put the plain-text password in the source, you can instead use the following:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;require 'digest'&lt;br /&gt;&lt;br /&gt;class AdminController &lt; ApplicationController&lt;br /&gt; before_filter :authenticate&lt;br /&gt;&lt;br /&gt;private&lt;br /&gt; def authenticate&lt;br /&gt;   authenticate_or_request_with_http_basic do |username, password|&lt;br /&gt;     encrypted_password = Digest::MD5.hexdigest(password)&lt;br /&gt;     username == 'UserName' &amp;amp;&amp;amp; encrypted_password == '58d613129c5e71de57ee3f44c5ce16bc'&lt;br /&gt;   end&lt;br /&gt; end&lt;br /&gt;end  &lt;/pre&gt;I used http://www.miraclesalad.com/webtools/md5.php to generate the hash&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-3831827829525163076?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/3831827829525163076/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2009/04/ruby-on-rails-basic-authentication.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/3831827829525163076'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/3831827829525163076'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2009/04/ruby-on-rails-basic-authentication.html' title='Ruby on Rails - Basic Authentication'/><author><name>DocLogic</name><uri>http://www.blogger.com/profile/09149149882666714621</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://3.bp.blogspot.com/_rTMzO9gHrhM/Sd0iXzZQY8I/AAAAAAAAABE/OpHqxzM9EN4/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-5996252444667786272</id><published>2009-04-09T15:23:00.004-04:00</published><updated>2009-04-11T19:22:40.431-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><title type='text'>10x Difference in Software Developers</title><content type='html'>I finished reading Uncle Bob's posting on &lt;a href="http://blog.objectmentor.com/articles/2009/04/01/master-craftsman-teams"&gt;Master Craftsman Teams&lt;/a&gt; and in the comments was a link to Steve McConnell on &lt;a href="http://forums.construx.com/blogs/stevemcc/archive/2008/03/31/chief-programmer-team-update.aspx"&gt;10x differences in software developers&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I encourage you to read both articles along with the comments attached to each.&lt;br /&gt;&lt;br /&gt;In McConnell's article was a paragraph that made me stop and think for a bit:&lt;br /&gt;&lt;br /&gt;"Another factor is that, while numerous studies have found 10x differences among individuals, researchers have &lt;em&gt;not &lt;/em&gt;found 10-fold differences among programmers &lt;em&gt;working within the same organizations&lt;/em&gt;. Some research has found that good programmers tend to cluster within certain companies, average programmers tend to cluster within other companies, and so on (Mills 1983). So even if there’s a 10x difference industrywide, the difference you’d typically see within a given company is more like 3-5x from best to worst, which means the difference from &lt;em&gt;best to average&lt;/em&gt; is more like 1.5x or 2x within any given company."&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;So which company am I in and with whom have I clustered? What about you?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;I can say with certainty that I've spent some time at the bottom of the scale. Rallying against not only the organization as a whole, but against the fear and apathy of my own team. Clustered they had. And they settled in an environment that supported them. I posit to you - should you ever find yourself in this situation, it is far easier to change your circumstance that it is to change an organization. I should have left far sooner than I did.&lt;br /&gt;&lt;br /&gt;Today, I find myself surrounded by wonderful, talented, people. I suspect I pull down the multiplier, but I aspire to be one of them. And the best way I know to improve yourself is to surround yourself with people who are much better than you. People who can push you, challenge you, and teach you. It worked for me as a musician. It worked for me as a runner. I am certain it will work for me as a software developer.&lt;br /&gt;&lt;br /&gt;Look around. What end of the multiplier do you think you are on in your current organization? And are you clustered with the top, middle, or bottom of the scale?&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Is that where you want to be...?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8528631747209969303-5996252444667786272?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/5996252444667786272/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2009/04/10x-difference-in-software-developers.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/5996252444667786272'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/5996252444667786272'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2009/04/10x-difference-in-software-developers.html' title='10x Difference in Software Developers'/><author><name>DocLogic</name><uri>http://www.blogger.com/profile/09149149882666714621</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://3.bp.blogspot.com/_rTMzO9gHrhM/Sd0iXzZQY8I/AAAAAAAAABE/OpHqxzM9EN4/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-6322135726876043517</id><published>2009-03-20T18:05:00.002-04:00</published><updated>2009-03-20T18:09:47.691-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Rant'/><title type='text'>Values</title><content type='html'>&lt;span class="Apple-style-span"  style="font-family:'trebuchet ms';"&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'trebuchet ms';"&gt;&lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Our Values...&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;... are the foundation for all decisions. They serve as the compass that guides us through our personal and professional lives. All action; all thought; in every way we represent ourselves; we must represent our values.&lt;div&gt;&lt;br /&gt;&lt;span class="Apple-style-span"  style="font-family:'trebuchet ms';"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Be fair.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Find the answer that best serves all parties. Act upon your highest sense of right.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;span class="Apple-style-span"  style="font-family:'trebuchet ms';"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Improve.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Grow continuously, personally and professionally, in small ways. Evolution is the sum of many tiny, nearly indiscernible adjustments.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'trebuchet ms';"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Innovate.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Seek new ways; seek new means; do the unexpected.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'trebuchet ms';"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Take Initiative.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Present your ideas. Put forth the extra effort. The one who make the most mistakes, learns the most lessons.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'trebuchet ms';"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Be accountable.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Answer for your mistakes and your deserved praise will come.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'trebuchet ms';"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Be forgiving.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Seek to understand and assist. Do not condemn others for their differences. To criticize and dismiss leaves neither party better off.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'trebuchet ms';"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Participate.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Become truly involved. Make this your team, for it already is.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'trebuchet ms';"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Have respect.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Honor your coworkers and clients.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'trebuchet ms';"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Live.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Make your life rich in many ways. Seek new experiences, new relationships, and a new perspective. Then bring it back and teach others.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'trebuchet ms';"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;And always, Tell The Truth.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: right;"&gt;&lt;span class="Apple-style-span" style="color: rgb(153, 153, 153);"&gt;- Michael J. Norton (1997)&lt;/span&gt;&lt;br /&gt;&lt;/div&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/8528631747209969303-6322135726876043517?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/6322135726876043517/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2009/03/values.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/6322135726876043517'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/6322135726876043517'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2009/03/values.html' title='Values'/><author><name>DocLogic</name><uri>http://www.blogger.com/profile/09149149882666714621</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://3.bp.blogspot.com/_rTMzO9gHrhM/Sd0iXzZQY8I/AAAAAAAAABE/OpHqxzM9EN4/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-3097399117769143669</id><published>2009-03-15T09:51:00.012-04:00</published><updated>2009-03-16T09:00:18.740-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Event'/><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><title type='text'>Code Retreat #2</title><content type='html'>&lt;script type="text/javascript"&gt;digg_bgcolor = '#558866';digg_skin = 'compact';digg_window = 'new';digg_title = 'Code Retreat Number 2';digg_url = 'http://docondev.blogspot.com/2009/03/code-retreat-2.html';digg_topic = 'Programming';&lt;/script&gt;&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;Yesterday was the second &lt;a href="http://coderetreat.ning.com/"&gt;Code Retreat&lt;/a&gt;. Thanks to &lt;a href="http://www.leandog.com/"&gt;LeanDog&lt;/a&gt; for the use of their facilities. We didn't quite hit 40 in attendance, but we came close. With participants like &lt;a href="http://juddsolutions.blogspot.com/"&gt;Chris Judd&lt;/a&gt;, James Shingler, &lt;a href="http://programmingtour.blogspot.com/"&gt;Corey Haines&lt;/a&gt; and &lt;a href="http://www.jbrains.ca/"&gt;J.B. Rainsberger&lt;/a&gt;, we had some real ninjas present. I had the fortune to pair with Corey and J.B. as well as several others. All of the pairing experiences were fantastic. I learned something new with each iteration of the kata. I couldn't have asked for more.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The format was pretty simple. We paired (or tripled) for 40 minutes with 10 minute breaks. Using TDD and &lt;a href="http://www.stickyminds.com/sitewide.asp?Function=edetail&amp;amp;ObjectType=COL&amp;amp;ObjectId=9101"&gt;ping-pong&lt;/a&gt; or carousel, we attempted to create a program for &lt;a href="http://en.wikipedia.org/wiki/Conway's_Game_of_Life"&gt;Conway's Game of Life.&lt;/a&gt; At the end of each 40 minute session, we threw away the code, changed partners, and started all over again.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For many, this sounds like an exercise in torture. It is nearly impossible to write a solution for Conway's Game of Life in under 40 minutes. So how did we expect to achieve anything for the day?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I came to genuinely understand the purpose of the day early into the second round. I was in a triple the first round and we'd made it pretty far. We were satisfied with our approach and were confident we were on the right track. One of our members swapped out, so I was in a pair with a gentleman I had already completed a round with. Dumping the code was painful. All that progress lost. We decided to quickly rebuild what we'd previously developed and move forward with our solution. While he was writing a test, Corey Haines joined our team. I was explaining our approach to Corey. He remarked how different it was from the approach his prior team had taken. We were coding as we spoke. Before we knew it, we'd taken yet another approach to the problem. One neither of us had previously considered.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This was the purpose of the day. We weren't there to use Java. We weren't there to practice a few agile techniques. We certainly weren't there to write the Game of Life. We were there to &lt;a href="http://en.wikipedia.org/wiki/The_Seven_Habits_of_Highly_Effective_People"&gt;sharpen the saw&lt;/a&gt;. To share. To learn. To grow. This was everything about the journey and nothing about the destination.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;There was no right approach. There was no wrong approach. There was only approach. Working together, sharing ideas, joking, and honing our skills.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;You may not be comfortable with Java (or Ruby or C# or ... ). You may not know much about TDD. You may have never paired before. None of these things matter. If you are a professional developer who understands that what you do transcends a language or tool set, then Code Retreat is certainly for you. Wether you are new to the profession or have 30+ years of code behind you, there is something to be gained from sharing with others.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you knew about this one and didn't make it, you missed a fantastic moment. Be sure to make the next one.&lt;/div&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/8528631747209969303-3097399117769143669?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/3097399117769143669/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2009/03/code-retreat-2.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/3097399117769143669'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/3097399117769143669'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2009/03/code-retreat-2.html' title='Code Retreat #2'/><author><name>DocLogic</name><uri>http://www.blogger.com/profile/09149149882666714621</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://3.bp.blogspot.com/_rTMzO9gHrhM/Sd0iXzZQY8I/AAAAAAAAABE/OpHqxzM9EN4/S220/Profile_Picture.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-7105483929509696874</id><published>2009-03-08T10:11:00.007-04:00</published><updated>2009-03-15T14:01:08.697-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Mac'/><category scheme='http://www.blogger.com/atom/ns#' term='git'/><category scheme='http://www.blogger.com/atom/ns#' term='How To'/><category scheme='http://www.blogger.com/atom/ns#' term='Source Control'/><title type='text'>Installing git on a Mac</title><content type='html'>&lt;script type="text/javascript"&gt;digg_bgcolor = '#558866';digg_skin = 'compact';digg_window = 'new';digg_title = 'Installing git on a Mac';digg_url = 'http://docondev.blogspot.com/2009/03/installing-git-on-mac.html';digg_topic = 'Programming';&lt;/script&gt;&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;br /&gt;&lt;br /&gt;I've seen a lot of posts on bulletin boards and other sites regarding the install of git on a Mac. It appears many people have tried to download the source and compile it only to discover missing dependencies and other annoying issues.&lt;br /&gt;&lt;br /&gt;I did the following and was up and running in 5 minutes.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;&lt;span class="Apple-style-span"  style="font-family:'trebuchet ms';"&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Install MacPorts&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;If you have MacPorts installed, you just need to update it.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The full details for installation of MacPorts are available on their site.&lt;/div&gt;&lt;div&gt;http://www.macports.org/install.php&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;span class="Apple-style-span"  style="font-family:'trebuchet ms';"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Confirm Latest Update of MacPorts&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;sudo port selfupdate&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span"  style="font-family:'trebuchet ms';"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;Install git&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;sudo port install git-core [+svn]&lt;/span&gt;&lt;br /&gt;Use the optional +svn parameter if you will want to import from svn&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The  git install may take some time. There are a number of dependencies that need to be installed as well, but MacPorts takes care of it all for you.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;That's it.&lt;br /&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/8528631747209969303-7105483929509696874?l=www.docondev.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.docondev.com/feeds/7105483929509696874/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.docondev.com/2009/03/installing-git-on-mac.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7105483929509696874'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8528631747209969303/posts/default/7105483929509696874'/><link rel='alternate' type='text/html' href='http://www.docondev.com/2009/03/installing-git-on-mac.html' title='Installing git on a Mac'/><author><name>DocLogic</name><uri>http://www.blogger.com/profile/09149149882666714621</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://3.bp.blogspot.com/_rTMzO9gHrhM/Sd0iXzZQY8I/AAAAAAAAABE/OpHqxzM9EN4/S220/Profile_Picture.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8528631747209969303.post-3360487627074665295</id><published>2009-02-24T10:50:00.005-05:00</published><updated>2009-02-27T17:41:25.737-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='javascript'/><category scheme='http://www.blogger.com/atom/ns#' term='Development'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming Practices'/><title type='text'>javascript object helper</title><content type='html'>&lt;script type="text/javascript"&gt;digg_bgcolor = '#558866';digg_skin = 'compact';digg_window = 'new';digg_title = 'javascript object helper';digg_url = 'http://docondev.blogspot.com/2009/02/javascript-object-helper.html';digg_topic = 'Programming';&lt;/script&gt;&lt;script src="http://digg.com/tools/diggthis.js" type="text/javascript"&gt;&lt;/script&gt;&lt;br /&gt;I've been working in Javascript quite a bit lately. This seems to be a recurring theme in my development career going back to 199x. As I always looked at javascript as a pseudo-language used to manipulate browser characteristics, I hadn't really taken a good look at it.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Recently, I found I was using a lot of the same code over and over again between pages. Good old copy/paste/molest style of coding. Ugh. And at first I though, "I should write procedures for this".&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;PROCEDURES?!? Isn't javascript object oriented? Some would argue that it is not. But it sure can act like it is. There are no classes, but there are objects with properties and methods. It supports encapsulation and aggregation. And it supports inheritance. There are a number of different ways of achieving inheritance. I am not going to go into all of them in this posting. What I know, I learned from the &lt;a href="http://crockford.com/javascript"&gt;Master&lt;/a&gt; anyway.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I decided to create an object that would encapsulate my common object manipulations; create a new instance of an existing object, extend an objects properties, and create a new object through multiple inheritance. With these three simple tools, I can accomplish quite a bit.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The following is the code as of this writing:&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;var objectHelper = {&lt;br /&gt;  clone: function (originalObject) {&lt;br /&gt;      var returnObject;&lt;br /&gt;      function interstitial() {};&lt;br /&gt;      interstitial.prototype = originalObject;&lt;br /&gt;      returnObject = new interstitial();&lt;br /&gt;      returnObject.uber = originalObject;&lt;br /&gt;&lt;br /&gt;      return returnObject;&lt;br /&gt;  },&lt;br /&gt;&lt;br /&gt;  extend: function (originalObject, newProperties) {&lt;br /&gt;      var returnObject = this.clone( originalObject );&lt;br /&gt;      for ( var prop in newProperties ) {&lt;br /&gt;          returnObject[prop] = newProperties[prop];&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      return returnObject;&lt;br /&gt;  },&lt;br /&gt;&lt;br /&gt;  assemble: function(objectHash) {&lt;br /&gt;      var returnObject = {};&lt;br /&gt;      for ( var obj in objectHash ) {&lt;br /&gt;          returnObject[obj] = this.clone(objectHash[obj]);&lt;br /&gt;      };&lt;br /&gt;      return returnObject;&lt;br /&gt;  }&lt;br /&gt;};&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;
