<?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-8696186</id><updated>2011-11-29T19:40:29.315-04:00</updated><category term='code style'/><category term='python swig c threads'/><category term='visual studio assemblies 2008 manifest debug mfc c++ runtime'/><category term='programming'/><title type='text'>SandyWalsh.com</title><subtitle type='html'>An ounce of perception. A pound of obscure.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>33</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8696186.post-4217593103993929024</id><published>2011-11-08T11:28:00.002-04:00</published><updated>2011-11-08T11:28:51.774-04:00</updated><title type='text'>Python Halifax!</title><content type='html'>A one-day Python gathering here in Halifax? Say it ain't so?!&lt;br /&gt;&lt;br /&gt;It's true ... register now!&lt;br /&gt;&lt;br /&gt;&lt;a href="http://pythonhalifax.org/"&gt;http://pythonhalifax.org/&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8696186-4217593103993929024?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/4217593103993929024/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=4217593103993929024' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/4217593103993929024'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/4217593103993929024'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2011/11/python-halifax.html' title='Python Halifax!'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-5904795609663683261</id><published>2011-08-30T22:44:00.000-03:00</published><updated>2011-08-30T22:44:49.981-03:00</updated><title type='text'>The Pain of Unit Tests and Dynamically Typed Languages</title><content type='html'>&lt;br /&gt;&lt;div style="margin-bottom: 0in;"&gt;Don't get me wrong. I love me some Python and I love me some unit tests. The problem is, I find strict unit tests in &lt;a href="http://en.wikipedia.org/wiki/Dynamic_programming_language"&gt;dynamically typed languages&lt;/a&gt; aren't nearly as useful as they are in &lt;a href="http://en.wikipedia.org/wiki/Dynamic_typing#Static_typing"&gt;statically typed&lt;/a&gt; languages.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;I can hopefully better illustrate this with an example. Let's say we have some code like below. &lt;b&gt;Note:&lt;/b&gt;&lt;i&gt;&amp;nbsp;&lt;/i&gt;Don't worry about what's actually happening (I completely made it up), but just be aware that &lt;i&gt;decide() &lt;/i&gt;&lt;span style="font-style: normal;"&gt;calls on &lt;/span&gt;&lt;i&gt;compute()&lt;/i&gt;&lt;span style="font-style: normal;"&gt; and both have conditionals/exceptions/loops, etc which make them good candidates for unit testing … in that, they could easily bust our application if someone starts messing with either of them.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;Also note that &lt;/span&gt;&lt;i&gt;decide()&lt;/i&gt;&lt;span style="font-style: normal;"&gt; is dependent on a bunch of other functions: &lt;/span&gt;&lt;i&gt;get_seed(), get_first()/second()/third()&lt;/i&gt;&lt;span style="font-style: normal;"&gt; … which we will assume are equally unit tested.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;script src="https://gist.github.com/1182579.js?file=gistfile1.py"&gt;&lt;/script&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;So, we write our unit tests and they're really good. They mess with the fence post cases of &lt;i&gt;compute()&lt;/i&gt;&lt;span style="font-style: normal;"&gt;. They make &lt;/span&gt;&lt;i&gt;get_&lt;/i&gt;whatever()&lt;span style="font-style: normal;"&gt;&amp;nbsp;exception out to test the retry code. All of this is done with Mocks and Fakes so we're not dependent on the other code. These are unit tests after all; we shouldn't be calling external functions/methods. This means that in our &lt;/span&gt;&lt;i&gt;decide()&lt;/i&gt;&lt;span style="font-style: normal;"&gt; unit tests, we've mocked out &lt;/span&gt;&lt;i&gt;compute()&lt;/i&gt;&lt;span style="font-style: normal;"&gt;.&amp;nbsp;&lt;/span&gt;&lt;span style="font-style: normal;"&gt;We green bar our test suites and all is good.&amp;nbsp;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: normal;"&gt;Until someone changes &lt;/span&gt;&lt;i&gt;compute()&lt;/i&gt;&amp;nbsp;to something like this:&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;script src="https://gist.github.com/1182582.js?file=gistfile1.py"&gt;&lt;/script&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;Now it's some weird function that takes a boolean (or something that can be coerced into a boolean) and returns a string. Fortunately the author fixed the unit tests for &lt;i&gt;compute() &lt;/i&gt;and everything green bars again.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;But the application no longer works. d&lt;i&gt;ecide()&lt;/i&gt;&lt;span style="font-style: normal;"&gt; is broken … and we won't discover it until &lt;/span&gt;&lt;i&gt;decide()&lt;/i&gt;&lt;span style="font-style: normal;"&gt; gets called. &lt;/span&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;Why? Because with most dynamically typed languages, the contracts between functions or methods are decided at runtime. When &lt;/span&gt;&lt;i&gt;compute() &lt;/i&gt;&lt;span style="font-style: normal;"&gt;is called by &lt;/span&gt;&lt;i&gt;decide()&lt;/i&gt;&lt;span style="font-style: normal;"&gt; the virtual machine will try to  coerce the values for &lt;/span&gt;&lt;i&gt;first &lt;/i&gt;&lt;span style="font-style: normal;"&gt;and &lt;/span&gt;&lt;i&gt;second &lt;/i&gt;&lt;span style="font-style: normal;"&gt;as best as it can. Likewise, when the response from &lt;/span&gt;&lt;i&gt;compute() &lt;/i&gt;&lt;span style="font-style: normal;"&gt;comes back to &lt;/span&gt;&lt;i&gt;decide()&lt;/i&gt;&lt;span style="font-style: normal;"&gt; the virtual machine will try to apply the +100 to it the best way it can. Maybe it will work, maybe it won't. Almost certainly it won't be what the developers intended.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;If we are using a statically typed language such as C/C++/Java/C# things are a little easier. Our function would probably look something like &lt;/span&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;script src="https://gist.github.com/1182583.js?file=gistfile1.c"&gt;&lt;/script&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;So, when &lt;/span&gt;&lt;i&gt;compute()&lt;/i&gt;&lt;span style="font-style: normal;"&gt; changes to&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;script src="https://gist.github.com/1182598.js?file=gistfile1.c"&gt;&lt;/script&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;… &lt;span style="font-style: normal;"&gt;the compiler can catch it and complain long before the unit tests are ever run.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;What does this mean for us Python/Ruby/PHP developers? It means we have to start moving towards integration tests in addition to our unit tests. Unit tests alone are not enough to let us sleep at night. &lt;/span&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;&lt;a href="http://www.sandywalsh.com/2011/06/effective-units-tests-and-integration.html"&gt;As I've said before&lt;/a&gt;, integration tests, while great, are a royal pain in the buttocks. They are fragile and difficult to maintain. Do we need to go full-on end-to-end integration testing? No. A normal unit test has a call-out depth of zero. We only test the function in question. But, what we can do is start to write some 1-depth unit tests (or baby integration tests, if you prefer). A 1-depth unit test would allow &lt;/span&gt;&lt;i&gt;decide() &lt;/i&gt;&lt;span style="font-style: normal;"&gt;to call &lt;/span&gt;&lt;i&gt;compute() &lt;/i&gt;&lt;span style="font-style: normal;"&gt;(and &lt;/span&gt;&lt;i&gt;get_first/second/third/seed&lt;/i&gt;&lt;span style="font-style: normal;"&gt;, etc&lt;/span&gt;&lt;i&gt;)&lt;/i&gt;&lt;span style="font-style: normal;"&gt; but no further. All calls beyond the 1-function call depth would be stubbed out as normal.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;How do we decide where to place our 1-depth unit tests? I find that file or module boundaries are good places; places where it's not really easy to scan with your eyes. I will also skip third party libraries. I'm really just worried about the code I can immediately control.&amp;nbsp;&lt;/span&gt;Or perhaps you might want to write them between highly dependent and equally complex functions?&lt;br /&gt;&lt;span style="font-style: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: normal;"&gt;Do you need to include every external call? Probably not. Make it a judgment call. Is the return type from a call sufficiently complex that it's likely to change? That's a great place to push your call depth down a level. Does one of your functions parameters have a dictionary of assorted types? If so, that sounds suitably fragile.&amp;nbsp;&lt;/span&gt;Use common sense, there's no one-size-fits-all rule to this.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;But, I would strongly encourage you to place these tests in a separate directory away from your strict unit tests. Developers should know what they're getting into when they open those files.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;I look forward to hearing your thoughts on this.&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/8696186-5904795609663683261?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/5904795609663683261/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=5904795609663683261' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/5904795609663683261'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/5904795609663683261'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2011/08/pain-of-unit-tests-and-dynamically.html' title='The Pain of Unit Tests and Dynamically Typed Languages'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-1478186483478607934</id><published>2011-06-30T11:14:00.002-03:00</published><updated>2011-06-30T11:47:18.807-03:00</updated><title type='text'>Effective Units Tests and Integration Tests</title><content type='html'>&lt;div style="text-align: center;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;br /&gt;A unit is the smallest testable part of an application.&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;More often than not, I see &lt;a href="http://en.wikipedia.org/wiki/Unit_testing"&gt;unit tests&lt;/a&gt; that forget this core tenet. Picture a method or function as a sandbox. When you are writing a unit test, never let a call get outside of your sandbox.&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/-BJw3aTyLEHA/Tgx3Z5OU1jI/AAAAAAAAAkE/xFkxFIC71k0/s1600/sandbox.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="144" src="http://3.bp.blogspot.com/-BJw3aTyLEHA/Tgx3Z5OU1jI/AAAAAAAAAkE/xFkxFIC71k0/s320/sandbox.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;You unit test should be testing the &lt;a href="http://en.wikipedia.org/wiki/Conditional_(programming)"&gt;conditional logic&lt;/a&gt;&lt;i&gt;&amp;nbsp;&lt;/i&gt;and &lt;a href="http://en.wikipedia.org/wiki/Correctness_(computer_science)"&gt;correctness&lt;/a&gt;&amp;nbsp;of the code in your sandbox. Let another test worry about all that external/dependent code. When writing a suite of unit tests we're interested in &lt;a href="http://en.wikipedia.org/wiki/Code_coverage"&gt;code coverage&lt;/a&gt;. We want to exercise as much of our code base as possible. That's a lot of tests. We need to make sure these tests are not fragile, difficult to write or hard to maintain. And we need to make sure they're quick to execute.&lt;br /&gt;&lt;br /&gt;The code in your sandbox really only has one or two purposes:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;To execute some external operation, and/or&lt;/li&gt;&lt;li&gt;To compute some result&lt;/li&gt;&lt;/ul&gt;Your unit test should be testing all possible code paths through your sandbox. What can cause your code path to change?&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Conditional_(programming)#If-then.28-else.29"&gt;If-Then statements&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Ternary_operation"&gt;Ternary operators&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Switch_statement"&gt;Switch statements&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Boolean_expression"&gt;Boolean expressions&lt;/a&gt;&amp;nbsp;(x = y or z)&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Try_catch#Exception_support_in_programming_languages"&gt;Try-catch blocks&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Goto"&gt;Goto statements&lt;/a&gt; (if applicable)&lt;/li&gt;&lt;/ul&gt;Each of these constructs can make one pass through your code different from the next one. That's the stuff your unit tests should be exercising.&lt;br /&gt;&lt;br /&gt;Computing a result includes:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Checking return values&lt;/li&gt;&lt;li&gt;Checking thrown exceptions&lt;/li&gt;&lt;li&gt;Checking set member variables and/or globals&lt;/li&gt;&lt;/ul&gt;Your unit test should be throwing all kinds of input at your code to ensure the return values are correct. Also that your code throws the appropriate exceptions on bad input. If your code doesn't return any values you may need to check that any global or member variables were correctly set.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;How to stay in your sandbox&lt;/b&gt;&lt;br /&gt;Nearly all programming languages have some sort of Fake, Mock or Stub library available for it. The purpose of these libraries is to short-circuit the external code and replace it with your test code. Something that:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Always returns an expected value&lt;/li&gt;&lt;li&gt;Has no state&lt;/li&gt;&lt;li&gt;Has no external state dependencies (i.e. a database initialized to known values)&lt;/li&gt;&lt;li&gt;Returns nearly instantly&lt;/li&gt;&lt;li&gt;Has no conditional logic in it&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;In "&lt;a href="http://xunitpatterns.com/"&gt;XUnit Test Patterns&lt;/a&gt;", Gerard Meszaros has a nice breakdown of Fakes, Mocks, Stubs and Dummies:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Dummy&lt;/b&gt; objects are passed around but never actually used. Usually they are just used to fill parameter lists.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Fake&lt;/b&gt; objects actually have working implementations, but usually take some shortcut which makes them not suitable for production (an in memory database is a good example).&lt;/li&gt;&lt;li&gt;&lt;b&gt;Stubs&lt;/b&gt; provide canned answers to calls made during the test, usually not responding at all to anything outside what's programmed in for the test. Stubs may also record information about calls, such as an email gateway stub that remembers the messages it 'sent', or maybe only how many messages it 'sent'.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Mocks&lt;/b&gt;&amp;nbsp;are objects pre-programmed with expectations which form a specification of the calls they are expected to receive.&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;I try to only use Dummies and Mock objects for unit tests. I don't like storing state in my &lt;a href="http://xunitpatterns.com/Test%20Double.html"&gt;test doubles&lt;/a&gt;&amp;nbsp;... after a while you spend so much time making an effective stub you don't know if you're testing the stub or the code in the sandbox. That's why I like mock objects. They usually just consist of "return &lt;i&gt;value&lt;/i&gt;" or "raise &lt;i&gt;exception&lt;/i&gt;" ... simple, maintainable and readable.&lt;br /&gt;&lt;br /&gt;&lt;i&gt;If you find yourself putting an If statement in a Mock, you're doing something wrong.&lt;/i&gt;&lt;/div&gt;&lt;br /&gt;&lt;b&gt;How can you verify an If-Then statement?&lt;/b&gt;&lt;br /&gt;Most of the time you just want to be sure that an external method or function was actually called. Do you need to &lt;i&gt;actually call &lt;/i&gt;that method? Hell no. Not in a unit test.&amp;nbsp;Many of these Mock libraries also have provisions for "Was Called" semantics. Essentially a flag is set if a Mock method was called. If your library doesn't have one, it's pretty darn simple to simple to set one up:&lt;br /&gt;&lt;script src="https://gist.github.com/1056192.js"&gt;&lt;/script&gt;&lt;br /&gt;So, rather than let your code call outside of your sandbox, replace the external method (via &lt;a href="http://en.wikipedia.org/wiki/Monkey_patching"&gt;monkey-patching&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Dependency_injection"&gt;dependency injection&lt;/a&gt; or some other mechanism) to use your mock instead.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Does all code need a Unit Test?&lt;/b&gt;&lt;br /&gt;No. Consider the following gist:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1056220.js"&gt; &lt;/script&gt;&lt;br /&gt;What would a unit test accomplish here? Nothing. Just make sure you have tests around each of the methods within foo().&lt;br /&gt;&lt;br /&gt;&lt;b&gt;When Unit Tests aren't sufficient&lt;/b&gt;&lt;br /&gt;Let's say we did write a unit test for foo() in the above example. Would it accomplish anything? No, because we aren't checking the semantic ordering of the calls within foo(). Putting logic in to ensure that do_this() was called before do_that() and do_something_else() would just be a waste of time.&lt;br /&gt;&lt;br /&gt;What if foo() was changed to this:&lt;br /&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/1056224.js"&gt; &lt;/script&gt;&lt;br /&gt;Our unit test would still pass just fine. But it would be wrong. What we need here is an &lt;a href="http://en.wikipedia.org/wiki/Integration_testing"&gt;Integration Test&lt;/a&gt;. Integration tests &lt;i&gt;do&lt;/i&gt;&amp;nbsp;check the semantic ordering of statements.&amp;nbsp;With an integration test we allow ourselves to step outside of our sandbox. We may even use test doubles to help us build our integration tests (including Fakes and Stubs).&lt;br /&gt;&lt;br /&gt;But now our mandate for these tests have changed: No longer are we concerned with code coverage, but instead we're interested in testing&lt;i&gt; specific usage scenarios that are critical to our customers acceptance of the software&lt;/i&gt;.&amp;nbsp;Other than manual testing, integration testing is the only way to ensure we're building software that will work for the customer.&lt;br /&gt;&lt;br /&gt;We don't need 100% code coverage, instead we want the 80% of the every day scenarios the user will be experiencing when they use our software. If we were making a word processor, do we need integration tests for mail merge, form builder and the math editor? Probably not. Sure, it would be nice to have, but it's not critical. What we &lt;i&gt;absolutely need&lt;/i&gt;&amp;nbsp;are integration tests for: launch, enter some text, setting basic styles like bold, italics, etc, printing, saving and loading, page flow, etc.&lt;br /&gt;&lt;br /&gt;Do we need to do integration testing for every edge case where an error might occur? No (again, it would be nice to have) ... but realistically we need to test: disk full, disk failed, out of memory, out of paper, etc. The &lt;i&gt;most common scenarios.&lt;/i&gt;&lt;br /&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;br /&gt;But, if integration testing is so good and so important, why not just do integration testing?&lt;br /&gt;&lt;br /&gt;Because integration testing is hard, slow, brittle, hard to read and hard to maintain. Everything unit tests aren't. In other words ... they're a pain in the ass.&amp;nbsp;Integration testing is &lt;a href="http://blog.thecodewhisperer.com/2010/10/16/integrated-tests-are-a-scam"&gt;sometimes frowned upon&lt;/a&gt; because of these limitations, but they're being compared to unit tests. Integration tests and unit tests are &lt;i&gt;very different animals.&lt;/i&gt;&amp;nbsp;They serve two different purposes and give two different levels of comfort to the developer. I don't even think they're comparable at all. The worst mistake a development team can make (regarding testing) is to mix and match their integration tests with their unit tests. You get the worst of both worlds. Keep them clearly separate.&lt;br /&gt;&lt;br /&gt;Also, treat your integration tests like your core code base. Unit tests can be hacky since they're so small. But integration tests are complicated and need to be carefully maintained. They need to be documented properly. They need fantastic logging capabilities with rich output. They need to follow the same coding styles as your core code base. They need to be structured, refactored and updated so that they're always easily readable. Unit tests are rarely refactored, since they're so small and atomic, there's usually nothing to change.&lt;br /&gt;&lt;br /&gt;So, to grow an effective body of Unit and Integration tests for your application, remember these rules:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Don't step outside your sandbox for unit tests&lt;/li&gt;&lt;li&gt;Use Mocks and Dummies for your unit tests&lt;/li&gt;&lt;li&gt;Check all branching logic in your unit tests&lt;/li&gt;&lt;li&gt;Go for very high code coverage for your unit tests&lt;/li&gt;&lt;li&gt;Integration tests are difficult beasts. Go for high-impact user stories in your integration testing. Mostly Happy Day scenarios.&lt;/li&gt;&lt;li&gt;Don't spend a lot of time on the edge-case failure conditions in your integration tests&lt;/li&gt;&lt;li&gt;Keep your integration test code clean and maintainable. Refactor as frequently as your core code base.&amp;nbsp;&lt;/li&gt;&lt;li&gt;Set up a dedicated integration test server that runs on every commit to trunk (they're slow and hard to set up remember)&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/8696186-1478186483478607934?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/1478186483478607934/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=1478186483478607934' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/1478186483478607934'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/1478186483478607934'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2011/06/effective-units-tests-and-integration.html' title='Effective Units Tests and Integration Tests'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/-BJw3aTyLEHA/Tgx3Z5OU1jI/AAAAAAAAAkE/xFkxFIC71k0/s72-c/sandbox.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-6628139836435498773</id><published>2011-06-22T20:48:00.000-03:00</published><updated>2011-06-22T20:48:49.081-03:00</updated><title type='text'>Technical Rabbit Holes …</title><content type='html'>&lt;div style="margin-bottom: 0in;"&gt;&lt;span id="goog_414926772"&gt;&lt;/span&gt;&lt;a href="http://www.sandywalsh.com/2011/04/iterations-and-time-boxing-are-mostly.html"&gt;Last time we had a good discussion about iteration&lt;span id="goog_414926773"&gt;&lt;/span&gt;s&lt;/a&gt; and how there's a potential for dead-air and confusion near the end of a time-box. Tricky problem with lots of nuances. But there's another place where we can get fooled by the perceived safety of time boxes and iterations. Complex code.&lt;/div&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0in;"&gt;Most interesting software is complex. You're not really treading the high-wire when you're cookie cutting variations on the same app over and over again. The fun stuff comes in when you're solving new or hard problems.  &lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-6vJ3xn66CDg/TgIMFe7DorI/AAAAAAAAAj4/jORYKl0H8LM/s1600/hole-in-the-rock.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="304" src="http://2.bp.blogspot.com/-6vJ3xn66CDg/TgIMFe7DorI/AAAAAAAAAj4/jORYKl0H8LM/s320/hole-in-the-rock.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;The issue with difficult problems is it's easy to go down &lt;i&gt;technical rabbit holes&lt;/i&gt;. To me, technical rabbit holes are when there's a gap between the what the developer is working on and the understanding of it by the customer. It's not that developer is doing something dishonest and obscuring their work. It's not that the customer is unable to understand the problem. The problem is trust. There's too much of it. The developer has just enough rope to potentially hang his part of the project and the customer is willing to let it happen.&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0in;"&gt;And, I know I like to pick on Scrum, but this is not Agile's fault. Agile does a great job of forcing small units of work to be produced and highlights customer interaction and feedback. Agile solved the old problem of “Going Dark” as &lt;a href="http://www.stevemcconnell.com/est.htm"&gt;Steve McConnell&lt;/a&gt; correctly describes it: The customer anxiously waiting at the end of a pipe for a product to drop out.&lt;/div&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0in;"&gt;So, then, how can a technical rabbit hole occur?&lt;/div&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0in;"&gt;Well, we know what a good project should look like. We may go off course a little from iteration to iteration, but the customer is there to keep us on track and reach the goal.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-UDkRDPHhyeg/TgIMFPYJ32I/AAAAAAAAAj0/DkzePSinaeE/s1600/InControl.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://3.bp.blogspot.com/-UDkRDPHhyeg/TgIMFPYJ32I/AAAAAAAAAj0/DkzePSinaeE/s320/InControl.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;When there is no clearly accessible customer or a poor customer proxy we know it's easy to go off course for real. We keep hitting our iterations, we keep delivering code, but it's not the right code (it's not solving the customers problem.)&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-jCTaFCSlUus/TgIMCSV100I/AAAAAAAAAjc/ES06aRWtV34/s1600/NotCustomerDriven.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://1.bp.blogspot.com/-jCTaFCSlUus/TgIMCSV100I/AAAAAAAAAjc/ES06aRWtV34/s320/NotCustomerDriven.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Dev shops often forget that there are two aspects of writing software: Research and Development. Too often these functions are rolled together into just “Development” and sadly the total becomes less than the sum of the parts. The customer needs to understand whether the developer is doing &lt;b&gt;R&lt;/b&gt; or&lt;b&gt; D&lt;/b&gt;.&lt;/div&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/--IwI_NPjCwY/TgIMFtytG9I/AAAAAAAAAj8/bcWoUpwK2IA/s1600/IntoTheRabbitHole.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://3.bp.blogspot.com/--IwI_NPjCwY/TgIMFtytG9I/AAAAAAAAAj8/bcWoUpwK2IA/s320/IntoTheRabbitHole.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;In the above illustration, the Y axis is the customers understanding of what the developer is doing. Green = “I see what's happening.” Red = “I don't really understand, but you say it's important.” You can see that for nearly two iterations, the customer wasn't really comfortable in what the developer was doing. &lt;i&gt;Two iterations. &lt;/i&gt;&lt;span style="font-style: normal;"&gt;Probably in the best case, that's four weeks of time. That's a long time.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;Can you see how this could go bad?&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-ctP6u-Zx2vo/TgIMDCrjpRI/AAAAAAAAAjg/2hFV4weAMWg/s1600/WhereIsTheBottom.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://4.bp.blogspot.com/-ctP6u-Zx2vo/TgIMDCrjpRI/AAAAAAAAAjg/2hFV4weAMWg/s320/WhereIsTheBottom.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;How many iterations do you have to go before the customer finally says “Stop!”?&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;And, again, it's not that the developer is doing something bad. He's not being tricky or deceitful. He's mostly likely really chasing down some complex code. The problem is he's doing in a manner that abandons the customer. Agile development means developing code &lt;/span&gt;&lt;i&gt;together&lt;/i&gt;&lt;span style="font-style: normal;"&gt; with the customer. It's not Us vs. Them. The customer put too much trust in the developer.&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;Many times these things work out. But there are times when they don't, when the rabbit hole goes too deep and the developer gets lost. Now we've just spent a lot of time and money and we aren't any closer to the goal for it.&lt;/span&gt;&lt;/div&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;What can we do to identify and prevent technical rabbit holes?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Get  a Second Opinion&lt;/b&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-gmCYHAcIgF8/TgIMEau_lsI/AAAAAAAAAjs/-2H-valBrd4/s1600/Double_Tap.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-gmCYHAcIgF8/TgIMEau_lsI/AAAAAAAAAjs/-2H-valBrd4/s1600/Double_Tap.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;As with any possible fatal disease, you should get a second opinion. Bring in another developer or two to bounce your approach off. Go deep. Talk about all the nitty gritty issues you foresee. Make them own the problem as much as you do. Ask questions, do they understand your vision? Do they understand your development plan? Do they have any concerns about your approach?&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;It's these people that are going to help you stay in the light. Perhaps they can articulate your plan to the customer better than you can? Perhaps they can see other ways to deliver on your vision without requiring the customer to put blind faith in you?&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;Never swim alone in deep water.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Incremental  Completeness&lt;/b&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/--ekASFPWVTA/TgIMCRqvTAI/AAAAAAAAAjY/ziOKfU6cl3k/s1600/StayVisible.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://3.bp.blogspot.com/--ekASFPWVTA/TgIMCRqvTAI/AAAAAAAAAjY/ziOKfU6cl3k/s320/StayVisible.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;span style="font-style: normal;"&gt;Technical rabbit holes can easily occur in any project with some degree of technical complexity. What we should be striving for is &lt;/span&gt;&lt;i&gt;I&lt;/i&gt;&lt;i&gt;ncremental Completeness.&lt;/i&gt;&lt;span style="font-style: normal;"&gt; Delivering small chunks of working code (with tests) to trunk that, not only help the developer with the R part of Research and Development but, show the customer that we understand where the destination is.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;Every iteration, try to put &lt;/span&gt;&lt;i&gt;something &lt;/i&gt;&lt;span style="font-style: normal;"&gt;in the code drop that the customer can see the results of. Perhaps even a simple command line tool the user can run on the release to play with the feature in some fashion (the customer is getting a working build every iteration, right?)&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;Which gets us to our next point ...&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Educate  the Customer&lt;/b&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;Don't assume the customer knows anything about what you're building. They may be able to spout off all kinds of technical mumbo jumbo, but is it code? If they don't understand the piece your building, how can they expect to confirm they have it at the end of the iteration?&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;Use analogies for the data structures you're building. Try to put it in terms they'll understand. Draw pictures. Share the whiteboard. Explain the complexity.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;You may not get it at the first sitting and don't try to force it in a single go. You're telling them a story. Put it in their terms. You're bringing them on a journey, take your time. Just make sure they're not just nodding mindlessly at you.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;You're not trying to turn them into computer scientists, but you want to get to the point where the customer can call &lt;a href="http://en.wikipedia.org/wiki/You_ain't_gonna_need_it"&gt;YAGNI&lt;/a&gt;. You want them to tighten the requirements to the point where they can say “we're not going to hit that condition frequently enough … so just print an error message.”&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Always Commit&lt;/b&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-yyzBCpvsvC0/TgIMDXYKrCI/AAAAAAAAAjk/QGNcGDaQ5Uw/s1600/commit.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="213" src="http://4.bp.blogspot.com/-yyzBCpvsvC0/TgIMDXYKrCI/AAAAAAAAAjk/QGNcGDaQ5Uw/s320/commit.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;This probably goes without saying, assuming you're using a modern day revision control system, but you have to commit and push your code. Do it frequently. Ideally, no later than every 3 days. Get others to look at your branch. Keep it in the light. Let other developers see what you've been up to. Tell them the same story you told the customer … what do they think? Do they agree that your description is a fair explanation of what you're actually doing? Do they think you're on course?&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;b&gt;Don't lose sight of trunk&lt;/b&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-QfVTM6XLNSo/TgIMF3pYh0I/AAAAAAAAAkA/dXiRW4MSINw/s1600/trunk.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="212" src="http://1.bp.blogspot.com/-QfVTM6XLNSo/TgIMF3pYh0I/AAAAAAAAAkA/dXiRW4MSINw/s320/trunk.jpg" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;Merge. Merge. Merge. Pull from &lt;a href="http://en.wikipedia.org/wiki/Trunk_(software)"&gt;trunk &lt;/a&gt;frequently . Keep those tests green. If you're doing something that is going to break trunk, use a scaffolding technique: build around the existing mechanism and provide a means to turn it on and off. Later, once your implementation is complete, you can remove the dead code. But, until then, you still have working code. Each iteration you should be pushing something working (with tests) back into trunk.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;Letting trunk get a way from you is a sure way to get lost in a technical rabbit hole. If you're adding new code when your tests don't run, you're in trouble. Do you remember what you changed that broke the tests? Are you getting closer or further away from them working again?&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;As a developer, it's probably your greatest risk.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Mr. Customer: Share  the vision&lt;/b&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-0aCL047Unnw/TgIMD4sX8tI/AAAAAAAAAjo/gQVjulebzDk/s1600/destination.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-0aCL047Unnw/TgIMD4sX8tI/AAAAAAAAAjo/gQVjulebzDk/s1600/destination.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;This one is for the customer ... it's ok to sound like a broken record. Keep talking about what the final product will look like. Give lots of detail. Make sure everyone knows where they are going. Make sure everyone knows what's important and what's not. Help the development team understand your business, who &lt;/span&gt;&lt;i&gt;your&lt;/i&gt;&lt;span style="font-style: normal;"&gt; customers are, what &lt;/span&gt;&lt;i&gt;they&lt;/i&gt;&lt;span style="font-style: normal;"&gt; want to experience from this software. &lt;/span&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;If you keep everyone focused on the goal (and the deadline), it's harder to wander off course. You want the developer to say “You know, I'd like to do this differently, but there won't be time right now. Let me find an intermediate step.”&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;TL;DR&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;Technical Rabbit-Holes can be prevented with Eyeballs and Education. Show people what your doing and explain how you're doing it. Don't let too much trust get the better of you.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;Good luck … and keep your head above ground!&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/8696186-6628139836435498773?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/6628139836435498773/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=6628139836435498773' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/6628139836435498773'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/6628139836435498773'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2011/06/technical-rabbit-holes.html' title='Technical Rabbit Holes …'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-6vJ3xn66CDg/TgIMFe7DorI/AAAAAAAAAj4/jORYKl0H8LM/s72-c/hole-in-the-rock.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-758896689845574115</id><published>2011-04-28T19:23:00.001-03:00</published><updated>2011-05-03T08:41:15.908-03:00</updated><title type='text'>Iterations and Time-boxing are (Mostly) Useless</title><content type='html'>&lt;i&gt;Sorry, this is a rather long post, but I've been thinking a lot about &lt;a href="http://en.wikipedia.org/wiki/Scrum_(development)"&gt;Scrum&lt;/a&gt; and iterations lately and haven't had time to blast this out in smaller chunks.&lt;/i&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;i&gt;If you know me, you know I'm not a big fan of Scrum. I don't like the hand-waving concept of &lt;a href="http://www.versionone.com/Agile101/velocity.asp"&gt;Velocity&lt;/a&gt; and I don't like the fact that it places a priority on process over code. XP, I feel, is a much more important for software development. Agile (aka customer responsiveness) can be achieved without the dogma. But that's not the point of this post. In this post I want to question the value of &lt;a href="http://en.wikipedia.org/wiki/Timeboxing"&gt;timeboxing&lt;/a&gt; and the benefits that modern revision control systems grant developers. So, stick with it, I spend some time setting it up before getting into the meat of the post. &lt;/i&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;Back in the 90's I was using &lt;a href="http://en.wikipedia.org/wiki/Spiral_model"&gt;Spiral Development Model&lt;/a&gt; on a project. Spiral is Waterfall with shorter, fixed-length, time spans between milestones. In XP, this idea was formalized as Iterations by dropping the Design phase and using automated testing to replace the long, drawn-out, testing phase.&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;The rationale behind iterations and Spiral was simple: Estimating is hard. The further out you look, the greater your error rate.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-b3fwEegCr1k/TbnhyPEuKFI/AAAAAAAAAe8/AwlsVKWJP_o/s1600/ErrorRange.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://4.bp.blogspot.com/-b3fwEegCr1k/TbnhyPEuKFI/AAAAAAAAAe8/AwlsVKWJP_o/s320/ErrorRange.gif" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;Spiral's insight was to reduce risk by keeping the milestones close together (and ensuring that each milestone is a shippable product).  &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;Scrum expanded on this idea and permitted the functionality &lt;span style="font-style: normal;"&gt;of the project to change from iteration to iteration. It does this by bringing the customer back into the picture each iteration for sign off and review of “what's most important now”. &lt;/span&gt;&lt;span style="font-style: normal;"&gt;All good stuff.&lt;/span&gt;&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-XqWpzMzhDPY/TbnhuUYMcpI/AAAAAAAAAe4/1K1EAvj8ZW4/s1600/ErrorIterations.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="95" src="http://2.bp.blogspot.com/-XqWpzMzhDPY/TbnhuUYMcpI/AAAAAAAAAe4/1K1EAvj8ZW4/s320/ErrorIterations.gif" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm; page-break-after: avoid; page-break-before: auto;"&gt;At the start of the project, the customer has a general idea of what they want from the development effort. Working with the team, these requirements manifest themselves as Stories (aka Requirements ... friggin' Scum wants to rename everything)&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-34DE7bA3xWY/TbniBmJ1f3I/AAAAAAAAAfk/yA0bMaoijIQ/s1600/Stories.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-34DE7bA3xWY/TbniBmJ1f3I/AAAAAAAAAfk/yA0bMaoijIQ/s1600/Stories.gif" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm; page-break-after: avoid;"&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;Now the developers enter the picture and give some guesses about how difficult each story is. This is usually done as T-Shirt Sizes (Small, Medium, Large) or some other metric. In a perfect world, these sizings are not equated to Time ... they are relative efforts &lt;/span&gt;&lt;span style="font-style: normal;"&gt;and no planning occurs more than one iteration out&lt;/span&gt;&lt;span style="font-style: normal;"&gt;. But in reality, the customer needs to have &lt;/span&gt;&lt;i&gt;some&lt;/i&gt;&lt;span style="font-style: normal;"&gt; idea for when to expect their product. It could be as co&lt;/span&gt;&lt;span style="font-style: normal;"&gt;a&lt;/span&gt;&lt;span style="font-style: normal;"&gt;rse a resolution as 1&lt;/span&gt;&lt;sup&gt;&lt;span style="font-style: normal;"&gt;st&lt;/span&gt;&lt;/sup&gt;&lt;span style="font-style: normal;"&gt; Half of Next Year or 4&lt;/span&gt;&lt;sup&gt;&lt;span style="font-style: normal;"&gt;th&lt;/span&gt;&lt;/sup&gt;&lt;span style="font-style: normal;"&gt; Calendar Quarter, etc.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;So ... we're back to using Time again. T-Shirt sizes get equated to some unit of time (let's say, Small = 1 day, Medium = 2 days, Large = 3 days). Iteration sizes are set into something manageable such as 2-3 weeks each.  &lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;Finally, given the number of developers it's a pretty easy exercise to give a Wild Assed Guess (WAG) as to when the product will ship. If everyone is happy, the dance can begin with the first iteration.&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-DO9K5IGkdAc/Tbnh2rkWN7I/AAAAAAAAAfA/IUPLZthjW0w/s1600/Estimate.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="250" src="http://2.bp.blogspot.com/-DO9K5IGkdAc/Tbnh2rkWN7I/AAAAAAAAAfA/IUPLZthjW0w/s320/Estimate.gif" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;When the developers get into the first iteration &lt;/span&gt;&lt;span style="font-style: normal;"&gt;they start coding on the most important stories (as selected by the customer). Things are wonderful. But, when they get into the second iteration some things may have changed. The priority of the stories may have changed, the first iteration dev effort may have uncovered new stories or perhaps, there is already technical debt that needs to be addressed. Regardless, the original WAG deadline is likely changing (for better or worse). &lt;/span&gt; &lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;The reality is that time-boxing the iteration introduces waste near the deadline. Let's say I'm 2 weeks into a 3 week iteration and I've finished all my work early, what should I do? Should I start working on another story from the next iteration (which includes bug fixes)? Should I perform some other non-development task such as manual testing or documentation? Should I refactor?&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;Surprisingly, the &lt;a href="http://en.wikipedia.org/wiki/Revision_control"&gt;Source Revision Control System &lt;/a&gt;(RCS) that you are using can have a significant impact on your decision. Personally, I think &lt;a href="http://en.wikipedia.org/wiki/Distributed_revision_control"&gt;Distributed Revision Control Systems&lt;/a&gt; (DRCS) such as &lt;a href="http://git-scm.com/"&gt;git&lt;/a&gt;, &lt;a href="http://bazaar.canonical.com/en/"&gt;bazaar&lt;/a&gt; or &lt;a href="http://mercurial.selenic.com/"&gt;mercurial&lt;/a&gt; are the most significant change in software engineering within that last 10 years. Not because having a non-central repository is so revolutionary, but because branching and merging has become such a low-cost operation that the speed of software development has increased &lt;/span&gt;&lt;span style="font-style: normal;"&gt;dramat&lt;/span&gt;&lt;span style="font-style: normal;"&gt;ically. Development shops that &lt;/span&gt;&lt;span style="font-style: normal;"&gt;utilize these tools can see some big improvements in how they deal with the “&lt;/span&gt;&lt;span style="font-style: normal;"&gt;Rough Edge” at the e&lt;/span&gt;&lt;span style="font-style: normal;"&gt;nd of the &lt;/span&gt;&lt;span style="font-style: normal;"&gt;s&lt;/span&gt;&lt;span style="font-style: normal;"&gt;print. &lt;/span&gt; &lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;Let's &lt;/span&gt;&lt;span style="font-style: normal;"&gt;compare&lt;/span&gt;&lt;span style="font-style: normal;"&gt; dev shops that use a RCS that supports fast/low-cost branching and merging &lt;/span&gt;&lt;span style="font-style: normal;"&gt;to those at don't&lt;/span&gt;&lt;span style="font-style: normal;"&gt;. &lt;/span&gt; &lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;As I mentioned above, having rigid deadlines means potentially having dead time on your hands.  &lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; margin-bottom: 0.21cm; margin-left: 0px; margin-right: 0px; margin-top: 0px; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-7LGxZUxKIM8/Tbnh9QsLFhI/AAAAAAAAAfU/n2_tT5J5gw0/s1600/RigidPoor.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="186" src="http://3.bp.blogspot.com/-7LGxZUxKIM8/Tbnh9QsLFhI/AAAAAAAAAfU/n2_tT5J5gw0/s320/RigidPoor.gif" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;You either have to find small, low-risk stories that you can take on within the remaining time or do busy-work to fill the gaps. &lt;/span&gt;&lt;span style="font-style: normal;"&gt;If your customer is more willing to let the deadline slip to get the functionality they desire, things aren't much better. You're simply moving the dead time out a little further.&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-kjf5JFoICtc/Tbnh7xwDEYI/AAAAAAAAAfI/OZXXoutnll0/s1600/FlexPoor.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="232" src="http://4.bp.blogspot.com/-kjf5JFoICtc/Tbnh7xwDEYI/AAAAAAAAAfI/OZXXoutnll0/s320/FlexPoor.gif" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;But if you're using a RCS that has low cost branches and good merge capabilities, things get much easier because the developers can keep working on upcoming stories without affecting the current iteration.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/--XcfMldb8R4/Tbnh8vVzTmI/AAAAAAAAAfQ/a-A9hvQczBU/s1600/RigidGood.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="238" src="http://2.bp.blogspot.com/--XcfMldb8R4/Tbnh8vVzTmI/AAAAAAAAAfQ/a-A9hvQczBU/s320/RigidGood.gif" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;“&lt;span style="font-style: normal;"&gt;But I can branch and merge with svn or &lt;insert here="" name=""&gt;” I hear you say. Yes, you can, but not quickly. &lt;/insert&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt;When keeping in sync with trunk is expensive, it doesn't happen. When you don't sync with trunk the costs of your merges increase, &lt;/span&gt;&lt;span style="font-style: normal;"&gt;merges are larger&lt;/span&gt;&lt;span style="font-style: normal;"&gt; and your &lt;/span&gt;&lt;span style="font-style: normal;"&gt;unit &lt;/span&gt;&lt;span style="font-style: normal;"&gt;test maintenance efforts increase.  When branching and merging costs are low, it's easy for developers to start and new branch and keep working without upsetting trunk or the deliverable for the current iteration. &lt;/span&gt;&lt;span style="font-style: normal;"&gt;Look at the &lt;a href="http://nvie.com/posts/a-successful-git-branching-model/"&gt;NVIE branching model&lt;/a&gt; as your reference standard.&lt;/span&gt;&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;&lt;span style="font-weight: normal;"&gt;So, the million dollar question ...&lt;/span&gt;&lt;b&gt; if I can keep working and still ship my promised set of stories as they become available, why time box in the first place?&lt;/b&gt;&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;Pull models such as &lt;a href="http://en.wikipedia.org/wiki/Kanban"&gt;Kanban&lt;/a&gt; &lt;/span&gt;&lt;span style="font-style: normal;"&gt;don't really rely on timeboxing. Instead, developers &lt;/span&gt;&lt;i&gt;pull&lt;/i&gt;&lt;span style="font-style: normal;"&gt; stories from the backlog when they need to. The customer can re-prioritize the backlog as they desire. Finally, when a feature is completed it's merged into trunk and becomes part of the deliverable. The customer can decide which version of trunk they want to use and don't need to wait for an N week deadline to pass before grabbing the product. &lt;/span&gt;&lt;span style="font-style: normal;"&gt;Developers are encouraged to keep the &lt;a href="http://en.wikipedia.org/wiki/Work_in_process"&gt;Work In Progress&lt;/a&gt; (WIP) to a minimum &lt;/span&gt;&lt;span style="font-style: normal;"&gt;to prevent having lots of half-finished efforts.&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-67fIolykLnA/Tbnh8XAWtpI/AAAAAAAAAfM/btwrbB2t4CI/s1600/Kanban.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-67fIolykLnA/Tbnh8XAWtpI/AAAAAAAAAfM/btwrbB2t4CI/s1600/Kanban.gif" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;We, as developers, can still give estimates on each feature and we can still do our burn up/down charts to track progress, but we don't need to actually block out time frames. Actually what we're doing is taking the idea of iterations to the logical extreme: &lt;i&gt;each story is an iteration&lt;/i&gt;.&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;I can think of only one situation where time boxing is useful and that's in Scrum of Scrums. When the senior managers/customers have to monitor more than one team of developers they need to be able to snapshot the state of progress across teams. The ideal situation however, would be a Scrum of Kanbans:&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-5hGDtWElF2Y/Tbnh-VWMQlI/AAAAAAAAAfY/MEukUjYZsis/s1600/ScrumOfKanbans.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://2.bp.blogspot.com/-5hGDtWElF2Y/Tbnh-VWMQlI/AAAAAAAAAfY/MEukUjYZsis/s320/ScrumOfKanbans.gif" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;Senior stakeholders get a top-down view of the state of the development process without slowing down the developers every 2-3 weeks. For them, this is a simple synchronization mechanism for keeping the cats herded.&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;This gets us back to &lt;/span&gt;&lt;span style="font-style: normal;"&gt;one last point on estimating. As I've said before, estimating sucks. Developers hate having to break down tasks to such a fine resolution that they can be tracked in 4&lt;/span&gt;&lt;span style="font-style: normal;"&gt;-8 &lt;/span&gt;&lt;span style="font-style: normal;"&gt;hr intervals. If I have to think about a problem to 4hr resolution I may as well just &lt;/span&gt;&lt;span style="font-style: normal;"&gt;code it. &lt;/span&gt;&lt;span style="font-style: normal;"&gt;Why not 1 hour? Why not task out to every 30 minutes? Simple, it's a case of diminishing returns. The time it takes to document the tasks outweighs the effort itself. &lt;/span&gt; &lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;I think a better approach is to not to track tasks &lt;/span&gt;&lt;span style="font-style: normal;"&gt;at&lt;/span&gt;&lt;span style="font-style: normal;"&gt; high resolution. Instead keep things &lt;/span&gt;&lt;span style="font-style: normal;"&gt;in the &lt;/span&gt;&lt;span style="font-style: normal;"&gt;1-3 day range with a clear deliverable and simply track the &lt;/span&gt;&lt;i&gt;sentiment&lt;/i&gt;&lt;span style="font-style: normal;"&gt; of the developer towards the story. On the first day of the iteration, the developer should be very positive that they can deliver this story in this iteration (otherwise, why did they sign up for it?) ... but as the iteration progresses their sentiment may change. And it's going to North or South very quickly. “Oh, that's not good”, “This is getting bad.”, “I'm screwed”. &lt;/span&gt; &lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-ypGuXA-8lKQ/Tbnh_MmfKZI/AAAAAAAAAfc/uV778uSGSjQ/s1600/Sentiment.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="188" src="http://3.bp.blogspot.com/-ypGuXA-8lKQ/Tbnh_MmfKZI/AAAAAAAAAfc/uV778uSGSjQ/s320/Sentiment.gif" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;This is what we should be getting from our &lt;a href="http://en.wikipedia.org/wiki/Stand-up_meeting"&gt;Standup Meetings&lt;/a&gt;. When we report status and obvious impediments to our peers we should also be giving a vibe on our ability to deliver.&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;This gets ever better for the Senior Managers, not only can they see their Scrum of Kanban stories getting executed, but they can boil up the sentiment from each of the teams to see how the iteration is going.  &lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://4.bp.blogspot.com/-ZGKomkpTl0Q/TbniBVEfELI/AAAAAAAAAfg/RGKu1MwxxU0/s1600/SentimentOverview.gif" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://4.bp.blogspot.com/-ZGKomkpTl0Q/TbniBVEfELI/AAAAAAAAAfg/RGKu1MwxxU0/s320/SentimentOverview.gif" width="254" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;div style="font-style: normal;"&gt;What do you think? Would your daily development process be better if you didn't have to break down tasks to super-fine resolution? As a manager, could you better estimate ability-to-deliver based on higher-level sentiment vs. tasks completed?&lt;/div&gt;&lt;div style="font-style: normal;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;b style="font-style: normal;"&gt;UPDATE:&lt;/b&gt; &lt;i&gt;&lt;a href="http://glenc.info/"&gt;Glen Campbell&lt;/a&gt; was nice enough to &lt;a href="http://glenc.info/2011/05/02/iterative-development-and-branching/"&gt;give his perspective&lt;/a&gt; on this post. Jump over there to read his post and the comments to see my response.&amp;nbsp;&lt;/i&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8696186-758896689845574115?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/758896689845574115/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=758896689845574115' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/758896689845574115'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/758896689845574115'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2011/04/iterations-and-time-boxing-are-mostly.html' title='Iterations and Time-boxing are (Mostly) Useless'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/-b3fwEegCr1k/TbnhyPEuKFI/AAAAAAAAAe8/AwlsVKWJP_o/s72-c/ErrorRange.gif' height='72' width='72'/><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-5651297347314896166</id><published>2011-03-01T00:32:00.000-04:00</published><updated>2011-03-01T00:32:58.422-04:00</updated><title type='text'>WebOS: Horizontally and Vertically centering an image.</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: left;"&gt;Ok, this shouldn't have been too difficult. I just wanted to horizontally and vertically center an image using HTML5/CSS3 for WebOS. There's lots of ways to do this, but most solutions have fixed coordinates and wouldn't work well moving to different resolutions. Turns out it was a little tricker than I thought.&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: left;"&gt;Here's the proper way (colored borders added so you can see what's what):&amp;nbsp;&lt;/div&gt;&lt;br /&gt;&lt;script src="https://gist.github.com/848606.js"&gt; &lt;/script&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="https://lh4.googleusercontent.com/-faH0FhCDyWM/TWxygbLCQDI/AAAAAAAAAao/Bx5yJW5mQsc/s1600/webosscreenshot3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="https://lh4.googleusercontent.com/-faH0FhCDyWM/TWxygbLCQDI/AAAAAAAAAao/Bx5yJW5mQsc/s320/webosscreenshot3.png" width="212" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8696186-5651297347314896166?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/5651297347314896166/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=5651297347314896166' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/5651297347314896166'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/5651297347314896166'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2011/03/webos-horizontally-and-vertically.html' title='WebOS: Horizontally and Vertically centering an image.'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='https://lh4.googleusercontent.com/-faH0FhCDyWM/TWxygbLCQDI/AAAAAAAAAao/Bx5yJW5mQsc/s72-c/webosscreenshot3.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-522921907451837369</id><published>2011-02-27T15:41:00.006-04:00</published><updated>2011-02-27T19:30:59.233-04:00</updated><title type='text'>Palm Pre 2 - First Impressions from an iPhone user</title><content type='html'>I've been an iPhone user for about 3yrs now. And, while it's a great phone, I've never developed any software for it. Why? Well, I didn't really want to learn Obj-C (no good reason), I'm an Ubuntu user and I could never justify the Mac hardware prices. I'd prefer to stick with Python or HTML/CSS/JS. Yes, I could do C/C++ and have support on nearly all the platforms, but I think HTML5/CSS3/JS is a more versatile cross platform approach.&lt;br /&gt;&lt;br /&gt;I've been really riding the fence on Android, but I really couldn't get myself excited about Java development again. It would take all the fun out of it.&lt;br /&gt;&lt;br /&gt;Anyway ... &lt;a href="http://www.palm.com/us/company/events/index.html"&gt;HP WebOS&lt;/a&gt; caught my eye. I noticed Palm has a&lt;a href="http://developer.palm.com/index.php?option=com_content&amp;amp;view=article&amp;amp;id=2129"&gt; $200 rebate&lt;/a&gt; for app developers to go towards a Palm Pre 2. But it's only for the US. I pleaded my case and HP was very quick to get me into the program. Naturally I had to prove I could find my way around the emulator, build tools, SDK, PDK and app store registration stuff. These were all easy to do&amp;nbsp;(certainly better than another&amp;nbsp;&lt;a href="http://blog.jamiemurai.com/2011/02/you-win-rim/"&gt;not-so-well-run developer program&lt;/a&gt;). No hidden costs and, since I already have a registered company, signing up for the app store was simple.&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://new-cell-phone.org/wp-content/uploads/2010/10/HP-Palm-Pre-2-Cell-Phone-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://new-cell-phone.org/wp-content/uploads/2010/10/HP-Palm-Pre-2-Cell-Phone-1.png" /&gt;&lt;/a&gt;&lt;/div&gt;It's only been a couple of days and I'm still getting into it. The tools are nice and development is pretty easy. Apparently a Linux emulator is going to be available soon, so I run in a VM image for now. The tutorials are sparse and the videos are arduous, but it's better than a Readme file.&amp;nbsp;I've hit a couple of snags with some trivial things; fortunately the community is supportive, as is the company. I'm looking forward to getting into a little WebOS development now ... and not just because of the incentives. WebOS is actually really cool.&lt;br /&gt;&lt;br /&gt;As an iPhone user I was really concerned how the touch interface would compare. There are some definite quirks, but overall it's an easy transition. The Pre products have a "Gesture Area" where the iPhone home button is. You can do some basic swipes in the gesture area to go backwards, etc. But the real strength of the gesture area is in managing your multi-threaded apps. WebOS has a really cool card management UI metaphor that works nicely over all applications. Since the apps are mostly in HTML managing your apps and managing your websites have all the same look and feel to it. Creating a new browser page is just creating a new card in the stack. That page can sit next to your other apps and you can create stacks of these cards around function, not application. It just feels right.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.wirefresh.com/images/palm-webos-2-0.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="320" src="http://www.wirefresh.com/images/palm-webos-2-0.jpg" width="214" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;WebOS has a "launcher" which does feel a little clunky though. I prefer to have the icons on the main screen instead of a separate operation. Instead WebOS has a "Just Type" area. You can start entering an email, sms, tweet, etc while the thought is fresh and &lt;i&gt;then&lt;/i&gt;&amp;nbsp;say "send this as an email", "tweet this" or "SMS to ..." It's going to take some getting used to for me.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.palm.com/uk/en/assets/images/products/software/webos2/webos_launcher.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.palm.com/uk/en/assets/images/products/software/webos2/webos_launcher.png" /&gt;&lt;/a&gt;&lt;/div&gt;Notifications are handled better on WebOS than the iPhone, but I do miss the "going dim" warning on the iPhone that says the screen is about to shut off. I think I also miss push notifications, but they were always a love/hate thing anyway. And, I'm of two minds on the slide out keyboard. It's a little small for me. Perhaps the&lt;a href="http://www.palm.com/us/products/phones/pre3/index.html"&gt; Pre 3&lt;/a&gt; would be better? I'm also keen to see more of the stuff WebOS is doing for sharing data between the devices like the &lt;a href="http://www.palm.com/us/products/pads/touchpad/index.html"&gt;HP Tablet&lt;/a&gt; with the "tap" metaphor. I will miss Beluga Messenger, my IRC client, TweetDeck and InstaPaper. Skype is coming soon though and Flash is supported.&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://www.keroncalame.com/wp-content/uploads/2010/10/webos_notifications.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://www.keroncalame.com/wp-content/uploads/2010/10/webos_notifications.jpg" /&gt;&lt;/a&gt;&lt;/div&gt;I was easily able to get my calendars and email synced since they're all on Google. But now I've got to cut the tether on iTunes for my music. I'm not too worried. The Pre seems very open. It has a removable battery, uses a standard USB cable and can act as a fully operational USB drive when plugged in. No magic. And the app store isn't a military lock down zone. So I think making the move will be easy.&lt;br /&gt;&lt;br /&gt;Naturally, the app store is a little bare. But hopefully other developers will appreciate this platform and jump in to fill the void. I'll let you know when I get my first app in the app store.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8696186-522921907451837369?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/522921907451837369/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=522921907451837369' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/522921907451837369'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/522921907451837369'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2011/02/palm-pre-2-first-impressions-from.html' title='Palm Pre 2 - First Impressions from an iPhone user'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-2382920536452791303</id><published>2011-02-12T14:01:00.000-04:00</published><updated>2011-02-12T14:01:50.211-04:00</updated><title type='text'>15 Problems with Old School Technical Support</title><content type='html'>Last time I checked it was 2011. So why is it I have to deal with these 1990-era call centers when I need customer support? ISP's, cell phone providers, telcos, large retail organizations … it's the same thing every time. I'll just refer to them as BigCo.&lt;br /&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;You know the flow. Something goes wrong with a product or service and you have to contact the company.&amp;nbsp;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-z5_bR-PaDUM/TVa_wSZSwWI/AAAAAAAAAZk/zi8OCyZbuyM/s1600/Problem.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="233" src="http://2.bp.blogspot.com/-z5_bR-PaDUM/TVa_wSZSwWI/AAAAAAAAAZk/zi8OCyZbuyM/s320/Problem.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;If you can, you go to their website and look for the contact page. Otherwise it's the only time you dig out the Yellow Pages.  &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-FbeAnhQ9RsI/TVaw1l6gPnI/AAAAAAAAAYU/K9icMyw8brQ/s1600/frog.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-FbeAnhQ9RsI/TVaw1l6gPnI/AAAAAAAAAYU/K9icMyw8brQ/s1600/frog.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;b&gt;Problem 1:&lt;/b&gt; The customer support contact page is either so well hidden or written in such a confusing manner you have no idea how to reach the company.  &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;More often than not a phone number is not even available. If you are stuck with leaving an email (assuming you have Internet connectivity) you have no idea when you may hear back or even if the email was received. So, to play it safe, you phone them. No way they can lose a voice call is there?&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;You call the number and you're greeted with a lovely … robot. Those damn Interactive Voice Response (IVR) systems.&amp;nbsp;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-JFnM6RVmBNQ/TVa_sSFgVxI/AAAAAAAAAZc/vjkiZgIjNY0/s1600/IVR.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="170" src="http://1.bp.blogspot.com/-JFnM6RVmBNQ/TVa_sSFgVxI/AAAAAAAAAZc/vjkiZgIjNY0/s320/IVR.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;Instantly you added a few minutes to your service effort. If you're like me, you hit 0 immediately to get an operator. The bottom feeders of the customer support business will disable the 0 button and simply repeat the message. Assuming you have to follow the menu, you hang tight while your mind wanders and you miss the fact that option 4 of 7 was the one you needed. God forbid you press the wrong number and need to go backwards. Was it # or * to get the menu again? Then the menu goes 3 levels deep and ultimately doesn't offer anything that helps your cause.  Or worse, you get a canned message with no hints of what to do next.  &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;b&gt;Problem 2: &lt;/b&gt; IVR systems were invented in the 70's and have not evolved since 1997. Everyone hates them. BigCo disables the “0 for operator function” or does not permit “type ahead” and force you to listen to the entire message.&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;Side note, there is only one thing worse than IVR … voice recognition systems. The thinking is that it's more “conversational” and less robotic. It sucks. Often, it doesn't work and you have a long delay while the system times out and you get the annoying “Sorry I didn't understand that. &lt;repeat lead-in="" long="" message=""&gt;”. Even when it does work it only goes so many levels deep and you are forced to go back to touch-tone options regardless. Why bother? Perhaps it's intended for old people with rotary phones. In which case, wouldn't a human be the best approach?&lt;/repeat&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-tfU-1W1pq9Y/TVaw11TTRCI/AAAAAAAAAYk/g6Kto12-UzM/s1600/VoiceRecognition.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-tfU-1W1pq9Y/TVaw11TTRCI/AAAAAAAAAYk/g6Kto12-UzM/s1600/VoiceRecognition.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;b&gt;Problem 2a:&lt;/b&gt; Voice Recognition Systems don't work.&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;Let's assume you get an operator. More than likely your dealing with a BigCo call center. Unless you've been living on desert island with no phone service for the last 20 years, you know that call centers are caves deep underground that keep slaves (aka Customer Service Agents or CSA's) chained to small rocks (called 'cubicles') and force them to answer phones.&amp;nbsp;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-eziriFAJ4tQ/TVa_wdaBytI/AAAAAAAAAZg/v1hlpwpWQVQ/s1600/CallCenter.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="209" src="http://2.bp.blogspot.com/-eziriFAJ4tQ/TVa_wdaBytI/AAAAAAAAAZg/v1hlpwpWQVQ/s320/CallCenter.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;The actions these slaves perform are timed to within four decimal places of accuracy. They are told when they can sit, stand, use the bathroom and eat. Most importantly though, they are told what to say and are not allowed to think for themselves.&amp;nbsp;We should all feel for these poor souls, they take all of our crap when the real problem is higher up.&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-AG6KsIqD-UY/TVaw1wxeTQI/AAAAAAAAAYg/ymYKCU4Uw7I/s1600/Drones.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-AG6KsIqD-UY/TVaw1wxeTQI/AAAAAAAAAYg/ymYKCU4Uw7I/s1600/Drones.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;The things they are allowed to say are dictated in Scripts called “Policy Manuals”. Deviating from the Policy Manual is grounds for keel-hauling.&amp;nbsp;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-ksatnQ2OidE/TVa3VZqdJdI/AAAAAAAAAZI/LjC98CeIyBM/s1600/PolicyDocuments.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-ksatnQ2OidE/TVa3VZqdJdI/AAAAAAAAAZI/LjC98CeIyBM/s1600/PolicyDocuments.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;b&gt;Problem 3:&lt;/b&gt; Call centers do not encourage individuality or self-thought. But instead they encourage compliance and uniformity (think fast-food joints). This is really too bad since the real task, servicing the customer, can often be accomplished very quickly if the agent is permitted to think and act outside the box.  &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;Maybe your problem was part of the 70% of problems that can be solved by a simple phone call. Your irritation was minimal. You lost a few minutes navigating the system, but you write it off as the cost of doing business. Life goes on.&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-TpyEjOF2Eo4/TVa3AQeSUZI/AAAAAAAAAY8/MIBKiDNqYbk/s1600/WaitForever.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-TpyEjOF2Eo4/TVa3AQeSUZI/AAAAAAAAAY8/MIBKiDNqYbk/s1600/WaitForever.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;If you're in the 10% of problems that are not easily addressed by the Policy Manuals your journey is a little more complicated. You were likely transferred to 1, 2 or 3 other agents. Probably your call was dropped during the transfer. Maybe you had to call back in and repeat the whole process.  &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;b&gt;Problem 4:&lt;/b&gt; The Call Center does Blind Transfers. They forward a call to another agent or department and do no stay on the line with all parties until the transfer has been conducted successfully.  &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;b&gt;Problem 5:&lt;/b&gt; No trouble ticket. At the start of your call you should be given a trouble ticket number and a priority callback number. In the event you get cut off or dropped you should be able to circumvent all the conventional mechanisms and get back the agent you were dealing with &lt;i&gt;immediately.&lt;/i&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="font-style: normal; margin-bottom: 0cm;"&gt;&lt;b&gt;Problem 6: &lt;/b&gt;&lt;span style="font-weight: normal;"&gt;CSA's cannot make outgoing calls. When the call ends, the call center queuing system sends another call down the pipe. Unless your call is resolved during that call you better hope your phone batteries don't go dead or you're heading back to start over again.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;Regardless, on every transfer you have to repeat your story again. Start again from the top. “What is your name?” “I have a few security questions for your safety. &lt;ask address?!="" for="" mailing="" your=""&gt;” “Tell me about the problem”. Now you've just doubled your time on the call while the CSA refers to their copy of the Policy Manual.&lt;/ask&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-eU4OMOYRMu8/TVa3VK5rI_I/AAAAAAAAAZE/cLKFD-PYTU0/s1600/TellStoryOverAndOver.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-eU4OMOYRMu8/TVa3VK5rI_I/AAAAAAAAAZE/cLKFD-PYTU0/s1600/TellStoryOverAndOver.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;b&gt;Problem &lt;/b&gt;&lt;b&gt;7&lt;/b&gt;: Don't make us repeat ourselves. Don't ask inane security-theater questions over and over again when the call came internally.  &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;But maybe your problem was more complicated than that. Maybe your problem required some free thought? Maybe your problem had extenuating circumstances? Maybe your problem isn't documented in the Policy Manuals.  &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;God forbid your problem requires Field Service. If it does, well hang tight 'cause you're screwed.  &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-GanUpraQ9mk/TVa_sY3Mw1I/AAAAAAAAAZY/D2hmFVqNFuw/s1600/FieldSupport.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-GanUpraQ9mk/TVa_sY3Mw1I/AAAAAAAAAZY/D2hmFVqNFuw/s1600/FieldSupport.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;Field Service technicians and Level 2+ NOC technicians are BigCo royalty. You know the drill “we will send a field technician out between 8am and 12pm” … no finer resolution than that. &lt;i&gt;And you had better be home when they arrive&lt;/i&gt;&lt;span style="font-style: normal;"&gt;, or your name will do in the Black Book and never get service again.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;Problem &lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;8&lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;:&lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt; &lt;/span&gt;&lt;span style="font-style: normal;"&gt;Hire &lt;/span&gt;&lt;span style="font-style: normal;"&gt;skilled staff. Don't put your Field Technicians and Level 2 line of defense in glass towers where they are handled like Fabergé eggs. Increase the skill levels of your call center workers and Level 1 operators. Give the &lt;/span&gt;&lt;span style="font-style: normal;"&gt;skilled&lt;/span&gt;&lt;span style="font-style: normal;"&gt; service that is needed &lt;/span&gt;&lt;i&gt;earlier&lt;/i&gt;&lt;span style="font-style: normal;"&gt; in the process … not later. &lt;/span&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;The problem with the old-school call center is how performance is measured. Customers view success as the companies ability to quickly resolve our problem with a minimum of fuss and repetition. Call Centers like to give the impression that these things are important. They conduct customer satisfaction surveys. Some even perform follow up phone calls inquiring if our problem was met to our satisfaction.   &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;Unless BigCo really screwed up, most people will give a “ok”, “fine”, “whatever” … &lt;i&gt;because everyone hates telemarketers and spam more than in-bound call centers!&lt;/i&gt;&lt;span style="font-style: normal;"&gt; They want to get off the phone. They delete the&lt;/span&gt;&lt;i&gt; &lt;/i&gt;&lt;span style="font-style: normal;"&gt;spam email. JUST GO AWAY. Especially if &lt;/span&gt;&lt;span style="font-style: normal;"&gt;the &lt;/span&gt;&lt;span style="font-style: normal;"&gt;problem &lt;/span&gt;&lt;span style="font-style: normal;"&gt;wa&lt;/span&gt;&lt;span style="font-style: normal;"&gt;s resolved. It's Consumer Post Traumatic Stress Syndrome. We don't want to think about the pain we had to suffer dealing with your company. Lord knows we'll never say to our friends “You know I dealt with BigCo last week on a complicated issue and they solved it without any issues and I felt good at the end of it.”&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;For me, just the thought of having to deal with BigCo makes my blood pressure go up.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;Problem &lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;9&lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;:&lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt; These follow up calls and customer satisfaction surveys are just more spam. They waste &lt;/span&gt;&lt;i&gt;more&lt;/i&gt;&lt;span style="font-style: normal;"&gt; of our already precious time and you can't trust their results. &lt;/span&gt;&lt;span style="font-style: normal;"&gt;Find other, &lt;/span&gt;&lt;span style="font-style: normal;"&gt;less intrusive,&lt;/span&gt;&lt;span style="font-style: normal;"&gt; ways to gauge customer satisfaction … &lt;/span&gt;&lt;span style="font-style: normal;"&gt;like # of positive mentions on Facebook/Twitter or permitting BigCo discussion forums &lt;/span&gt;&lt;span style="font-style: normal;"&gt;or chat rooms&lt;/span&gt;&lt;span style="font-style: normal;"&gt;. &lt;/span&gt;&lt;span style="font-style: normal;"&gt;Bring BigCo customers together to solve problems. Don't keep us apart. &lt;/span&gt;&lt;span style="font-style: normal;"&gt; &lt;/span&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;No, call centers don't really care about customer satisfaction … you know what they do care about? Call Metrics. They care about Utilization Rates and Inbound Calls Handled and Abandon Rate. Do those things sound they affect &lt;/span&gt;&lt;span style="font-style: normal;"&gt;us&lt;/span&gt;&lt;span style="font-style: normal;"&gt;? Hell no. Inbound Calls Handled is an interesting one because it means “Get them off the line as quickly as possible.” Ugh.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-_QzPABoecXo/TVa_2L-h_4I/AAAAAAAAAZo/TBGf_SCSHfI/s1600/Reports.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="230" src="http://1.bp.blogspot.com/-_QzPABoecXo/TVa_2L-h_4I/AAAAAAAAAZo/TBGf_SCSHfI/s320/Reports.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;Problem &lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;10&lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;:&lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt; Call centers measure the wrong things. They should be forming customer &lt;/span&gt;&lt;i&gt;relationships, &lt;/i&gt;&lt;span style="font-style: normal;"&gt;not just solving technical problems. &lt;/span&gt;&lt;span style="font-style: normal;"&gt;Drop the &lt;/span&gt;&lt;span style="font-style: normal;"&gt;green bar reports.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;Here&lt;/span&gt;&lt;span style="font-style: normal;"&gt; is the crux of the problem. There are two groups within BigCo: &lt;/span&gt;&lt;span style="font-style: normal;"&gt;t&lt;/span&gt;&lt;span style="font-style: normal;"&gt;he Executive Management team (and their immediate lieutenants) and the front line workers. And never the two shall meet.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-4O7woHGsc7E/TVa_2GJfDdI/AAAAAAAAAZs/3o4d5IcaRzA/s1600/ExecutiveTeam.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="240" src="http://1.bp.blogspot.com/-4O7woHGsc7E/TVa_2GJfDdI/AAAAAAAAAZs/3o4d5IcaRzA/s320/ExecutiveTeam.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;The gatekeeper on the call center side is The Supervisor. The most hated and dreaded person in the customer service experience. Scrawled in blood on the call center dungeon walls are the words “Do Not Disturb”.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-c5Bwlww3FAg/TVaw14EpoYI/AAAAAAAAAYc/AJVLGYBnjZ8/s1600/MiddleManager.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-c5Bwlww3FAg/TVaw14EpoYI/AAAAAAAAAYc/AJVLGYBnjZ8/s1600/MiddleManager.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;Every perturbed customers asks their CSA to “speak to a supervisor”. Most call centers have electric shock sensors embedded in the chairs such that any agent that says “one moment please” will immediately receive 10,000 low current volts to their nether regions.&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-Cx-2JSKFZQc/TVa_5LoRi6I/AAAAAAAAAZw/vcXWfTakIpw/s1600/DoNotDisturb.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-Cx-2JSKFZQc/TVa_5LoRi6I/AAAAAAAAAZw/vcXWfTakIpw/s1600/DoNotDisturb.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;“&lt;span style="font-style: normal;"&gt;Damn them all”, you say, “I want to speak to your supervisor!”. &lt;/span&gt;&lt;span style="font-style: normal;"&gt;Background: t&lt;/span&gt;&lt;span style="font-style: normal;"&gt;he Supervisor is usually a battle worn CSA that has heard all the stories before. They have a toughened hide and know, from their many beatings, that there are only four important facts in life:&lt;/span&gt;&lt;/div&gt;&lt;ol&gt;&lt;li&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;Keep  your metrics in line&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;Never,  under penalty of immediate death, escalate a matter beyond the call  center&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;Life  does not exist outside of the Policy Manual&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;Follow  the script&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;Problem &lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;1&lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;1&lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;:&lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt; Call Center Supervisor's don't want to talk to customers. They will only after extended periods of duress. And then, they only repeat the same thing the CSA said … they cite the Policy Manual &lt;/span&gt;&lt;span style="font-style: normal;"&gt;verbatim. Chapter and verse like an old-timey preacher&lt;/span&gt;&lt;span style="font-style: normal;"&gt;. &lt;/span&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;Why are these supervisors so cold? Well, we all like to thi&lt;/span&gt;&lt;span style="font-style: normal;"&gt;nk that BigCo is one big happy family. We like to think that all departments keep in touch with each other and work together for the greater good. The reality is that the Executive Team would &lt;/span&gt;&lt;i&gt;never &lt;/i&gt;&lt;span style="font-style: normal;"&gt;sully themselves by dealing with the front-line workers. Doing so would be like the over privileged working in a soup kitchen on Thanksgiving. &lt;/span&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;“&lt;span style="font-style: normal;"&gt;Yes Muffy, those poor people. Tad and I spent the whole day with them. Listening to their problems and helping out wherever we could. But their problems run so deep, whatever can we do? Charity isn't the answer. &lt;/span&gt;&lt;span style="font-style: normal;"&gt;One of them &lt;/span&gt;&lt;span style="font-style: normal;"&gt;asked for my home address to visit, but that wouldn't be right would it? Another martini?”&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;There is not a razor-wire fence between these groups, there is a gaping chasm.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-vQ48c4K4eYk/TVaw1j83l4I/AAAAAAAAAYY/w6rIVtNP8B8/s1600/chasm.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-vQ48c4K4eYk/TVaw1j83l4I/AAAAAAAAAYY/w6rIVtNP8B8/s1600/chasm.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;Problem 1&lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;2&lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;:&lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt; The Executive Team is so far out of touch with the customer experience they are useless in the customer satisfaction equation. They need more quality time on the front lines or in the trenches. &lt;/span&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;The Executive Team care about a subset of the Call Center metrics. Mostly Utilization Rate. If one call center is under-performing … outsource to another one. They switch front-line services like a day trader with a penny stock. &lt;/span&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;So, &lt;/span&gt;&lt;span style="font-style: normal;"&gt;is it&lt;/span&gt;&lt;span style="font-style: normal;"&gt; the Executive Management teams fault? Are they the puppet masters behind this grand scheme to piss off the customer? Kind of. But it's not entirely their fault.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;The real fault lies with the technology vendors. Back in the 90's the buzz in the call center business was “Integrated Customer Service” (or “Unified Messaging” or '&lt;/span&gt;&lt;i&gt;insert marketing BS here&lt;/i&gt;&lt;span style="font-style: normal;"&gt;')&amp;nbsp;&lt;/span&gt;&lt;span style="font-style: normal;"&gt;Previously there was only the phone. AT&amp;amp;T had solved the IVR problem and honed the call center metrics to a precision point. &lt;/span&gt;&lt;span style="font-style: normal;"&gt;But with the web, there was email. There was live chat. There were multiple contact points. &lt;/span&gt;&lt;span style="font-style: normal;"&gt;Then w&lt;/span&gt;&lt;span style="font-style: normal;"&gt;e saw the rise of Customer Relationship Management (CRM) – integrated databases that track all customer interactions.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/-8iN4O8sKDzY/TVa2rV2VknI/AAAAAAAAAY0/blXzEG84W1w/s1600/IntegratedCallCenter.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://2.bp.blogspot.com/-8iN4O8sKDzY/TVa2rV2VknI/AAAAAAAAAY0/blXzEG84W1w/s1600/IntegratedCallCenter.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;CRM Fact #1:&lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt; No one &lt;/span&gt;&lt;span style="font-style: normal;"&gt;ever &lt;/span&gt;&lt;span style="font-style: normal;"&gt;reads the case history. No one. Ever. &lt;/span&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;Problem 1&lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;3&lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;:&lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt; Technology is not the answer. Being a human being is. &lt;/span&gt;&lt;span style="font-style: normal;"&gt;Ditch the IVR. Ditch the Voice Recognition Systems. Ditch the outsourced call centers. &lt;/span&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;There's an &lt;/span&gt;&lt;span style="font-style: normal;"&gt;old saying in &lt;/span&gt;&lt;span style="font-style: normal;"&gt;software development &lt;/span&gt;&lt;span style="font-style: normal;"&gt;circles&lt;/span&gt;&lt;span style="font-style: normal;"&gt;: &lt;/span&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;“&lt;i&gt;All problems can be solved by introducing a level of indirection.” - Butler Lampson &lt;/i&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;This is what's happened in the customer service industry. So many levels of indirection have arisen between the business and the customer that service has fallen between the cracks. &lt;/span&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;David Wheelers corollary to this is “&lt;/span&gt;&lt;i&gt;... except for the problem of too many levels of indirection&lt;/i&gt;&lt;span style="font-style: normal;"&gt;” in other words. &lt;/span&gt;&lt;i&gt;“All problems of performance can be solved by removing a level of indirection.”&lt;/i&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;And that's what we are faced with in the customer service industry … a problem of performance. There are so many layers of indirection that customers are forced repeat themselves endlessly. We get shuffled between groups. We, &lt;/span&gt;&lt;span style="font-style: normal;"&gt;the customers,&lt;/span&gt;&lt;span style="font-style: normal;"&gt; get lost in the cracks. &lt;/span&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;BigCo was sold a &lt;/span&gt;&lt;span style="font-style: normal;"&gt;vision&lt;/span&gt;&lt;span style="font-style: normal;"&gt;. They were told “use our products and your customer service levels will increase.” And they were right, but &lt;/span&gt;&lt;span style="font-style: normal;"&gt;at the cost of customer satisfaction. &lt;/span&gt;&lt;span style="font-style: normal;"&gt;The call center is a finely tuned machine, capable of handling large call volumes with relative ease. All the while the customers pay the price. Not only in wasted time but in increase&lt;/span&gt;&lt;span style="font-style: normal;"&gt;d&lt;/span&gt;&lt;span style="font-style: normal;"&gt; service costs. Running these centers cost money. Buying these switches, IVR's, CRM packages and putting bums in seats cost real dollars. But the real cost is the cost to BigCo. Now, BigCo is not just a big company, but BigCo becomes Big-Company-With-Fat-Cat-Managers-That-Hide-Behind-Layers-Of-Customer-Support-And-Are-Out-Of-Touch-With-Their-Client-Base. &lt;/span&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;And we hate them for it. &lt;/span&gt;&lt;span style="font-style: normal;"&gt;The technology may help their internal numbers but their outside perception &lt;/span&gt;&lt;span style="font-style: normal;"&gt;has &lt;/span&gt;&lt;span style="font-style: normal;"&gt;suffer&lt;/span&gt;&lt;span style="font-style: normal;"&gt;ed&lt;/span&gt;&lt;span style="font-style: normal;"&gt;. &lt;/span&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;Problem 1&lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;4&lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;:&lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt; Too many layers of indirection inside of the customer support department. The customer ends up getting bounced around like a ball in pinball machine. &lt;/span&gt;&lt;span style="font-style: normal;"&gt;Reduce the layers of indirection. CSA's should handle a problem from start to finish, holding your hand the whole time.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;It gets worse.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/-uecjINCnjiA/TVa3AfHMd6I/AAAAAAAAAY4/YFl_-fAqPhE/s1600/SocialMedia.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-uecjINCnjiA/TVa3AfHMd6I/AAAAAAAAAY4/YFl_-fAqPhE/s1600/SocialMedia.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;Twitter, Facebook and other forms of Social Media. Oh BigCo is all over them. But it's usually not the call center. It seems &lt;/span&gt;&lt;span style="font-style: normal;"&gt;like &lt;/span&gt;&lt;span style="font-style: normal;"&gt;these are Executive management initiatives. Spin offs from the executive management customer support groups or marketing groups are watching the Twitter accounts. &lt;/span&gt;&lt;span style="font-style: normal;"&gt;And why wouldn't it be? Social Media is hot. No executive is stupid enough not to dust up their resume with “Led BigCo's Social Media initiative and reduced print marketing costs by 7% blah blah blah”&lt;/span&gt;&lt;span style="font-style: normal;"&gt; &lt;/span&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="font-style: normal;"&gt;The&lt;/span&gt;&lt;span style="font-style: normal;"&gt;se social media presences&lt;/span&gt;&lt;span style="font-style: normal;"&gt; try to be more “personable” and put a human face to BigCo. But they have no power. When you need real work done you still have to deal with the old call center. The end result? &lt;/span&gt;&lt;span style="font-style: normal;"&gt;The frustrated customer has &lt;/span&gt;&lt;span style="font-style: normal;"&gt;to repeat &lt;/span&gt;&lt;span style="font-style: normal;"&gt;themselves &lt;/span&gt;&lt;i&gt;yet again.&lt;/i&gt;&lt;span style="font-style: normal;"&gt; &lt;/span&gt; &lt;br /&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;Problem 1&lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;5&lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;:&lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt; &lt;/span&gt;&lt;span style="font-style: normal;"&gt;For BigCo, &lt;/span&gt;&lt;span style="font-style: normal;"&gt;Social Media is a bag hung on the side of the customer support effort. It's a crippled dog that just ends up getting in the way of actually getting your problem resolved. If you're going to use Social Media, go full hog. &lt;/span&gt;&lt;span style="font-style: normal;"&gt;Replace your &lt;/span&gt;&lt;span style="font-style: normal;"&gt;call center farms with empowered in-house employees that can handle issues fully. Or keep Social Media as a marketing tool and don't even bother trying to solve our problems &lt;/span&gt;&lt;span style="font-style: normal;"&gt;in real-time&lt;/span&gt;&lt;span style="font-style: normal;"&gt;. &lt;/span&gt;&lt;span style="font-style: normal;"&gt;Your Twitter account isn't fooling anyone. &lt;/span&gt;&lt;span style="font-style: normal;"&gt;Watch how smaller companies do it. &lt;/span&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;True Story: I recently had a CSA try to sell me new products after my 10&lt;/span&gt;&lt;sup&gt;&lt;span style="font-style: normal;"&gt;th&lt;/span&gt;&lt;/sup&gt;&lt;span style="font-style: normal;"&gt; call attempting to get service. Really.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;b&gt;&lt;span style="font-style: normal;"&gt;Summary&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;Sadly for us, &lt;/span&gt;&lt;span style="font-style: normal;"&gt;BigCo &lt;/span&gt;&lt;span style="font-style: normal;"&gt;often &lt;/span&gt;&lt;span style="font-style: normal;"&gt;has a near monopoly … there &lt;/span&gt;&lt;span style="font-style: normal;"&gt;may be&lt;/span&gt;&lt;span style="font-style: normal;"&gt; only one &lt;/span&gt;&lt;span style="font-style: normal;"&gt;competitor &lt;/span&gt;&lt;span style="font-style: normal;"&gt;for consumers &lt;/span&gt;&lt;span style="font-style: normal;"&gt;to run to, and it's the exact same crap over there too. The devil you know vs. the devil you don't know.&lt;/span&gt;&lt;span style="font-style: normal;"&gt; There's &lt;/span&gt;&lt;span style="font-style: normal;"&gt;nowhere to turn&lt;/span&gt;&lt;span style="font-style: normal;"&gt;. &lt;/span&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;But there is something BigCo can do. They can try to win back the customer &lt;/span&gt;&lt;span style="font-style: normal;"&gt;and they can effectively crush their competition in the process. &lt;/span&gt;&lt;span style="font-style: normal;"&gt; &lt;/span&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;If BigCo really wants to &lt;/span&gt;&lt;span style="font-style: normal;"&gt;destroy their nemisis FatShop,&lt;/span&gt;&lt;span style="font-style: normal;"&gt; it's not going to be by offering streaming movies on demand or fiber to the house or +10mbps … it's going to be by having killer customer support. &lt;/span&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;Message to BigCo's everywhere: &lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt;Don't woo the customer on speeds and feeds. Woo us with your killer support. &lt;/span&gt;&lt;span style="font-style: normal;"&gt;Woo us with attention to detail. Woo us with ability to execute. I'd rather have older technology that works over bleeding edge stuff that you can't support.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;Business customers: ask &lt;/span&gt;&lt;span style="font-style: normal;"&gt;yourself this, Knowing the level of service you get from BigCo &lt;/span&gt;&lt;span style="font-style: normal;"&gt;as a consumer&lt;/span&gt;&lt;span style="font-style: normal;"&gt;, would you ever consider running your &lt;/span&gt;&lt;span style="font-style: normal;"&gt;mission critical &lt;/span&gt;&lt;span style="font-style: normal;"&gt;business &lt;/span&gt;&lt;span style="font-style: normal;"&gt;with them&lt;/span&gt;&lt;span style="font-style: normal;"&gt;?&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;BigCo needs to get with the times. Modern companies are winning the business from BigCo's all over the world by offering &lt;/span&gt;&lt;span style="font-style: normal;"&gt;leading &lt;/span&gt;&lt;span style="font-style: normal;"&gt;customer service. &lt;/span&gt;&lt;span style="font-style: normal;"&gt;I think of all the products and services I use from all over the world and get stellar service from. Where do I get the worse service? … right here in my hometown. That saddens me.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0cm;"&gt;&lt;span style="font-style: normal;"&gt;You know, my phone is a funny device. I use it for everything but making phone calls. When it rings I get startled. Why, because nearly everything I need is available online. Except for BigCo's customer support. There is no Quality of Service, no Service Level Agreement online, no Anticipated Response Time. It's a crap shoot. &lt;/span&gt;&lt;span style="font-style: normal;"&gt;So I'm stuck having to use their antiquated gauntlet of &lt;/span&gt;&lt;span style="font-style: normal;"&gt;voice &lt;/span&gt;&lt;span style="font-style: normal;"&gt;technology. But you know what? &lt;/span&gt;&lt;span style="font-style: normal;"&gt;The &lt;/span&gt;&lt;i&gt;instant&lt;/i&gt;&lt;span style="font-style: normal;"&gt; I can get a competitive offering from a modern company that allows me to ditch a BigCo service … I'm gone. &lt;/span&gt;&lt;span style="font-style: normal;"&gt;And customer support will be the deciding factor. &lt;/span&gt;&lt;span style="font-style: normal;"&gt;I'm done with Dinosaur Customer Support.&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/8696186-2382920536452791303?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/2382920536452791303/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=2382920536452791303' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/2382920536452791303'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/2382920536452791303'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2011/02/15-problems-with-old-school-technical.html' title='15 Problems with Old School Technical Support'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/-z5_bR-PaDUM/TVa_wSZSwWI/AAAAAAAAAZk/zi8OCyZbuyM/s72-c/Problem.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-6622356541578731590</id><published>2011-01-13T23:27:00.006-04:00</published><updated>2011-01-14T09:14:59.971-04:00</updated><title type='text'>Software Craftsmanship - Knife Skills, Tools and Art</title><content type='html'>I have a love/hate relationship with the expression &lt;i&gt;Software Craftsmanship&lt;/i&gt;. Jason Gorman has an interesting article entitled "&lt;a href="http://parlezuml.com/blog/?postid=989"&gt;Why Software Craftsmanship Is Not Just About 'Beautiful Code&lt;/a&gt;'" and I agree with his points.&lt;br /&gt;&lt;br /&gt;Don't confuse Craftsmenship with 'Knife Skills'. Cooks with great knife skills in a kitchen are able to try &amp;nbsp;ideas faster because they are not bogged down by the tools. Vim, shell, Git and&amp;nbsp;algorithms are knife skills. Iterations, continuous integration and stand-ups are tools. The Art is applying them. Interpersonal skills are also an Art. Be they talking with your team or coaxing requirements from a customer.&lt;br /&gt;&lt;br /&gt;My issue with the expression is when people label themselves a "Software Craftsperson". In my mind, Craftsman implies Master Craftsman. That connotes an image of the grey bearded guru who roams the countryside like Kung Fu looking to impart his wisdom on the "poor unfortunates". His charming tales of daring and adventure, loves won and lost, enrapture the weary apprentices as they strive to achieve that same level of Programming Zen. ... or Bob Vila. Both images cause equal pain.&lt;br /&gt;&lt;br /&gt;I think the real Software Craftsmen are the ones that view themselves as the apprentices. Humble. Usually you'll only hear them ask their colleagues "Could you show me how you did that?" They take pride in the work they've done and are happy to show others how they did it, but only from a place of shared excitement. Or, when unhappy with their results, they'll say "Can someone help me clean up this mess I've made?" and respect the feedback given.&lt;br /&gt;&lt;br /&gt;For now, I like Software Journeyman more.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8696186-6622356541578731590?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/6622356541578731590/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=6622356541578731590' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/6622356541578731590'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/6622356541578731590'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2011/01/software-craftsmanship.html' title='Software Craftsmanship - Knife Skills, Tools and Art'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-1653138394496793537</id><published>2010-12-03T08:19:00.006-04:00</published><updated>2010-12-03T08:36:42.175-04:00</updated><title type='text'>Done ...</title><content type='html'>There is no such thing as "Done Done". Stop saying it.&lt;br /&gt;&lt;br /&gt;You can be:&lt;br /&gt;1. Code Complete (proper comments and debugging code removed)&lt;br /&gt;2. Tests written and all tests pass&lt;br /&gt;3. Pull merge from trunk and integration testing done&lt;br /&gt;4. Pushed /&amp;nbsp;Committed&lt;br /&gt;5. Integrated with Trunk&lt;br /&gt;6. Deployed&lt;br /&gt;&lt;br /&gt;1 and 2 may be performed in any order appropriate.&lt;br /&gt;3, 4 and 5 may go many iterations and may mean revisiting 1 and 2.&lt;br /&gt;6 may contain a GOTO 1 in there somewhere.&lt;br /&gt;&lt;br /&gt;Then, you are Done. Singular&amp;nbsp;... hopefully.&amp;nbsp;The beast could wake up again.&lt;br /&gt;&lt;br /&gt;Yes, I know the formal definition of "done done" means all this stuff, but it's confusing. Done means done. There is so much that can go wrong between done and done-done that you need to be more specific when reporting to your team. &lt;i&gt;Team&amp;nbsp;communication is too important to discount.&amp;nbsp;&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8696186-1653138394496793537?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/1653138394496793537/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=1653138394496793537' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/1653138394496793537'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/1653138394496793537'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2010/12/done.html' title='Done ...'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-1191291004776050839</id><published>2010-11-22T08:33:00.003-04:00</published><updated>2010-11-22T09:41:12.740-04:00</updated><title type='text'>Buying Firewood (aka Becoming a Shirt)</title><content type='html'>It gets cold in Nova Scotia. My house uses electric heat which is expensive, so I burn wood on cold days. I burn about four face cords of wood over the winter (a Face Cord is 16" x 4' x 8' of wood)&lt;br /&gt;&lt;br /&gt;Wood needs to be cut, seasoned (dried), delivered, split and stacked before the season starts. Wood comes in hardwood (like Maple) or softwood (like Spruce). Hardwood is better for burning. With tax, a face cord of hardwood, cut, split and delivered costs as much as $250 from a reputable supplier. The low end of the price range is about $200, but the moisture content or mix of hard/soft wood may vary. It takes about a year or more for wood to be seasoned enough to be suitable for drying.&amp;nbsp;I can buy 8' lengths of hardwood for about $100/fc.&amp;nbsp;As you can easily deduce, it can cost $1000 for enough wood to last the winter, but it can be much cheaper if you're willing to do some of the work yourself.&lt;br /&gt;&lt;br /&gt;Buying unseasoned wood is even cheaper, but it means I need to store two loads of wood on my property. One for the current season, one for the next season. Eight cords of wood takes up a lot of room, so I try not to do that.&lt;br /&gt;&lt;br /&gt;Recently, I've been getting wood from friends who don't burn. They have large wooded lots and often lose trees to wind storms, etc. I've been able to get enough wood from them to not have to buy from a supplier. But it comes at a cost. To rent a trailer capable of carrying the weight of a load of wood is about $40/day. You can lug a lot of wood in a day. If the wood isn't cut to 16" lengths, you are also looking at getting the chainsaw out and slicing it up. Assume you're going to destroy a chainsaw chain during this process (resharpening about 5-6 times), so this is about $20. Then you need to split the wood. Rental of a splitter, here, is about $50 for 4 hrs or $80/day. I can split about a face cord of wood per hour. Assume an hour to get the splitter and bring it back.&amp;nbsp;I could buy a splitter for about $2000 and a good trailer for about $2000.&lt;br /&gt;&lt;br /&gt;It's a lot of work. Getting fell lumber from friends usually means I have to move it, recut it to size, split it, and stack it. I probably touch each piece of firewood about eight times by the time it gets in the stove. It's tremendous exercise. I like being outdoors in the cool air doing physical labor. It's an added bonus and cheaper than a gym membership. It can, however, be dangerous. You're working with heavy loads of wood, chainsaws, hydraulic splitters and falling trees. It could be done faster with more people, but coordinating the extra manpower is a pain ... unless there's a beer incentive, but that has to be factored into the cost.&lt;br /&gt;&lt;br /&gt;I assume I'm going to run out of this supply of free wood from friends in a couple of years. And I'm sure there is a Lost Opportunity Cost given the number of hours I spend on this vs. something else I could be doing that is either making or saving me more money.&lt;br /&gt;&lt;br /&gt;The question is, should I continue to scrounge the wood, lug, cut and split it myself or have 8' lengths delivered to process? Should I just pay the price and have cut, split &amp;amp; seasoned wood delivered at the end of each summer ... sort of Just-In-Time Delivery? How should I factor in the obvious exercise component of all of this work? Should I buy unseasoned wood and have a two-year pipeline in the works? Should I invest in a trailer and a splitter to reduce the time travelling to the rental shop and for the&amp;nbsp;convenience&amp;nbsp;of being able to work at my own pace?&lt;br /&gt;&lt;br /&gt;Don't know? Ask your Head of Engineering. They should be able to knock this problem out on the back of a napkin in short order. They have to make these decisions all the time. Should we license a third-party component, use Open Source or build it ourselves? Should we hire three more bodies or reorganize the project? Should we tackle this technical debt now or defer until a future iteration?&lt;br /&gt;&lt;br /&gt;As programmers, we spend a lot of time stacking firewood. Or splitting&amp;nbsp;firewood. Or moving&amp;nbsp;firewood. We don't take the time to stand back, look at the overall process and wonder if what we're doing is efficient or financially sound. Don't assume that when a developer has "turned into a shirt" that they've lost their problem solving skills. They're just tackling new problems which can be just a challenging. The big difference is that there's often more human interaction (politics) involved in getting a solution.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8696186-1191291004776050839?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/1191291004776050839/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=1191291004776050839' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/1191291004776050839'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/1191291004776050839'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2010/11/buying-firewood-aka-becoming-shirt.html' title='Buying Firewood (aka Becoming a Shirt)'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-836637523698285828</id><published>2010-11-05T09:52:00.000-03:00</published><updated>2010-11-05T09:52:20.082-03:00</updated><title type='text'>State Creep</title><content type='html'>State kills. It makes concurrency difficult and transactions brittle. State creeps into your program slowly and, over time, makes things difficult to read, understand, manage and maintain.&lt;br /&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;What is state? State is data. But data by itself is not complicated, nor is it something we can do without. When I talk about state, I mean data that affects business logic. Depending on the &lt;i&gt;state&lt;/i&gt;&lt;span style="font-style: normal;"&gt; of a variable, the logic of how a module works changes.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;The most common form of state is the Boolean:&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;pre&gt;is_manager&lt;br /&gt;requires_approval&lt;br /&gt;can_see_salaries&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;When you see a boolean, you should automatically see an IF statement … and, more than likely, many of them.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;If two or more booleans are related in such a way that the value of one affects the value of another, your complexity just shot up 2^N. You can expect to see the most nasty construct in your code: &lt;/span&gt;&lt;i&gt;The Nested If&lt;/i&gt;&lt;span style="font-style: normal;"&gt; (and remember that And/Or clauses are just short forms of nested If's). Two related Booleans means four cases to consider. Three means eight. You get the idea. &lt;/span&gt; &lt;/div&gt;&lt;br /&gt;&lt;pre&gt;def show_salaries:&lt;br /&gt;    get_approval = false&lt;br /&gt;    if requires_approval:&lt;br /&gt;        get_approval = not is_manager&lt;br /&gt;    if can_see_salaries:&lt;br /&gt;        if get_approval:&lt;br /&gt;            return redirect('GetApproval')&lt;br /&gt;        else:&lt;br /&gt;            return redirect('SalaryPage')&lt;br /&gt;    return redirect('NotAllowed')&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;Ugh. &lt;/span&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;Recommendation:&lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt; &lt;/span&gt;&lt;i&gt;Once you get beyond two linked booleans … &lt;a href="http://en.wikipedia.org/wiki/Extract_class"&gt;Extract to Class&lt;/a&gt;. If you can't avoid these nested If statements, at least keep them in one place.&lt;/i&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;If you're lucky, the state is atomic. In which case the object can only be in one state at a time. Finite State Machines (&lt;a href="http://en.wikipedia.org/wiki/Finite-state_machine"&gt;FSM&lt;/a&gt;'s)&amp;nbsp;are great way to manage atomic state. The Poor Man's FSM is the &lt;a href="http://en.wikipedia.org/wiki/Enumerated_type"&gt;Enum&lt;/a&gt;.&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;pre&gt;enum RegistrationState { Ready, EmailSent, Waiting, Approved, Error }&lt;/pre&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_Al595rN4OWo/TNP6V0SnmQI/AAAAAAAAAWA/hG9lun4V0no/s1600/StateCreepIllustrations1a.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_Al595rN4OWo/TNP6V0SnmQI/AAAAAAAAAWA/hG9lun4V0no/s1600/StateCreepIllustrations1a.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;This is usually followed by state transition statements sprinkled throughout your code. Every time you see a branch in your FSM, you should again see an If statement. It gets worse if you need to worry about multiple threads coming into module and attempting to change state. You can see from the diagram above that the Enum does nothing to tell you about valid or invalid transitions from one state to another. You have to read all the code to understand what is acceptable.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;b style="font-style: normal;"&gt;Recommendation: &lt;/b&gt;&lt;i&gt;PMFSM's are generally bad, but better than nested If's.&amp;nbsp;If you have anything beyond the most trivial PMFSM … Extract to Class. It's nice to keep your state transition logic and locking mechanisms in one place which is easy to test. &lt;/i&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;But the Poor Man's FSM is only good for state within a single instance of an object. When multiple objects (probably of the same type) need to coordinate you need something a little more industrial strength. &lt;/span&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;Consider two Employee's that need coordinate on an approval for pending purchases. At first blush you might think the state diagram for the process looks like this:&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://3.bp.blogspot.com/_Al595rN4OWo/TNP6WJoCngI/AAAAAAAAAWE/U5rjOwud5Io/s1600/StateCreepIllustrations2a.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/_Al595rN4OWo/TNP6WJoCngI/AAAAAAAAAWE/U5rjOwud5Io/s1600/StateCreepIllustrations2a.png" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;The PMFSM might look like this:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;pre&gt;enum PurchaseState { Ready, Review, Approve, Reject, SendEmail, PlaceOrder, Done}&lt;/pre&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;In reality there is a separation of state between both Employee's. The Role of the Employee in this particular FSM determines which states are applicable to each employee. Bob and Alice are both Employees, but Bob is the Requester and Alice is the Approver. So, keeping the state of the process in any one Employee instance is going to get ugly quickly. It will also limit the number of purchase requests that Bob can make concurrently to 1. &lt;/span&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;The real FSM might look something like this:&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://2.bp.blogspot.com/_Al595rN4OWo/TNP6WK6LR-I/AAAAAAAAAWI/CVUAub_Ao6g/s1600/StateCreepIllustrations3a.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="231" src="http://2.bp.blogspot.com/_Al595rN4OWo/TNP6WK6LR-I/AAAAAAAAAWI/CVUAub_Ao6g/s320/StateCreepIllustrations3a.png" width="320" /&gt;&lt;/a&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;We need to break this FSM out and away from the Employee and make them participants in the transitions of the FSM. &lt;a href="http://en.wikipedia.org/wiki/Petri_net"&gt;Petri-Nets&lt;/a&gt; (PN)&amp;nbsp;are excellent data structures for modeling these sorts of FSM. With a Petri-Net you can model concurrency, forks, joins, splits, merges and multiple running jobs … everything needed by most business applications.&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;PN's are the basis for most modern Business Process Modeling (&lt;a href="http://en.wikipedia.org/wiki/Business_process_modeling"&gt;BPM&lt;/a&gt;) &amp;nbsp;/ &lt;a href="http://en.wikipedia.org/wiki/Workflow"&gt;Workflow &lt;/a&gt;solutions such as &lt;a href="http://msdn.microsoft.com/en-us/netframework/aa663328.aspx"&gt;Windows Workflow Foundation&lt;/a&gt;, &lt;a href="http://jboss.org/jbpm"&gt;jBPM&lt;/a&gt;&amp;nbsp;and a multitude of others. If you live in a big stack like Java or .NET, these are valid options. We're also starting to see many BPM solutions becoming SaaS, so implementation language is becoming less of an issue.&amp;nbsp;&lt;/span&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;You'll find that for most business applications, having a good BPM solution in your toolkit will make your life so much easier. And you don't need a heavy-weight solution that has graphical editors, connectors and other bloat … just a simple Petri-net implementation will get you a long way to more maintainable code. You'll find one for nearly every language out there. &lt;/span&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;&lt;b&gt;Recommendation&lt;/b&gt;&lt;/span&gt;&lt;span style="font-style: normal;"&gt;: When you have complex state interactions between multiple objects, consider using a Petri-net based library to keep your code manageable. &lt;/span&gt; &lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="margin-bottom: 0in;"&gt;&lt;span style="font-style: normal;"&gt;To summarize, state is a nasty thing in your code. Always be aware of it and be vigilant to keeping it under control. Hopefully some of the tips I've listed in this article will make that process easier. &amp;nbsp;&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/8696186-836637523698285828?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/836637523698285828/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=836637523698285828' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/836637523698285828'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/836637523698285828'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2010/11/state-creep.html' title='State Creep'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_Al595rN4OWo/TNP6V0SnmQI/AAAAAAAAAWA/hG9lun4V0no/s72-c/StateCreepIllustrations1a.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-8646336683142336096</id><published>2010-10-20T11:46:00.002-03:00</published><updated>2010-10-20T11:57:36.215-03:00</updated><title type='text'>Removing "Configuration Flag" Code ...</title><content type='html'>I had the pleasure of working on some code with &lt;a href="http://twitter.com/#!/EdLeafe"&gt;@edleafe&lt;/a&gt; recently. It was a change in some existing functionality. This change could be turned from "old way" to "new way" with a configuration flag, which is pretty normal practice and encouraged.&lt;br /&gt;&lt;br /&gt;The issue with "Configuration Code" is that after a while you have two blocks of code that you have to maintain. One for the old way, one for the new way. And, hopefully, there are tests around the old code and the new code.&lt;br /&gt;&lt;br /&gt;What has always bothered me that once the flag gets set and its state&amp;nbsp;stabilizes,&amp;nbsp;the old code should be ripped out and the flag removed. The reality is, this never seems to happen. When was the last time you grep'ed for TODO? So you end up with these Conditional Code blocks all over the place. It's worse when your flag touches many parts of the code.&lt;br /&gt;&lt;br /&gt;Ed had a great idea. Add a ticket to your bug tracker to remove the conditional code and the flag. Product management can review the bug from time to time and determine when the flag is no longer needed. It becomes a thorn in everyone's side until it gets removed.&lt;br /&gt;&lt;br /&gt;Simple solution and maybe it's common practice, but I had never considered or heard of it before. I like it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8696186-8646336683142336096?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/8646336683142336096/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=8646336683142336096' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/8646336683142336096'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/8646336683142336096'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2010/10/removing-configuration-flag-code.html' title='Removing &quot;Configuration Flag&quot; Code ...'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-752759551300762635</id><published>2010-10-17T13:59:00.001-03:00</published><updated>2010-10-17T14:12:25.538-03:00</updated><title type='text'>The Joy of Getting Cardinality Assumptions Wrong ...</title><content type='html'>(Sorry for the infrequent posts as of late ... just getting back into it. Lots of new fuel to write about. This is just a little note to prime the pump again.)&lt;br /&gt;&lt;br /&gt;As a developer, I find that some of the biggest code changes arise when my assumptions of "how many" of something I can expect are wrong.&lt;br /&gt;&lt;br /&gt;I thought there would only be 1 when there are going to be N items.&lt;br /&gt;I thought there would be N when there are going to be N&lt;sup&gt;2&amp;nbsp;&lt;/sup&gt;items.&lt;br /&gt;I thought there would be N&lt;sup&gt;2&lt;/sup&gt;&amp;nbsp;when there are going to be 2&lt;sup&gt;N&lt;/sup&gt; items.&lt;br /&gt;Or, I just guessed N wrong.&lt;br /&gt;&lt;br /&gt;Each change in magnitude calls for a radical change in architecture. You have to go from a single variable to data structure, or from a list to a tree or from a tree to a database or from a single database to a partitioned database. Everything changes. Often, the clients of the code break because the access mechanisms change. They don't get back a single item, they get a list. They can't get all the items in a single query, but have to page the results, they have to give better qualified queries, etc.&lt;br /&gt;&lt;br /&gt;User Interface is perhaps affected the most by these changes. Going from showing 1 result to N results is a big change. When N gets beyond a manageable number you start thinking about trees ... more UI changes. If N is too large for a tree you start thinking about tagging/search mechanisms. The UI changes again.&lt;br /&gt;&lt;br /&gt;Big development costs.&lt;br /&gt;&lt;br /&gt;The multi-tenant problem is a good example of getting bitten by these assumptions. You assume you're going to have one customer per installation of your code. But then you evolve into a hosted application so one installation has many customers and no customer can see another customer. Then you support resellers, so a customer is not an end-customer, but a meta-customer than has many sub-customers. The reseller can see all of their clients, but no client can see each other. Ugh. These sorts of changes hurt. They usually take considerable time to implement and it's tough to get right.&lt;br /&gt;&lt;br /&gt;So, when you are talking to your customers (or prospective customers), really try to get to get a sense for the cardinality of the things they talk about. Think about how big a change your code will undergo if you had to move from "one of these" to "N of these". Ask them explicitly "How many of these can you foresee?"&lt;br /&gt;&lt;br /&gt;Personally I think these sorts of design problems are so painful that I'm willing to violate &lt;a href="http://www.xprogramming.com/Practices/PracNotNeed.html"&gt;YAGNI&lt;/a&gt; and opt for the larger data structure.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8696186-752759551300762635?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/752759551300762635/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=752759551300762635' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/752759551300762635'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/752759551300762635'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2010/10/joy-of-getting-cardinality-assumptions.html' title='The Joy of Getting Cardinality Assumptions Wrong ...'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-2409559956902981610</id><published>2010-07-06T11:31:00.001-03:00</published><updated>2010-07-06T11:44:41.597-03:00</updated><title type='text'>Bug Triage &amp; Backlogs ... Unseen Broken Windows</title><content type='html'>Bug reviews are a necessary evil. Your application is out in the wild and,&amp;nbsp;inevitably, bugs will be found. If you're busy working on other things, these bugs usually get stuffed in the bug tracking system for later review. At some point you will sit down with all the product stakeholders and decide what sort of priority to put on these bugs. Everyone needs to agree which bugs are going to get fixed and which are going to get deferred.&lt;br /&gt;&lt;br /&gt;As a developer, this is generally "yet another meeting". We show up. We give our thoughts on the bugs. Is this one difficult to fix or can you fix it during the meeting (kidding)? We don't assign priorities ... that's generally the job of the product owners. The product owner might be a direct customer or it could be an abstracted customer like a product manager or the sales team (the Customer Proxy in Agile parlance). We just throw in our $0.02&lt;br /&gt;&lt;br /&gt;Now the real show begins. Sales flips out because this bug or feature request is holding up revenue. Product management may veto a ranking because of a more strategic matter. Marketing will scream that the competitors can make a Square Circle and that our product needs one too. There are feats of strength, ruffling of plumage, bun fights and&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Kiva"&gt;kiva&lt;/a&gt; sits until eventually the bug list is placed in an ordered fashion. Bugs are ranked in some &lt;a href="http://fogcreek.com/FogBugz/KB/howto/Priorityvs.Severity.html"&gt;Priority and Severity&lt;/a&gt; such as &lt;a href="http://trac.edgewall.org/wiki/TracTickets"&gt;Blocker, Critical, Major, Minor or Trivial&lt;/a&gt; / &lt;a href="https://wiki.mozilla.org/Bugzilla:Priority_System"&gt;number codes&lt;/a&gt; / whatever. If you're really lucky, some bugs will be removed from the list as being no longer relevant or already fixed.&lt;br /&gt;&lt;br /&gt;Then it's our job. Development will do whatever sort of &lt;a href="http://www.planningpoker.com/"&gt;voodoo&lt;/a&gt; it needs to do to estimate, assign and work on these tasks. &amp;nbsp;A new release is issued and the process repeats. Ideally the cycle time between bug review and product release is &lt;a href="http://en.wikipedia.org/wiki/Iterative_and_incremental_development"&gt;suitably short&lt;/a&gt; so that the bug rankings don't shift too much. No real magic here.&lt;br /&gt;&lt;br /&gt;And, as we all know and every Agile pundit will evangelize, the priorities &lt;i&gt;will &lt;/i&gt;shift.&lt;br /&gt;&lt;br /&gt;If you get your priorities from Sales, your priorities will shift on a near-daily basis. The hottest customer will get the most attention. Depending on the length of your sales cycle, don't plan on taking on any&amp;nbsp;ambitious&amp;nbsp;new features or refactorings because you're likely to get pulled in a new direction tomorrow. One thing I like about having a good product manager to work with is they can temper the rapid mood swings of sales people and boil them down to a common theme or essence.&lt;br /&gt;&lt;br /&gt;Regardless ...&lt;b&gt;&lt;i&gt; &lt;span class="Apple-style-span" style="font-weight: normal;"&gt;not all of the bugs can get fixed&lt;/span&gt;&lt;/i&gt;&lt;/b&gt;. You build up a &lt;a href="http://blog.mountaingoatsoftware.com/bugs-on-the-product-backlog"&gt;bug backlog&lt;/a&gt;. After a while, in an attempt to keep the meeting short, you stop reviewing the Minor or Trivial bugs and just focus on Blockers and Criticals. After a longer period of time, you can't &lt;a href="http://webcache.googleusercontent.com/search?q=cache:_95_eQYrIiwJ:www.eecs.berkeley.edu/~jalbert/slides/dsn08.ppt+bug+tracker+duplicate&amp;amp;cd=10&amp;amp;hl=en&amp;amp;ct=clnk&amp;amp;gl=ca"&gt;manage the duplicates&lt;/a&gt; anymore so the list grows even longer. It's a &lt;a href="http://pragprog.com/the-pragmatic-programmer/extracts/software-entropy"&gt;Broken Window&lt;/a&gt;. Because of the organizations inability to effectively manage these bugs the overall effect to the end-user is a rash of problems that are simply never addressed. Your application is dying and you can't prevent it.&lt;br /&gt;&lt;br /&gt;Here's the real kicker:&amp;nbsp;&lt;i&gt;it may have nothing to do with the quality of the code or the process&lt;/i&gt;&lt;b&gt;.&lt;/b&gt; Your code could be clean and readable, but simply because of market forces there is an unmanageable backlog. What can you do?!&lt;br /&gt;&lt;br /&gt;It's a hard problem, but here are some suggestions I would make to help get you back on track:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Group your bugs and look for architectural commonality.&lt;br /&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;You may notice that large collections of bugs stem from a common architectural place in the code. It may not be obvious at first. In a separate worksheet, try and group your bugs by software sub-modules and look for alternative approaches that might kill many bugs in one swat. You may find that cutting off an arm will save the body.&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Freeze all new feature development and do Bug Sprints&lt;br /&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;Push back on new feature requests or enhancements. Use all of your political powers to rally support about the importance of getting the bug list reduced. Try alternating Bug Sprints between normal iterations in an attempt to get the bug count down.&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Remove functionality&lt;br /&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;This is often not as hard as it sounds. Is the bug related to a legacy feature? How many customers will be affected if that feature is no longer there? Can they live with a work-around? Removing lesser-used functionality means less code. Less code means happier developers.&amp;nbsp;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Shore up your tests&lt;/b&gt;&lt;br /&gt;Are you lacking some critical code coverage in your unit or functional tests? How many of these bugs could have been eliminated with better tests?&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Hire a usability expert&lt;/b&gt;&lt;br /&gt;Are the bugs related to confusing UI, complicated configuration steps or poor documentation? Could the product benefit from a usability review? Your product might be stable, but due to poor usability you are seeing a high number of bug reports?&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Replace third-party components (or start using them)&lt;/b&gt;&lt;br /&gt;Do your bugs stem from a flaky piece of third party code? Can you replace it? Alternatively, do your bugs come from a piece of code that was developed in-house but can now be replaced by an off-the-shelf alternative?&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Start hiring or Split the Team&lt;/b&gt;&lt;br /&gt;Perhaps your growing bug list is a symptom of not enough resources? Should your company make the investment in another developer to help share the load? If so, can you ensure that they won't be used by the Customer as a means of slamming even more functionality into the product? If not, consider splitting the team so that the Customer deals with one group just for new functionality and the other group just for bug triage and repair. Balance the size of the teams according to how dire your situation is.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;And then ...&lt;/b&gt;&lt;br /&gt;... &lt;i&gt;fight tooth and nail to keep the bug count at zero&lt;/i&gt;. Always fix bugs first. You will get incredible pressure from sales to sweep them under the rug and some bugs can be notoriously difficult to find. Ask for help. Hire a highly skilled consultant to help you fix the bug if need be. But try to keep the bug count to zero or these Backlog Broken Windows may kill your productivity (if not your product).&lt;br /&gt;&lt;br /&gt;Next time, I'll try to give some of my thoughts on how Kanban may or may not be able to help with this problem. Until then, I look forward to your thoughts.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8696186-2409559956902981610?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/2409559956902981610/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=2409559956902981610' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/2409559956902981610'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/2409559956902981610'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2010/07/bug-triage-backlogs-unseen-broken.html' title='Bug Triage &amp; Backlogs ... Unseen Broken Windows'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-4046081268843574011</id><published>2010-06-29T10:10:00.003-03:00</published><updated>2010-06-29T10:15:52.572-03:00</updated><title type='text'>The Problem with Java and C# ...</title><content type='html'>I'm going to stick with saying "Java" in this article, but the same argument applies to C# as well. Replace accordingly.&lt;br /&gt;&lt;br /&gt;There seems to be a lot of &lt;a href="http://news.ycombinator.com/item?id=285066"&gt;bad sentiment&lt;/a&gt; aimed at Java these days. Either complaining about the verbosity of the language, the bloat of the surrounding tools or the &lt;a href="http://news.ycombinator.com/item?id=1463592"&gt;mentality of the developers&lt;/a&gt; that use it. Other articles seems to talk about how rapidly that community is &lt;a href="http://news.ycombinator.com/item?id=1378815"&gt;shrinking&lt;/a&gt; or the &lt;a href="http://john.freml.in/scala-is-not-a-better-java"&gt;futility of the innovation&lt;/a&gt; in the community.&lt;br /&gt;&lt;br /&gt;The problem with Java is not the language, it's the hiring mentality that goes behind it.&lt;br /&gt;&lt;br /&gt;When companies decide to play in the "enterprise" space, they feel they need to use programming languages that best fit with those environments. This usually means Java. This is nonsense. Facebook, Twitter, Google and other hot new companies have incredibly scalable architectures, many without SQL, LDAP and Application Servers. We know there are other/better ways to solve the scalability problem. Also, you have&amp;nbsp;compatibility&amp;nbsp;with legacy systems without requiring an Oracle Application Server. If you need to have an army of Operations people to tune your app server, you might want to reconsider your architecture.&lt;br /&gt;&lt;br /&gt;Another factor in this rationalization is the ability to hire from a wider gene-pool of developers. There are certainly more Java developers out there than nearly any other programming language. When hiring a Java developer many of these companies hire tactical skills, not general skills. Do you know Struts, JSF, Hibernate, Websphere, etc.?&amp;nbsp;And I can understand why. If you build a product that is going to have a long life-cycle, you have to assume the software is going to have to live beyond the developers that assembled it. If the application is written on niche or trendy languages or tools it will be harder to replace these developers later.&lt;br /&gt;&lt;br /&gt;This is broken thinking.&lt;br /&gt;&lt;br /&gt;People will do what you reward. If you reward blindly learning software packages without understanding what their benefits and limitations are you will end up with a development team full of automatons. If you reward understanding computer science fundamentals, the best tool for the job, code simplicity and readability you will end up with a better software product and it will take less developers to build / maintain it.&lt;br /&gt;&lt;br /&gt;And don't read this the wrong way. I'm not implying that all Java developers are sheep. There are many, many awe-inspiring Java developers out there. Sadly, there are far more sheep.&lt;br /&gt;&lt;br /&gt;Can you blame the developer? No. The common sentiment is "If I stick with Java, I'll have a job." ... and it's mostly true. This is usually followed by "Do I like my job? Meh."&lt;br /&gt;&lt;br /&gt;Yes, it is harder to hire these sorts of developers. Your interview process will be lengthy. You will eliminate more candidates. But do you want to work in a brain shop or a body shop? Which is harder: reading clean understandable code in a new language or reading verbose bloat code in an understood language? Which is easier: reading a new DSL or pages of XML?&lt;br /&gt;&lt;br /&gt;What is the impact of developer farms that are hired for tactical skill sets instead of core understanding and passion? An uninspired workspace. A breeding ground for "[Flavor-of-the-Day]&lt;flavor day="" of="" the=""&gt;&amp;nbsp;Coaches" who feed off the malaise of the corporation. "Certified [SilverBullet]&amp;nbsp;&lt;silverbullet&gt;Masters". Higher turnover. More developers pounding in Feature X, Y &amp;amp; Z without a care for the big picture.&amp;nbsp;&lt;/silverbullet&gt;&lt;/flavor&gt;&lt;br /&gt;&lt;br /&gt;Let's not throw out the baby with the bathwater. Don't diss the language. Diss the companies that foster this lousy work environment on us developers. Developers, work on your core skills. Don't let yourself fall into the "must master the Java stack" trap. Learn other languages and see how they tackle the problems. Look under the hood at how the libraries you use today work and what the alternatives are. Learn new API's, but then learn their implementations. Review your algorithm books and decide if there are better ways to solve the problem.&lt;br /&gt;&lt;br /&gt;Don't go wide, go deep and don't work for body shops.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8696186-4046081268843574011?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/4046081268843574011/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=4046081268843574011' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/4046081268843574011'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/4046081268843574011'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2010/06/problem-with-java-and-c.html' title='The Problem with Java and C# ...'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-3537196245819891390</id><published>2010-06-07T09:08:00.000-03:00</published><updated>2010-06-07T09:08:32.492-03:00</updated><title type='text'>Should You Always Explain Why?</title><content type='html'>When mentoring apprentice software craftsman there are times when rationale gets lost. You are trying to teach them &lt;i&gt;caution&lt;/i&gt;. Caution means slowing down and being attentive to your surroundings so you don't do something dangerous. But if they never get hurt can they really understand why they should be cautious?&lt;br /&gt;&lt;br /&gt;It's different with children. You don't want them to use the stove or run with scissors because the cost of not being cautious is too high. But you let them spin around like a top until they fall down, potentially getting a bop in the head. You let them have a pillow fight, knowing that someone is going to come screaming in a few minutes. Why? Because when they get hurt they learn a valuable lesson.&lt;br /&gt;&lt;br /&gt;In software, how do you gauge what is an acceptable risk? I remember several years ago working with a group of junior developers and getting them to write unit tests. I was a broken record: "You have to write your tests." "Did you write your tests?" "You can't refactor without tests." "Did you run the tests before checking in?" "Did you run the tests as soon as you checked out?" ... but they had never &lt;i&gt;really&lt;/i&gt; felt the pain of not having tests or dealing with poorly written tests. It was nearly three years later when one of the developers came to me and said "You know I finally get this unit testing thing now. I just did it before because we were told to, but I never really understood why. Now I do." Almost instantly, all the light bulbs went on for him. Short iterations, the importance of enforcing a coding style, the use of Fakes &amp;amp; Mocks ... it was easy to see he was no longer a junior developer. Testing was a part of his craft now.&lt;br /&gt;&lt;br /&gt;Is there anything more I could have said to make this more evident? Probably. But I think the words would have been lost or come across as more preachy than it always was. He needed to feel the pain for himself to learn.&lt;br /&gt;&lt;br /&gt;But ... as a manager, could we afford to have developers &lt;i&gt;not&lt;/i&gt;&amp;nbsp;doing tests for three years? &lt;i&gt;not&lt;/i&gt;&amp;nbsp;complying to the coding standard for three years?&lt;i&gt;&amp;nbsp;&lt;/i&gt;No. We had felt the pain. We know what the costs of not doing that stuff is. I'm sure many of the tests written during his&amp;nbsp;journeyman-ship&amp;nbsp;weren't very good ... but they were building muscle memory. I'm sure many master carpenters, glassblowers and potters do things by rote for a long time before really understanding the&amp;nbsp;subtlety&amp;nbsp;of their actions.&lt;br /&gt;&lt;br /&gt;Being a mentor, just as being a parent, you have to make the hard decisions of when your charges are really going to hurt themselves and when it's&amp;nbsp;ok for them&amp;nbsp;to take a smack in the head. And, often times, explaining why beforehand gives no benefit.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;object height="385" width="480"&gt;&lt;param name="movie" value="http://www.youtube.com/v/8aYl7N0JPWs&amp;hl=en_US&amp;fs=1&amp;"&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/8aYl7N0JPWs&amp;hl=en_US&amp;fs=1&amp;" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="385"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8696186-3537196245819891390?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/3537196245819891390/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=3537196245819891390' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/3537196245819891390'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/3537196245819891390'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2010/06/should-you-always-explain-why.html' title='Should You Always Explain Why?'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-4820343310554148841</id><published>2010-06-04T10:25:00.003-03:00</published><updated>2010-06-04T10:36:08.110-03:00</updated><title type='text'>How long can you work on a programming team before things get stale?</title><content type='html'>Assuming it involves lots of new learning initially, my gut tells me it's about 1-2 years. Once a developer understands the problem well enough they can start to get antsy.&lt;br /&gt;&lt;br /&gt;I have a theory that 3yrs is the maximum amount of time a programmer can work in a given problem space before things get routine. It doesn't have much to do with your team or the company ... it's the challenge. The rest is an "exercise left for the reader."&lt;br /&gt;&lt;br /&gt;Certainly there are exceptions. People can last longer but, to me, it seems generally they become ghosts in the machine. All the good programmers will tell you the same thing: "program on the side", "learn a new language", "experiment with an API", "moonlight".&lt;br /&gt;&lt;br /&gt;But are your extra-curricular activities aligned with those who write you a check? A recent trend is for programmers to be let go for "not being &lt;a href="http://gmj.gallup.com/content/142/Start-Worrying-About-Not-Engaged-Employees.aspx"&gt;engaged&lt;/a&gt;" ... that's scary.&lt;br /&gt;&lt;br /&gt;Or, are you one of the really lucky ones? Is your work so in-depth and challenging that you constantly have to research new techniques to solve them ... and you are given the time to do so?&lt;br /&gt;&lt;br /&gt;I think the quote on &lt;a href="http://sebastianlab.com/post/466961025/so-when-you-hear-people-say-that-change-is-hard"&gt;"Beards and Keyboards" regarding Change&lt;/a&gt;&amp;nbsp;says it best:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;So when you hear people say that change is hard because people are lazy or resistant, that’s just flat wrong. In fact, the opposite is true: Change is hard because people wear themselves out. And that’s the second surprise about change: What looks like laziness is often exhaustion.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;—&amp;nbsp;The first few pages of the book “Switch, how to change things when change is hard” are priceless. Get it! By Chip Heath &amp;amp; Dan Heath&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8696186-4820343310554148841?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/4820343310554148841/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=4820343310554148841' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/4820343310554148841'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/4820343310554148841'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2010/06/how-long-can-you-work-on-programming.html' title='How long can you work on a programming team before things get stale?'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-359405223822262526</id><published>2010-05-18T09:53:00.000-03:00</published><updated>2010-05-18T09:53:57.661-03:00</updated><title type='text'>Packaging a Django Application as a Stand-alone Application</title><content type='html'>Here is a little diversion from my normal Software Craftsmanship ramblings.&amp;nbsp;Recently, I needed to package a &lt;a href="http://www.djangoproject.com/"&gt;Django&lt;/a&gt; web app as a stand-alone Windows Application with an installer (see below for the rationale)&lt;br /&gt;&lt;br /&gt;In order to make this work I needed to get around a few hurdles:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Since I'm using Django, I didn't want to customer to have to install &lt;a href="http://www.python.org/"&gt;Python&lt;/a&gt;, so I needed to turn the Python&amp;nbsp;code into an .exe. &lt;a href="http://www.py2exe.org/"&gt;Py2exe&lt;/a&gt; is great for this.&lt;/li&gt;&lt;li&gt;I also use a bunch of other python libraries such as &lt;a href="http://rpyc.wikidot.com/"&gt;rpyc&lt;/a&gt;, Python Win32 extensions and have a bunch of custom C++ components&amp;nbsp;that interface with Python via &lt;a href="http://www.swig.org/"&gt;Swig&lt;/a&gt;. These all needed to get wrapped up and included as well.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;I didn't want the customer to have to deal with installing each of these components and sewing them together. Assume no IT person is available. I also didn't want to show the&amp;nbsp;installer spawning off all these other sub-installers.&amp;nbsp;It needs to install and appear in the menus like every other Windows application.&lt;br /&gt;&lt;br /&gt;"Well", I thought, "best get started. Let's get py2exe running on manage.py (the django project startup utility)&amp;nbsp;and make a .exe out of it." &lt;i&gt;And that's when the fight started.&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Django does some funky magic with imports under the hood that breaks the component discovery mechanism of py2exe.&amp;nbsp;The first thing I needed to do was eliminate manage.py. There were a couple of &lt;a href="http://www.danomagnum.com/wiki/py2exe%20and%20django"&gt;good&lt;/a&gt; blog &lt;a href="http://woobiz.com.ar/en/articles/django-and-py2exe-replacing-desktop-with-intranet-applications"&gt;posts&lt;/a&gt; that talk about&amp;nbsp;this very problem. The trick is mapping your inside and outside directories so you can keep your database and template files outside of the package that py2exe fabricates.&lt;br /&gt;&lt;br /&gt;Following their lead, I had a bootstrap program I could use to launch my application as an executable. All I had to&amp;nbsp;do then was throw an install script around it with &lt;a href="http://www.jrsoftware.org/isinfo.php"&gt;InnoSetup&lt;/a&gt;&amp;nbsp;we were off to&amp;nbsp;the races.&lt;br /&gt;&lt;br /&gt;Then there was Part Two: I had my daemon process that did the network monitoring. This was also Python and used the rpyc library to communicate with the Django server. It also talked to a bunch of C++ programs that&amp;nbsp;were python-wrappered using Swig, so it was .dll hell. This was going to be my other .exe.&lt;br /&gt;&lt;br /&gt;Py2exe normally does a great job of dealing with .pyd files (&lt;a href="http://pyfaq.infogami.com/is-a-pyd-file-the-same-as-a-dll"&gt;essentially Python extension dll's&lt;/a&gt;), but it has no&amp;nbsp;way of knowing when a .pyd references a .dll which may reference many other dll's since they are loaded&amp;nbsp;dynamically at runtime ... as their name suggests. The result was a crashing application in my test VM.&lt;br /&gt;&lt;br /&gt;In order&amp;nbsp;to track down all the dll dependencies I used &lt;a href="http://www.dependencywalker.com/"&gt;Dependency Walker&lt;/a&gt;&amp;nbsp;to see which&amp;nbsp;dll's were being accessed and which were failing. By using the "Profiling" option, you are able to see when a&amp;nbsp;&lt;a href="http://msdn.microsoft.com/en-us/library/ms684175(VS.85).aspx"&gt;LoadLibrary&lt;/a&gt; call is made and where it fails.&lt;br /&gt;&lt;br /&gt;Happy to say ... it works like a charm.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Why do this?&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;This is an experiment. There's a part of me that likes the idea of packaging a web-application as a standalone&amp;nbsp;application. While this is only applicable to certain class of applications, using a &lt;a href="http://djangoapi.quamquam.org/trunk/django.core.servers.basehttp-module.html"&gt;lightweight HTTP server&lt;/a&gt; and a&amp;nbsp;tiny database like &lt;a href="http://www.sqlite.org/"&gt;SqlLite&lt;/a&gt; to deploy is pretty sweet. Why? A browser is a familiar experience and it's &lt;i&gt;way&lt;/i&gt; faster&amp;nbsp;to write UI for web than GUI frameworks. People are familiar with web UI semantics. They know what happens when&amp;nbsp;you close a browser window, when you hit the refresh or back buttons, when you click on a link. GUI products&amp;nbsp;require new learning. Most of the users work day is in a browser. Why make them switch context to another tool?&lt;br /&gt;&lt;br /&gt;I can hear you now "Why not just make it Software as a Service (&lt;a href="http://en.wikipedia.org/wiki/Software_as_a_service"&gt;SaaS&lt;/a&gt;) like everyone else?"&lt;br /&gt;&lt;br /&gt;Normally I would. 99.9% of the time SaaS is the way to go. But for this application I need to have a continuously&amp;nbsp;running process (which listens on the internal network) while the user interface is running. I could still do this&amp;nbsp;with Saas, but it would require people trusting to install the daemon process inside their network and let it call&amp;nbsp;home. And, for our customers, often times their production network does not have access to the WAN.&lt;br /&gt;&lt;br /&gt;Down the road, they can buy a SaaS version if we deem the product worthy of that effort, or upgrade to more robust components. But for now, it's an easy way&amp;nbsp;to get started. And their entire team can try the application without every having to install it and futz with&amp;nbsp;networking. This also falls into the "&lt;a href="http://catb.org/esr/writings/homesteading/cathedral-bazaar/ar01s04.html"&gt;release early, release often&lt;/a&gt;" camp of product development. I need to get&amp;nbsp;feedback from our early adopter customers and this is a simple way to get started.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;Moreover, look at all the other tools I can integrate with a simple link: I'm using&amp;nbsp;&lt;a href="https://uservoice.com/"&gt;UserVoice&lt;/a&gt;&amp;nbsp;to capture customer feedback and &lt;a href="http://jquery.com/"&gt;jquery&lt;/a&gt; for some nice UI. I can use &lt;a href="http://www.google.com/analytics/"&gt;Google Analytics&lt;/a&gt; to see usage patterns. There is so much more I can do with a local website than is remotely available to a conventional fat-app. I can easily put a&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Representational_State_Transfer"&gt;REST&lt;/a&gt;&amp;nbsp;API on the product if need be and online help is a simple addition.&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;br /&gt;The obvious issue, in the short term, is that someone needs to remember to launch the server before hitting the web page. This could&amp;nbsp;be an issue. There's also no name resolution for the person that installed the application. It's essentially a&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Localhost"&gt;localhost&lt;/a&gt; website. And, there are known security issues with this particular http server. I may need to use something a little more secure soon ... but still lightweight.&amp;nbsp;We don't always want to notify the IT department, get new databases created, add new modules to the&amp;nbsp;application server. This, to me, is a middle ground ... well, at least I hope so. I may regret those words.&lt;br /&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;&lt;br /&gt;&lt;/div&gt;I'll let you know later how this experiment goes.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8696186-359405223822262526?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/359405223822262526/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=359405223822262526' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/359405223822262526'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/359405223822262526'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2010/05/packaging-django-application-as-stand.html' title='Packaging a Django Application as a Stand-alone Application'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-7413625740588008304</id><published>2010-04-21T22:53:00.006-03:00</published><updated>2010-04-22T11:00:09.351-03:00</updated><title type='text'>The new Facebook features and how they affect your privacy ...</title><content type='html'>This isn't a note for you geeks, it's for my friends that aren't geeks and use Facebook.&lt;br /&gt;----&lt;br /&gt;&lt;br /&gt;I know many of you don't follow this stuff, so here's the Readers Digest summary of the new Facebook changes made recently, what you can do with it and how private your actions are.&lt;br /&gt;&lt;br /&gt;As of today, if you visit sites like CNN or IMDB you can now "Like" or "Recommend" articles, products, movies, etc. directly from their site. If you do, these actions show up on your Profile (under Info | Pages) and cannot be filtered with your privacy settings.&lt;br /&gt;&lt;br /&gt;The only way to remove it is to go back to that page and un-like or un-recommend it. You can't remove it from within Facebook.&lt;br /&gt;&lt;br /&gt;This means that any person or application can see your Likes and Recommendations. This could be an issue if you "Like" the Marijuana Party or similar fiery topics. Everyone who sees your profile will see this stuff, even if they're not your friend! And, anyone outside Facebook can see ALL the people that endorse that thing too. You've just published personal stuff outside the gates of Facebook. Be aware.&lt;br /&gt;&lt;br /&gt;Also announced today, non-Facebook applications (like Mafiawars, quizzes, Scrabble, etc.) do NOT have to delete their copies of your personal data any more. Previously they could only keep it 24 hours and we all hoped they were honest.&lt;br /&gt;&lt;br /&gt;So, don't Like or Recommend something that could get you in trouble now or 10 years down the road (especially you crazy kids in university). The web never forgets. And don't install those stupid applications. You have no idea who runs these things and what they are doing with your personal data.&lt;br /&gt;&lt;br /&gt;Edit: Thanks for question from &lt;a href="http://twitter.com/BradFraser"&gt;@BradFraser&lt;/a&gt;. "Can you turn it off?" ... No, you can't turn it off, unless you log out whenever you leave FB. This also means that simply by looking at an "enabled" external page Facebook knows it. There is a new privacy option under "Privacy | Applications &amp;amp; Websites | Instant Personalization" that is enabled by default, you should turn it off so the site doesn't read your profile on visit. This can't stop Facebook however.&lt;br /&gt;&lt;br /&gt;Update: regarding my comment that "And, anyone outside Facebook can see ALL the people that endorse that thing too." You can turn this off by making sure "Privacy Settings | Profile Information | Likes and Interests" is not set to Everyone. I'm not sure if this will cover&amp;nbsp;Recommendations&amp;nbsp;too?&lt;br /&gt;&lt;br /&gt;Hope it helps!&lt;br /&gt;-Sandy&lt;br /&gt;&lt;br /&gt;PS&amp;gt; Geek postings will resume shortly.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8696186-7413625740588008304?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/7413625740588008304/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=7413625740588008304' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/7413625740588008304'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/7413625740588008304'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2010/04/new-facebook-features-and-how-they.html' title='The new Facebook features and how they affect your privacy ...'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-3699138525351020451</id><published>2010-04-09T14:40:00.001-03:00</published><updated>2010-04-09T16:05:43.456-03:00</updated><title type='text'>Am I a Bad Man for Naming my Classes after Patterns?</title><content type='html'>A couple of weeks ago a rather innocuous tweet from &lt;a href="http://natpryce.com/"&gt;Nat Pryce&lt;/a&gt; (&lt;a href="http://twitter.com/natpryce"&gt;@natpryce&lt;/a&gt;) flashed on my screen which read:&lt;br /&gt;&lt;blockquote&gt;“Pattern names should be obscene so that programmers will not be allowed to name classes after patterns.”&lt;/blockquote&gt;It was quickly picked up by the tweet-o-sphere as programmers from all over echoed the chant. But wait … I name my classes after patterns?! Was I committing some sort of programming &lt;i&gt;faux pas&lt;/i&gt;? For years, in discussions with other developers over design issues or implementation details, I would always try to reference the appropriate pattern where applicable. And these Pattern-based conversations inevitably made their way back into the code.&lt;br /&gt;&lt;blockquote&gt;“That server uses a Reactor Pattern so it's not going to perform as well on a multi-core machine. Perhaps you should consider one based on Leader-Follower?”&lt;/blockquote&gt;&lt;blockquote&gt;“Each instance of that class is going to occupy a lot of memory, but we need to cache the most popular ones. Would the Evictor Pattern be the best choice here?”&lt;/blockquote&gt;If you go back and look at the original &lt;a href="http://en.wikipedia.org/wiki/Design_patterns"&gt;GOF&lt;/a&gt;&amp;nbsp;book the rationale given for Patterns was based on a quote by &lt;a href="http://en.wikipedia.org/wiki/Christopher_Alexander"&gt;Christopher Alexander&lt;/a&gt; who, speaking of buildings and towns, said,&lt;br /&gt;&lt;blockquote&gt;"Each pattern describes a problem which occurs over and over again in our environment, and then describes the core of the solution to that problem, in such a way that you can use this solution a million times over, without ever doing it the same way twice"&lt;/blockquote&gt;Speaking in Patterns does something very important between programmers … it raises the level of the conversation. If I talk to another developer about a Strategy Pattern, I don't need to say “Create an interface and move the specific implementation for each way to lay out the nodes into each derivation of it. That way, if we can't lay out the nodes one way, we can just change that class and try another way. Get it?” If my colleague knows what a Strategy Pattern is, he'll just say “Yup, good idea.” (or "Are you insane?")&lt;br /&gt;&lt;br /&gt;I love whiteboards, but I don't need to write on them every day. That's where we would be without Patterns.&lt;br /&gt;&lt;br /&gt;When I name my classes with a Pattern name, I'm doing the same thing, I'm telling you how I'm attempting to solve a problem without requiring you to look into the nasty implementation details.&amp;nbsp;A comment on a class or interface definition is not the same thing. It's not going to follow everywhere the class or interface is referenced so the details get lost.&lt;br /&gt;&lt;br /&gt;If I see a package that has three classes: FooStrategyFactory, FooStrategy and FooState I have a very good idea what's going on in that module. I don't need to look at the code. &lt;br /&gt;&lt;br /&gt;This was the basis for my discussion with Nat when I asked “Why is this a bad thing?” We chatted back and forth (as best you can on Twitter) about my position and his first objection was “Why do you need to call it FooStrategy? If there is an Interface you can assume there are going to be more than one of them.”&lt;br /&gt;&lt;br /&gt;A good point.&amp;nbsp;Perhaps there is something to his argument, consider this developer conversation:&lt;br /&gt;&lt;br /&gt;“Oh, there are going to be several different ways to lay out those nodes in the graph?”&lt;br /&gt;“Yes, I'm going to switch between then using a Strategy Pattern.”&lt;br /&gt;&lt;br /&gt;And I set off to coding. I start with a LayoutStrategy interface and move down into the implementation definitions I may create concrete classes like LinearLayout, CircularLayout, SquareLayout. I will concede that you don't need to repeat the pattern name in these derived classes. There is no need to call them LinearLayoutStrategy, CircularLayoutStrategy, etc. because you'll see that in the class definition:&lt;br /&gt;&lt;blockquote&gt;interface LayoutStrategy ...&lt;/blockquote&gt;&lt;blockquote&gt;class LinearLayout implements LayoutStrategy …&lt;/blockquote&gt;And, in this scenario, you probably never should see these derived class names anyway. They are likely being instantiated from a Factory or being “injected” into some other class. A common calling scenario might look something like:&lt;br /&gt;&lt;blockquote&gt;LayoutStrategy layout = layout_strategy_factory.get_layout_strategy(“circular”);&lt;/blockquote&gt;&lt;blockquote&gt;renderer = new GraphRenderer(layout);&lt;/blockquote&gt;And, arguably, it's a little verbose. But, how does it look without the Pattern name in the class?&lt;br /&gt;&lt;blockquote&gt;Layout layout = layout_strategy_factory.get_layout_strategy(“circular”);&lt;/blockquote&gt;&lt;blockquote&gt;renderer = new GraphRenderer(layout);&lt;/blockquote&gt;That looks pretty vague to me. I can't infer how to interact with the class based on the name like I can with LayoutStrategy. How about we put the pattern in the instance variable?&lt;br /&gt;&lt;blockquote&gt;Layout layout_strategy = layout_strategy_factory.get_layout_strategy(“circular”);&lt;/blockquote&gt;&lt;blockquote&gt;renderer = new GraphRenderer(layout_strategy);&lt;/blockquote&gt;Uggh! Now the developer has to know what the implementation approach is in order to correctly name the local variable. No way.&lt;br /&gt;&lt;br /&gt;Personally I think the first snippet offers the most value. &lt;i&gt;But I find all of the above snippets equally useless.&lt;/i&gt; If I was a first time reader of that code, I wouldn't know if Layout objects should simply position the nodes or render them as well? What is the purpose of each class? I have a hint about their purpose and I have a good idea what's under the hood, but I have no idea about the separation of duties. &lt;br /&gt;&lt;br /&gt;And this seems to be one of Nat's concerns as well. Some other interesting points he mentioned related to this were:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;that classes should be named after their purpose and not their implementation, and&lt;/li&gt;&lt;li&gt;that every class applies and/or plays roles in many overlapping patterns. Picking just one for the name ignores all others.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;But I'm not sure I agree. I'm a big fan of the &lt;a href="http://en.wikipedia.org/wiki/Single_responsibility_principle"&gt;Single Responsibility Principle&lt;/a&gt;. That a class should do one thing and one thing only. If a class is implementing more than one Pattern it should be a &lt;a href="http://en.wikipedia.org/wiki/Composite_pattern"&gt;Composite &lt;/a&gt;of the separate functions. Perhaps his concern is that some programmers name a class after a Pattern and then the class ends up doing something different? Bait-and-Switch naming is a viable concern. But that's something that should be caught in a code review and not a reason for a blanket coding style guide such as “Don't Name Classes After Patterns”.&lt;br /&gt;&lt;br /&gt;Class Naming becomes an issue for two different groups of developers:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Consumers of the classes&lt;/li&gt;&lt;li&gt;Maintainers of the classes&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;And most frequently, these are different groups with different expectations from the class name. Knowing the Pattern a class follows helps both groups. If it's a Strategy, I'm going to look for a place where work occurs. If it's a Leader-Follower, I'm going to look for the event handler and the thread dispatcher. If it's a State object, I'm going to try and find the Finite State Machine and methods for transitioning between states. Those are important clues when you have to look at legacy code or use an API for the first time. I don't even need to read the docs to know what I'm looking for.&lt;br /&gt;&lt;br /&gt;So, the problem seems to be this:&lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;If the classes are granular enough, naming them after Patterns is useful since it provides an indication of &lt;span class="Apple-style-span" style="font-style: normal;"&gt;Behavior&lt;/span&gt;. But it is not expressive enough to convey &lt;span class="Apple-style-span" style="font-style: normal;"&gt;Purpose&lt;/span&gt; (in the context of the problem).&lt;/i&gt;&lt;/blockquote&gt;How can we name a class so as to convey behavior and purpose? I'm certain the wrong way would be to give classes names like LayoutButDoNotRenderStrategy and RenderNodesButDoNotPositionThem.&lt;br /&gt;&lt;br /&gt;But if the class is named after the behavior, perhaps the package/module names should convey purpose and context? &lt;b&gt;The package name describes what the Factory, Strategy and State objects are acting on.&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;In our toy example, we need the the GraphRenderer class to live in a package that screams “I draw stuff!” and the Layout classes live in a package that screams “I position stuff!”&amp;nbsp;Perhaps the following works:&lt;br /&gt;&lt;blockquote&gt;package Graph.Node.Placement;&lt;/blockquote&gt;&lt;blockquote&gt;class Factory;&lt;/blockquote&gt;&lt;blockquote&gt;interface Strategy;&lt;/blockquote&gt;and&lt;br /&gt;&lt;blockquote&gt;package Graph.Rendering;&lt;/blockquote&gt;&lt;blockquote&gt;class Renderer;&lt;/blockquote&gt;Our calling code now looks like:&lt;br /&gt;&lt;blockquote&gt;import Graph.Node.Placement.Factory;&lt;/blockquote&gt;&lt;blockquote&gt;import Graph.Node.Placement.Strategy;&lt;/blockquote&gt;&lt;blockquote&gt;import Graph.Rendering.Renderer;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;blockquote&gt;Factory strategies = new Factory(...);&lt;/blockquote&gt;&lt;blockquote&gt;Strategy layout = strategies.get_layout_strategy(“circular”);&lt;/blockquote&gt;&lt;blockquote&gt;renderer = new Renderer(layout);&lt;/blockquote&gt;Personally I find this more than a little sterile but immensely readable. If you want to make it like a hammer-to-the-head you could do:&lt;br /&gt;&lt;blockquote&gt;Factory strategies = new Graph.Node.Placement.Factory(...);&lt;/blockquote&gt;&lt;blockquote&gt;Strategy layout = strategies.get_layout_strategy(“circular”);&lt;/blockquote&gt;&lt;blockquote&gt;renderer = new Graph.Rendering.Renderer(layout);&lt;/blockquote&gt;Works for me. Am I still a bad man for my rationale? What am I missing here? What are some viable alternatives? What works for you? It would be interesting to try this experiment with other Patterns, but I think single implementation Patterns are the easy cases. Overall, it's a tricky topic and class/package naming is more Art than Science.&lt;br /&gt;&lt;br /&gt;Finally, some side notes:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;In order for any of this to work, your team needs to agree on the reference sources for their Patterns. If people start pulling Pattern names out of thin air the conversation doesn't benefit. For example, you could state that your project can only reference patterns from the &lt;a href="http://www.amazon.com/Design-Patterns-Elements-Reusable-Object-Oriented/dp/0201633612/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1270832893&amp;amp;sr=8-1"&gt;GOF&lt;/a&gt;, &lt;a href="http://www.amazon.com/Pattern-Oriented-Software-Architecture-Concurrent-Networked/dp/0471606952/ref=sr_1_2?ie=UTF8&amp;amp;s=books&amp;amp;qid=1270832928&amp;amp;sr=1-2"&gt;Pattern-Oriented Software Architecture Vol 2&lt;/a&gt; and &lt;a href="http://www.amazon.com/Core-Security-Patterns-Strategies-Management/dp/0131463071/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1270832950&amp;amp;sr=1-1"&gt;Core Security Patterns&lt;/a&gt;. At least then the developers have somewhere definitive to start their searches. (see my &lt;a href="http://sandywalsh.com/2010/02/your-code-is-other-team-member.html"&gt;previous article&lt;/a&gt;&amp;nbsp;on Coding Standards)&lt;/li&gt;&lt;li&gt;We do agree that calling things Manager is bad. But this is a simple problem to solve since there is no Manager Pattern. Did the developer mean Factory? Calling a class a Manager is a definite code smell and should be avoided.&lt;/li&gt;&lt;li&gt;Having Python as my weapon of choice for the last ten years it kills me to have to make all these verbose module definitions. But for projects of any meaningful size you need to be regimented in your code organization.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Look forward to your feedback in the comments!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8696186-3699138525351020451?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/3699138525351020451/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=3699138525351020451' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/3699138525351020451'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/3699138525351020451'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2010/04/am-i-bad-man-for-naming-my-classes.html' title='Am I a Bad Man for Naming my Classes after Patterns?'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-2653001539397416950</id><published>2010-03-16T13:18:00.002-03:00</published><updated>2010-03-16T14:40:30.570-03:00</updated><title type='text'>A Tip for Closed Source Software Houses: Hold off on giving Commit Access</title><content type='html'>In the preface of Kent Beck's fantastic "&lt;a href="http://www.amazon.com/Extreme-Programming-Explained-Embrace-Change/dp/0201616416"&gt;Extreme Programming Explained&lt;/a&gt;" book he spells out the core principles of XP:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;If code reviews are good, we'll review code all the time (pair&amp;nbsp;programming).&amp;nbsp;&lt;/li&gt;&lt;li&gt;If testing is good, everybody will test all the time (unit testing),&amp;nbsp;even the customers (functional testing).&amp;nbsp;&lt;/li&gt;&lt;li&gt;If design is good, we'll make it part of everybody's daily business&amp;nbsp;(refactoring).&amp;nbsp;&lt;/li&gt;&lt;li&gt;If simplicity is good, we'll always leave the system with the&amp;nbsp;simplest design that supports its current functionality (the&amp;nbsp;simplest thing that could possibly work).&amp;nbsp;&lt;/li&gt;&lt;li&gt;If architecture is important, everybody will work defining and&amp;nbsp;refining the architecture all the time (metaphor).&amp;nbsp;&lt;/li&gt;&lt;li&gt;If integration testing is important, then we'll integrate and test&amp;nbsp;several times a day (continuous integration).&amp;nbsp;&lt;/li&gt;&lt;li&gt;If short iterations are good, we'll make the iterations really,&amp;nbsp;really short—seconds and minutes and hours, not weeks and&amp;nbsp;months and years (the Planning Game).&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;As someone who is, not only a programmer, but responsible for making sure the correct products make it out the door on time, only three of these are &lt;i&gt;critically &lt;/i&gt;important to me:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;If code reviews are good, we'll review code all the time.&amp;nbsp;&lt;/li&gt;&lt;li&gt;If testing is good, everybody will test all the time.&lt;/li&gt;&lt;li&gt;If integration testing is important, then we'll integrate and test&amp;nbsp;several times a day&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;The others are important, but for different reasons and we'll touch on them later in this blog.&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The list is very similar to a story&amp;nbsp;Anthony Robbins tells in "&lt;a href="http://www.amazon.com/Awaken-Giant-Within-Immediate-Emotional/dp/0671791540"&gt;Awaken The Giant Within&lt;/a&gt;". Someone asked him "How do you become a great public speaker?" and he essentially said "Talk in public all the time". Poor testing and Integration are, without a doubt, the two things under our control that will make a software project go off the rails. Crappy code is the other. Test all the time. Integrate all the time. Read the code all the time. But how can you do this effectively? &lt;a href="http://en.wikipedia.org/wiki/Test-driven_development"&gt;TDD &lt;/a&gt;and &lt;a href="http://en.wikipedia.org/wiki/Continuous_integration"&gt;Continuous Integration&lt;/a&gt; are well solved problems. The real challenge is getting others to look at your code.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Many suggest&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Pair_programming"&gt;Peer Programming&lt;/a&gt;.&amp;nbsp;Most developers I know don't like it or can only handle it in small doses and management often have a hard time rationalizing it. Personally I'm not a fan. I find too much time is lost because the development thought process hasn't fully gelled yet. It's&amp;nbsp;gratuitous&amp;nbsp;programming. But the motivation is sound. In the Open Source world, &lt;a href="http://en.wikipedia.org/wiki/Linus'_Law"&gt;Linus' Law&lt;/a&gt; states "With Enough Eyeballs, All Bugs Are Shallow." We need to have visibility on our code and, I think, Eric Sink puts it most succinctly: "&lt;a href="http://www.ericsink.com/entries/Read_the_Diffs.html"&gt;Read the diffs!&lt;/a&gt;" This is a great way to read the code after the developer has had time to get their thoughts together. My issue is that it happens too late. Once the code is in the revision control system you have to make immediate decisions on how to rectify any problems you find during the review. Revert the code and repair or wait for the repair with broken windows in your source?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I prefer Jacob Kaplan-Moss's perspective on &lt;a href="http://jacobian.org/writing/commit-bits/"&gt;granting commit bits&lt;/a&gt; ... &lt;b&gt;don't&lt;/b&gt;. If lower level developers cannot perform commits it forces the higher-level developers (the ones trying to enforce the religion of the project) to review their code. They are looking for your use of &lt;a href="http://sandywalsh.com/2010/02/your-code-is-other-team-member.html"&gt;coding style&lt;/a&gt;, of &lt;a href="http://sandywalsh.com/2010/02/enforce-idioms-get-religion.html"&gt;enforced idioms&lt;/a&gt; and &lt;a href="http://sandywalsh.com/2010/02/self-documenting-code.html"&gt;documentation&lt;/a&gt;. If ... IF ... you can consistently code to the norms of the company THEN you are granted commit bits to the revision control system. You can then review other developers code, merge their patches and mentor them on what is important. So, I would make a slight variation to Eric's article and change it to "Read the Patches".&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For the corporate software houses that never let their source outside the door, you can still have the benefits of the open source world by making code review a mandatory part of your development process. No projectors, no print outs, no meeting rooms. Just turn off commit access. Right now ... how many people on your corporate development project should have their commit bits revoked?&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Revoke and Review is my new mantra.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8696186-2653001539397416950?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/2653001539397416950/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=2653001539397416950' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/2653001539397416950'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/2653001539397416950'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2010/03/tip-for-closed-source-software-houses.html' title='A Tip for Closed Source Software Houses: Hold off on giving Commit Access'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-8804806113612843711</id><published>2010-03-11T12:15:00.001-04:00</published><updated>2010-03-11T12:15:22.814-04:00</updated><title type='text'>How Do You Hire Software Developers?</title><content type='html'>I want to learn more about the s/w dev hiring practices used by software companies.&lt;br /&gt;&lt;br /&gt;When the time has come to bring a new body to the team, how do you execute that process?&lt;br /&gt;&lt;br /&gt;First, let's consider the job description ... do you write this up in an "ad" format? If so:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Does the hiring manager write the skills requirements?&lt;/li&gt;&lt;li&gt;Do you focus on tactical skills or fundamental skills (i.e. Joomla vs. core OOAD)&lt;/li&gt;&lt;li&gt;Can you give an example of how you separate your must-have and your nice-to-have skills?&lt;/li&gt;&lt;li&gt;Do you prefer a strictly business format or hyper / jumped-up / sell-sell-sell ad? Do you find it makes a difference?&lt;/li&gt;&lt;li&gt;Do you have any examples of great job ads you've seen, written or responded to?&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;With your fresh list of requirements, how do you get new resumes?&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;We just put an add in the 'Careers' section of our website and they appear&lt;/li&gt;&lt;li&gt;We put ad in traditional print media&lt;/li&gt;&lt;li&gt;We pay for ads on generic job websites&lt;/li&gt;&lt;li&gt;We pay for ads on IT-specific job websites&lt;/li&gt;&lt;li&gt;We pay for ads on Language or Technology-specific websites (django/php/etc.)&lt;/li&gt;&lt;li&gt;We attend job fairs&lt;/li&gt;&lt;li&gt;We promote through social media&lt;/li&gt;&lt;li&gt;We recruit from the open source community&lt;/li&gt;&lt;li&gt;We recruit from our open source community&lt;/li&gt;&lt;li&gt;We only use contractors&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Which gives the highest response rate? Which gives the best candidates?&lt;br /&gt;&lt;br /&gt;Now that you've got a stack of shiny new resumes and you've filtered out all the noise, what's next? Some people like to do a phone interview. For the purpose of this post, I'm not interested in communications skills, availability, salary expectations, previous employment red-flags ... I'm interested in how you test their technical ability over the phone. The phone can be a great way to get some high-level data on the candidate, including:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Some generic technical questions to weed out the weak ones.&lt;/li&gt;&lt;li&gt;Team dynamic questions about difficult interpersonal situations&lt;/li&gt;&lt;li&gt;Thinking process for debugging&lt;/li&gt;&lt;li&gt;Logic/lateral thinking tests&lt;/li&gt;&lt;li&gt;General understanding of algorithms or major systems&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Sometimes companies will ask the candidate to do a take-away programming quiz. This is a relatively simple programming challenge that most developers should be able to solve in a few hours. The intention is not to focus on ability to execute under pressure but, assuming you have have access to all your normal reference material and resources, does the candidate exhibit good code craftsmanship? Can they following a coding style guide? Do they have bad coding habits?&lt;br /&gt;&lt;br /&gt;Then do you bring them in for a face-to-face interrogation? If so, what is the agenda?&amp;nbsp;Is this a single person interview or do you take them through a gauntlet of technical and business interviews? Do you issue more "think on your feet" programming or logic problems?&lt;br /&gt;&lt;br /&gt;Do you think a take-away programming challenge gives better or worse results than a "think on your feet" test?&lt;br /&gt;&lt;br /&gt;What do you think of the Google/Facebook approach where the key to entry is to compete in their programming challenges before getting an interview?&lt;br /&gt;&lt;br /&gt;Ultimately ... &lt;b&gt;how do you hire developers? Is it working? Are you getting the best developers possible or getting stuck with duds? What would you change?&lt;/b&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8696186-8804806113612843711?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/8804806113612843711/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=8804806113612843711' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/8804806113612843711'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/8804806113612843711'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2010/03/how-do-you-hire-developers.html' title='How Do You Hire Software Developers?'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-2622291724178884648</id><published>2010-03-05T11:00:00.001-04:00</published><updated>2010-03-05T11:03:44.551-04:00</updated><title type='text'>Developer Skill Sets: There is no such thing as an Intermediate Software Developer ...</title><content type='html'>At every company I've worked, the performance reviews have been structured nearly the same way. Software developers are graded on perhaps five different traits:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;Technical skills &lt;/b&gt;- How well do you code?&lt;/li&gt;&lt;li&gt;&lt;b&gt;Debugging skills&lt;/b&gt; - How well can you do maintenance work?&lt;/li&gt;&lt;li&gt;&lt;b&gt;Communication skills&lt;/b&gt; - Can you write effective email, documentation and talk to your team?&lt;/li&gt;&lt;li&gt;&lt;b&gt;Business/Marketing awareness&lt;/b&gt; - How well do you know the market this company plays in and the competitors?&lt;/li&gt;&lt;li&gt;&lt;b&gt;Time management &lt;/b&gt;- Can you focus on the task at hand?&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;The weight applied to each category varied depending on the developers position of Junior, Intermediate or Senior, Team Lead, etc.&lt;br /&gt;&lt;br /&gt;While these are not bad, in the general sense, there are two very large buckets in the above list where a multitude of sins can occur: technical skills and debugging. Fine granularity is important to software developers when it comes to performance reviews. If you want a developer to exhibit great code craftsmanship, then you need to be explicit on what you value and reward. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;What Can We Do To Revitalize The Old Developers Performance Review?&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Let's look at the table stakes; skills every developer you hire should be able to exhibit&lt;i&gt; before you hire them!&lt;/i&gt; These are not skills you want to teach on the job:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;Solid core CS skills &lt;/b&gt;- algorithms, complexity, architecture, underpinnings, etc.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Operating system essentials &lt;/b&gt;- scripting, backup/restore, boot process, device management, remote access&lt;/li&gt;&lt;li&gt;&lt;b&gt;Programming as a passion&lt;/b&gt;&amp;nbsp;- They program recreationally and perhaps have a few side projects on the go. They never got into CS just because they thought it was a sound career choice.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;I assume I'm getting these skills from a good programmer right out of school. More is nice, but I don't assume much more. Code craftsmanship is rarely taught in school. It comes from the school of hard knocks. Once you've been beaten into submission by a chunk of code you can start to think about how to do things better.&lt;br /&gt;&lt;br /&gt;If we break Technical Skills and Debugging Skills down, what could this list look like? Here are the things I like to see in every developer that I work with:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;Adheres to coding style&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Correctly applies our core development idioms&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Follows language best practices (knows "Effective [Foo]&lt;/b&gt;&lt;foo&gt;&lt;b&gt;")&lt;/b&gt;&lt;/foo&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Maintains useful documentation&amp;nbsp;&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Writes effective tests&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Writes tests that act as teaching aids&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Is able to focus&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Contributes constructively in development discussions&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Experience with dynamically typed, static typed and functional languages&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Can grok new topics quickly&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Understands scalability concerns&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Understands usability concerns&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Effectively uses Patterns&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Refactors in a timely fashion&lt;/b&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;foo&gt; (What would your list look like?)&lt;br /&gt;&lt;br /&gt;You give me a team of developers that have those skills and we will conquer the world! Obviously not everyone, especially anyone straight out of school, is going to have that skill set. The above list is really a road map to great code craft. &lt;br /&gt;&lt;br /&gt;Personally, if over the years, I was given this list in my performance reviews it would have given me a lot more career direction than just "better technical and debugging skills". I would have loved to learn that I need to focus more on "writing tests that act as teaching aids" and that I'm considered great at "groking new topics quickly". &lt;br /&gt;&lt;br /&gt;Given a suitable list, any company should be able to delineate what they think it means to be a Junior, Intermediate or Senior developer. &lt;br /&gt;&lt;br /&gt;Perhaps:&lt;/foo&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;b&gt;Junior:&lt;/b&gt; &amp;lt; top grade in 5 topics,&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Intermediate&lt;/b&gt;: top grade in 5 to 9 areas and&amp;nbsp;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Senior:&lt;/b&gt; top grade in &amp;gt; 9 topics?&amp;nbsp;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;foo&gt;(What would work for you?)&lt;br /&gt;&lt;br /&gt;I have a theory about this: &lt;i&gt;There is no such thing as an Intermediate developer! &lt;/i&gt;You are either Junior or quickly on your way to becoming Senior. If a developer stays in the Intermediate designation for too long the company should re-evaluate their role in the company. Sounds a little harsh but, assuming they are being given every opportunity to advance, why are they not? Not everyone can be an astronaut. &lt;br /&gt;&lt;br /&gt;More so, these skills are applicable to nearly any company. Most programmer job ads have stuff like this:&lt;/foo&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Knows Struts, Hibernate and JSP&lt;/li&gt;&lt;li&gt;3yrs experience with Powerbuilder 6.x and Oracle Form Blaster&amp;nbsp;&lt;/li&gt;&lt;li&gt;Has Cake PHP experience&lt;/li&gt;&lt;/ul&gt;While I understand the motivation of getting a developer that can hit the ground running when you hire them, I would argue that a developer with the craftsmanship skill set listed above would be handle any of those specific domains with little problem. I would also argue they could probably do it better than developers that only focus on those specific tools.&amp;nbsp;There needs to be a balance. Yes, confirm that the developer has the specific skills needed by your company, but more importantly, &lt;i&gt;make sure they have the Code Craft skills to not do more harm than good!&lt;/i&gt;&lt;br /&gt;&lt;br /&gt;Would you hire a developer to work on your desktop graphical C# application if they only have Ruby on Rails experience? Would you change your mind if they could demonstrate great code craft and general language diversity?&lt;br /&gt;&lt;br /&gt;This is a hard problem. How can a developer prove they have good code craft? Sadly, I don't have a good answer for that right now. I don't think certification is the answer. The closest thing I can think is their demonstrable participation in an open source project. I'm open to suggestions here and will continue to post my thoughts on the topic as they come. &lt;br /&gt;&lt;br /&gt;&lt;b&gt; Is Code Craftsmanship The Only Thing?&lt;/b&gt;&lt;br /&gt;&lt;foo&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt; If code craftsmanship was the only thing that mattered to a company we would all be contractors … disposable drones brought in to do a task as needed. But we know this is not the case. The longer you work at a company, the more you should learn about how the company makes money. Who are their competitors? How do their products differentiate? Who are the key customers? How do customers use the products you create?&lt;br /&gt;&lt;br /&gt;A developers value in a company is multiplied greatly by their awareness of these factors. The other part the performance evaluation and hiring criteria needs to take these factors into account. A very valuable software developer is one that:&lt;/foo&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;&lt;b&gt;Designs with product vision in mind&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Identifies pending delivery roadblocks in a timely fashion&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Researches new technologies, languages and tools applicable to our product mix&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Helps improve our operational efficiency&lt;/b&gt;&lt;/li&gt;&lt;li&gt;&lt;b&gt;Contributes to our competitive advantage&lt;/b&gt;&lt;/li&gt;&lt;/ol&gt;Software developers that write solid code and understand the business are your greatest assets. Guard them accordingly!&lt;br /&gt;&lt;br /&gt;Your thoughts?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8696186-2622291724178884648?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/2622291724178884648/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=2622291724178884648' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/2622291724178884648'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/2622291724178884648'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2010/03/developer-skill-sets-there-is-no-such.html' title='Developer Skill Sets: There is no such thing as an Intermediate Software Developer ...'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-1453994284191569576</id><published>2010-02-24T11:31:00.007-04:00</published><updated>2010-02-25T20:39:33.271-04:00</updated><title type='text'>Enforce Idioms - Get Religion</title><content type='html'>In the &lt;a href="http://sandywalsh.blogspot.com/2010/02/your-code-is-other-team-member.html"&gt;last&lt;/a&gt; &lt;a href="http://sandywalsh.blogspot.com/2010/02/self-documenting-code.html"&gt;series&lt;/a&gt;&amp;nbsp;of &lt;a href="http://sandywalsh.blogspot.com/2010/02/before-sitting-down-to-eat-elephant.html"&gt;articles &lt;/a&gt;we talked about how consistent coding style and great documentation can help a code base stay manageable. Beyond coding style and documentation, I think the most important thing &lt;a href="http://sandywalsh.blogspot.com/2010/01/tale-of-two-code-bases.html"&gt;Project 2&lt;/a&gt; could have done would be to clearly define the coding idioms they deemed to be important.&lt;br /&gt;&lt;br /&gt;Idioms and coding religion are a great way to boil down the things that the designers, architects and programmers of the original code base deem to be important. Some things are about how code should be written and others are related to business aspects of the project. Often they reflect, at a code level, what the functional specifications of the project are. They all should be addressed as early into the project as possible.&lt;br /&gt;&lt;br /&gt;Perhaps you are making a web framework? What are the important characteristics that framework should exhibit. Look at how &lt;a href="http://docs.djangoproject.com/en/dev/misc/design-philosophies/"&gt;Django &lt;/a&gt;and &lt;a href="http://en.wikipedia.org/wiki/Ruby_on_Rails#Philosophy_and_design"&gt;Rails &lt;/a&gt;have defined their design philosophies. &lt;br /&gt;&lt;br /&gt;What if you are making an asynchronous communications library?  Look at what &lt;a href="http://www.zeroc.com/features.html"&gt;Ice&lt;/a&gt; deems to be important. Compare this to the &lt;a href="http://twistedmatrix.com/documents/current/core/howto/vision.html"&gt;Twisted&lt;/a&gt; library. &lt;br /&gt;&lt;br /&gt;What if you are writing a programming language? Then perhaps a whole other set of things are important to you? Consider &lt;a href="http://python-history.blogspot.com/2009/01/pythons-design-philosophy.html"&gt;The Zen of Python&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Just will a little thought (and a couple of beers) I assembled this short list of things I view as important considerations when tackling a software project.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Low Coupling, High Cohesion&lt;/li&gt;&lt;li&gt;Less code&lt;/li&gt;&lt;li&gt;Quick development&lt;/li&gt;&lt;li&gt;Don't Repeat Yourself&lt;/li&gt;&lt;li&gt;Explicit is better than Implicit&lt;/li&gt;&lt;li&gt;Consistency&lt;/li&gt;&lt;li&gt;Prefer Stateless Classes&lt;/li&gt;&lt;li&gt;Separate Logic from Presentation&lt;/li&gt;&lt;li&gt;All Code must have Tests&lt;/li&gt;&lt;li&gt;Internationalization must be addressed in all cases&lt;/li&gt;&lt;li&gt;MVC&lt;/li&gt;&lt;li&gt;SOA (RESTful?)&lt;/li&gt;&lt;li&gt;Getting Real - &lt;a href="https://gettingreal.37signals.com/"&gt;https://gettingreal.37signals.com/&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Convention over Configuration - No XML Situps&lt;/li&gt;&lt;li&gt;Principle of Least Surprise&lt;/li&gt;&lt;li&gt;Principle of Least Knowledge&lt;/li&gt;&lt;li&gt;What are the accepted licenses&lt;/li&gt;&lt;li&gt;What are the accepted libraries&lt;/li&gt;&lt;li&gt;What are the accepted languages&lt;/li&gt;&lt;li&gt;No commented out code&lt;/li&gt;&lt;li&gt;Remove dead classes&lt;/li&gt;&lt;li&gt;Compile Clean&lt;/li&gt;&lt;li&gt;Prefer Data Driven Design&lt;/li&gt;&lt;li&gt;Don't treat Exceptions like Booleans&lt;/li&gt;&lt;li&gt;Don't Mask Exceptions&lt;/li&gt;&lt;li&gt;Know your Exception Hierarchy&lt;/li&gt;&lt;li&gt;Prefer Aggregation over Inheritance&lt;/li&gt;&lt;li&gt;Prefer Event-driven over Multi-threaded (or vise-versa)&lt;/li&gt;&lt;li&gt;Prefer Reaping over Explicit Deletion&lt;/li&gt;&lt;li&gt;Prefer Immutable Data&lt;/li&gt;&lt;li&gt;Prefer Finite State Machines to Boolean Nests&lt;/li&gt;&lt;li&gt;No Switch Statements&lt;/li&gt;&lt;li&gt;No Singletons (includes Globals)&lt;/li&gt;&lt;li&gt;No “Regions” in C#&lt;/li&gt;&lt;li&gt;Avoid state / Offload state to the caller&lt;/li&gt;&lt;li&gt;Cache everything / Cache nothing&lt;/li&gt;&lt;li&gt;Prefer Lazy-loading / Lazy initialization&lt;/li&gt;&lt;li&gt;Don't make up new names for accepted practices&lt;/li&gt;&lt;/ul&gt;Now I'm sure some of you are looking at this list and going “Well, duh!” but don't laugh too soon. You would not believe how many of these common sense coding philosophies are violated daily. If anything these rules can serve as a training tool for new developers to learn the difference between good and bad code. Reviewing one ortwo of these during lunch sessions is a great way to ramp up your teams overall coding skills. &lt;br /&gt;&lt;br /&gt;I'm sure, even without a few beers, you could add a ton of your own rules to this list. The &lt;a href="http://c2.com/cgi/wiki?WelcomeVisitors"&gt;c2.com&lt;/a&gt; website is a great place for ideas and discussion. &lt;br /&gt;&lt;br /&gt;The question is … how many rules should you set?&lt;br /&gt;&lt;br /&gt;The answer is, of course, it depends. If you are running an open source project and are looking to recruit more developers onto your project, then perhaps you don't want too many barriers to adoption. If you are in a corporate environment and give RCS commit privileges immediately to new hires (bad), you might want to set more ground rules. &lt;br /&gt;&lt;br /&gt;Just be aware of one important thing: &lt;b&gt;When you add or change a rule, you instantly incur technical debt!&lt;/b&gt; If it was previously acceptable to mask exceptions and then you set a project rule that exceptions cannot be masked, you just took on a chunk of technical debt. Your first step in adopting this rule has to be cleaning up the debt. Don't start building your church with broken windows. &lt;br /&gt;&lt;br /&gt;If your programmers can follow and maintain an agreed upon set of programming idioms you are likely well on your way to producing a beautiful body of code.&lt;br /&gt;&lt;br /&gt;Knowing this sort of thing comes from experience. Next time we will talk about developer skills and what the good ones seem to have in common.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8696186-1453994284191569576?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/1453994284191569576/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=1453994284191569576' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/1453994284191569576'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/1453994284191569576'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2010/02/enforce-idioms-get-religion.html' title='Enforce Idioms - Get Religion'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-7231979170371484538</id><published>2010-02-09T12:26:00.003-04:00</published><updated>2010-02-09T19:21:36.880-04:00</updated><title type='text'>Self Documenting Code ...</title><content type='html'>I hope you read Jacob Kaplan-Moss's article "&lt;a href="http://jacobian.org/writing/great-documentation/what-to-write/"&gt;What to Write&lt;/a&gt;" ... because I'm not going to talk a lot more about that topic. He does an amazing job of explaining what users are looking for when they approach a code base as well as what a waste of time embedded documentation is. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;My perspective on documenting code builds on Jacob's observations. As I've mentioned previously in &lt;a href="http://sandywalsh.blogspot.com/2010/02/your-code-is-other-team-member.html"&gt;Your Code Is The Other Team Member&lt;/a&gt;, code should read like a book. Your eyes should be able to scan the source unencumbered to glean the meaning. &lt;a href="http://www-cs-faculty.stanford.edu/~uno/"&gt;Don Knuth&lt;/a&gt; says code should be written primarily to communicate its purpose to humans [not to make the compilers happy].&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In order to read like a book, code should be Self-Documenting. And by self-documenting I &lt;i&gt;do not&lt;/i&gt; mean &lt;a href="http://www.stack.nl/~dimitri/doxygen/"&gt;Doxygen &lt;/a&gt;or &lt;a href="http://java.sun.com/j2se/javadoc/"&gt;Javadoc&lt;/a&gt;. I mean, does the code clearly express its purpose in and of itself? &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When you write code you need to constantly ask yourself "Am I sabotaging the readability of this code?"&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;How can we sabotage the readability of our code?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Don't document the literal code, but rather, the intention of the code&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Who should I believe in this snippet of code?&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;// Do foo if check is True ... &lt;/div&gt;&lt;div&gt;if ( ! check_thing_has_occurred())&lt;/div&gt;&lt;div&gt;{&lt;/div&gt;&lt;div&gt;    foo();&lt;/div&gt;&lt;div&gt;}&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;You just broke my brain. Now I've got to drill through the logic to find out if the comment or the code is right. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;IDE Code Snippet Macros are an invention of the Devil&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What value does this comment bring to this method?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;div&gt;/*********************&lt;/div&gt;&lt;div&gt;Detail:&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Constructor&lt;/div&gt;&lt;div&gt;**********************/&lt;/div&gt;&lt;div&gt;CCPasswordDlg::CCPasswordDlg(CWnd* pParent)&lt;/div&gt;&lt;div&gt;{&lt;/div&gt;&lt;/div&gt;&lt;div&gt;...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;How about this?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;/*********************&lt;/div&gt;&lt;div&gt;Detail:&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Sets the quality level based on a 1-10 variant&lt;/div&gt;&lt;div&gt;Pram:&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;iQuality - quality setting (1-10)&lt;/div&gt;&lt;div&gt;Date:&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Sunday, April 06, 2008&lt;/div&gt;&lt;div&gt;By:&lt;span class="Apple-tab-span" style="white-space:pre"&gt;  &lt;/span&gt;Joe Developer&lt;/div&gt;&lt;div&gt;Note:&lt;span class="Apple-tab-span" style="white-space:pre"&gt; &lt;/span&gt;Returns VIDEO_CODEC_SUCCESS if successful, VIDEO_CODEC_INCORRECT_PARAMETER otherwise.&lt;/div&gt;&lt;div&gt;**********************/&lt;/div&gt;&lt;div&gt;int CVideoEncoder::SetQuality( int iQuality )&lt;/div&gt;&lt;div&gt;...&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So much of this fluff is auto-generated by some keystroke macro from the IDE. It's a complete waste of space. It breaks the flow of the code and creates more places for the reader to second guess themselves. Even worse, it's not even metadata for a doc generator. It's double junk.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Why do we need a date time stamp in the source? Why do we need the developers name? All that stuff is in the RCS. Don't duplicate it. Why do we need the /***...***/? Modern IDE's highlight method names perfectly. Isn't the bounds check more useful in the code? Can't we look at the source to see the return types? Sure, if this is a public-facing API, then &lt;i&gt;perhaps&lt;/i&gt; the summary, variable information and return types are valid ... but not for internal code. Again, I would much prefer to see a working unit test or tutorial that explains how this method should be called in the context of a proper use case. That gives me far more benefit than an auto-generated html page will ever provide. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is just the low-hanging fruit. The &lt;a href="http://c2.com/cgi/wiki?SelfDocumentingCode"&gt;C2 wiki entry on Self Documenting Code&lt;/a&gt; gives an excellent summary of other things you can do to make your code more readable. Think about all of these points before you start sprinkling doc sugar all over your source. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you focus on a consistent coding style and follow these rules for making your code base self-documenting you are well on your way to creating a code base that will out live your team or process. There is one more thing that really make it truly timeless ... establish a religion. We'll discuss this next time. &lt;/div&gt;&lt;/div&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/8696186-7231979170371484538?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/7231979170371484538/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=7231979170371484538' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/7231979170371484538'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/7231979170371484538'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2010/02/self-documenting-code.html' title='Self Documenting Code ...'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-8703006434384869848</id><published>2010-02-05T09:32:00.009-04:00</published><updated>2010-02-05T11:40:52.410-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='code style'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Your Code is the Other Team Member ...</title><content type='html'>One of my big complaints with the code base of &lt;a href="http://sandywalsh.blogspot.com/2010/01/tale-of-two-code-bases.html"&gt;Project 2&lt;/a&gt; was the complete lack of a consistent &lt;a href="http://en.wikipedia.org/wiki/Programming_style"&gt;coding style guide&lt;/a&gt;. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm of the belief that code should read like a book. You should be able to look at a function, class or method and read it from top to bottom like a story. It should have a clear beginning, middle and end. &lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;&lt;span class="Apple-style-span"  style="color:#009900;"&gt;How &lt;/span&gt;&lt;b&gt;would &lt;span class="Apple-style-span"  style="color:#FF6600;"&gt;you&lt;/span&gt;&lt;/b&gt;&lt;span class="Apple-style-span"  style="color:#FF6600;"&gt; &lt;/span&gt;like &lt;/span&gt;to &lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;i&gt;&lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;&lt;b&gt;a read&lt;/b&gt; &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;a book &lt;span class="Apple-style-span" style="font-style: normal;"&gt;&lt;span class="Apple-style-span"  style="color:#33CCFF;"&gt;where&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;&lt;span class="Apple-style-span" style="font-style: normal;"&gt;&lt;span class="Apple-style-span"  style="color:#33CCFF;"&gt; the&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:#CC66CC;"&gt;&lt;b&gt; formatting&lt;/b&gt; was &lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;c&lt;span class="Apple-style-span"  style="color:#FFCC00;"&gt;ompletely&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/i&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;&lt;span class="Apple-style-span"  style="color:#FFCC00;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="font-family:georgia;"&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;&lt;span class="Apple-style-span"  style="color:#CC66CC;"&gt;&lt;span class="Apple-style-span"  style="font-family:'times new roman';"&gt;&lt;span class="Apple-style-span"  style="color:#FFCC00;"&gt;inconsistent&lt;/span&gt;&lt;/span&gt; and &lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;&lt;span class="Apple-style-span"  style="color:#3333FF;"&gt;you&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:#3333FF;"&gt; &lt;/span&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;span class="Apple-style-span"  style="color:#3333FF;"&gt;had&lt;/span&gt; to &lt;span class="Apple-style-span"  style="color:#660000;"&gt;struggle&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:#660000;"&gt; with&lt;/span&gt; the &lt;/span&gt;&lt;span class="Apple-style-span"  style="color:#009900;"&gt;typesetting &lt;span class="Apple-style-span"  style="font-size:x-large;"&gt;&lt;span class="Apple-style-span"  style="color:#993300;"&gt;to get &lt;/span&gt;&lt;/span&gt;to&lt;/span&gt;&lt;span class="Apple-style-span"  style="color:#CC66CC;"&gt; the content&lt;/span&gt;.&lt;/span&gt;&lt;/b&gt;&lt;/span&gt; That's what happens when source doesn't follow a style guide. Your brain can't move up the semantic ladder because it's mired in syntactic noise. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In order to get to the goal of &lt;a href="http://c2.com/cgi/wiki/wiki?CollectiveCodeOwnership"&gt;Collective Code Ownership&lt;/a&gt;, everyone needs to see things the same way. Formatting and style is the first step to this goal.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There are a many different code style guides already available. Most are for specific languages: &lt;a href="http://www.chris-lott.org/resources/cstyle/"&gt;C, C++&lt;/a&gt;, &lt;a href="http://blogs.msdn.com/brada/articles/361363.aspx"&gt;C#&lt;/a&gt;, &lt;a href="http://java.sun.com/docs/codeconv/html/CodeConvTOC.doc.html"&gt;Java&lt;/a&gt;, &lt;a href="http://www.python.org/dev/peps/pep-0008/"&gt;Python&lt;/a&gt;. While some are variations on these for specific libraries or packages: &lt;a href="http://developer.gnome.org/doc/guides/programming-guidelines/code-style.html"&gt;Gnome&lt;/a&gt;, &lt;a href="http://docs.djangoproject.com/en/dev/internals/contributing/#coding-style"&gt;Django&lt;/a&gt;, &lt;a href="http://www.pathf.com/blogs/ruby-and-rails-style-guide/"&gt;Rails&lt;/a&gt;, &lt;a href="http://www.kernel.org/doc/Documentation/CodingStyle"&gt;Linux&lt;/a&gt;. And others are company specific style guides like the &lt;a href="http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml"&gt;Google C++&lt;/a&gt; guide and &lt;a href="http://en.wikipedia.org/wiki/Hungarian_notation"&gt;Microsoft Hungarian Notation&lt;/a&gt;. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;A good coding style should include more than just brace style, comment form and indent conventions, but also things such as:&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Directory naming&lt;/li&gt;&lt;li&gt;File naming&lt;/li&gt;&lt;li&gt;Package/Module naming&lt;/li&gt;&lt;li&gt;Class, Function and Variable naming (&lt;a href="http://en.wikipedia.org/wiki/CamelCase"&gt;CamelCase&lt;/a&gt;? all_lower? AbbrAllowed?)&lt;/li&gt;&lt;li&gt;Member variable referencing (&lt;b&gt;&lt;a href="http://blogs.msdn.com/ericgu/archive/2007/06/15/to-m-or-no-to-m-that-is-the-question.aspx"&gt;m_&lt;/a&gt;&lt;/b&gt; vs. &lt;b&gt;_&lt;/b&gt; vs. &lt;b&gt;this&lt;/b&gt;.?)&lt;/li&gt;&lt;li&gt;Member variable ordering (public, protected, private? Top of class vs. End of class?)&lt;/li&gt;&lt;li&gt;Method ordering (alphabetical? public, protected, private?)&lt;/li&gt;&lt;li&gt;Import rules and organization (Should all external references be fully qualified? Are blanket includes allowed?)&lt;/li&gt;&lt;li&gt;Variable &lt;a href="http://leepoint.net/notes-java/data/variables/60shadow-variables.html"&gt;shadowing&lt;/a&gt; rules?&lt;/li&gt;&lt;li&gt;&lt;a href="http://apr.apache.org/versioning.html"&gt;Versioning&lt;/a&gt; standards&lt;/li&gt;&lt;li&gt;Copyright and IP ownership notifications&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;These all need to be addressed! &lt;span class="Apple-style-span" style="font-style: normal; "&gt;It's very hard to find one standard that will address all of these points for your specific project, so you can expect to roll up your sleeves. Put it on a wiki and have all the developers get notified whenever it changes. Try and pick one that is as close as possible to an existing, widely enforced standard.&lt;/span&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;i&gt;&lt;br /&gt;&lt;/i&gt;&lt;/div&gt;&lt;div&gt;With so many definitions it can be a little daunting to pick one. There is one rule you must follow: BE CONSISTENT. While we all have preferences on whether braces should go at the end of the line or the next line, it's far more important to pick one and stick with it. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I saw a great tweet the other day from &lt;a href="https://twitter.com/sbastn"&gt;@sbastn&lt;/a&gt;: "&lt;i&gt;I am never going to use the word team unless I really mean it. The word group seems my best replacement&lt;/i&gt;"&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Your code is your other group member.&lt;/b&gt; I don't think you can even think about transitioning from a "group" to a "team" until your code is playing the game too. So, how can you get your group to start considering your code as the other team member?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Many places I've worked have won't permit code reviews to start until the code meets the style guide. "Fix it and I'll come back." Personally I like that rule, but it can frustrate some developers. Enforcing code style can be a daunting, laborious, thankless task ... trust me. Your group is on its way to becoming a team when there is no enforcement required ... everyone just does it because they see the value in it. So, following the mantra of "Automate Everything You Can" (and knowing you can't automate everything) ... there are things you can do with respect to code. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;b&gt;Automated Reformatting&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Some groups perform nightly automated reformat of the code base using pretty printers like&lt;a href="http://pythonwise.blogspot.com/2009/09/pyindent.html"&gt;PyIndent&lt;/a&gt;, &lt;a href="http://jalopy.sourceforge.net/"&gt;Jalopy&lt;/a&gt; and &lt;a href="http://astyle.sourceforge.net/"&gt;AStyle&lt;/a&gt;. I don't like this approach. If the code changes after you have checked it in, it will look foreign to you when you next look at it. These tools are best used &lt;i&gt;initially&lt;/i&gt; to get your legacy code to a good base state. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;No Commit Until Compliant&lt;/b&gt;&lt;/div&gt;&lt;div&gt;With most revision control systems you can install &lt;a href="http://wordaligned.org/articles/a-subversion-pre-commit-hook"&gt;pre-commit hooks&lt;/a&gt; that can verify code compliance first before letting the code into production. I prefer this approach because it makes the developer think about the code style as part of the check-in checklist ... right up there with making sure the tests are written.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Try to Convert the Legacy Codebase in One Fell Swoop&lt;/b&gt;&lt;/div&gt;&lt;div&gt;Picking away at a code base to make it match your new style can take forever. You may need to write some custom scripts to help with this (especially when renaming files), but formatting changes are one of the few modifications you can make to a legacy code base where behavior &lt;i&gt;should &lt;/i&gt;not change. You have to get into the new code style mindset as quickly as possible and doing this piecemeal only makes it harder.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In summary, establishing and enforcing a coding style on your project should be one of your first steps to fixing a legacy code base. Use automated tools or scripts to help with this project. If you can't automate the effort ask developers not to make the problem worse and to help clean up the mess when they're in fixing something else. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Another thing your programming style guide should address is the documentation style. We'll go over this next time, but in preparation you should read this great series of articles on the topic by &lt;a href="http://jacobian.org"&gt;Jacob Kaplan-Moss&lt;/a&gt;: &lt;a href="http://jacobian.org/writing/great-documentation/what-to-write/"&gt;What to Write&lt;/a&gt;, &lt;a href="http://jacobian.org/writing/great-documentation/technical-style/"&gt;Technical Style&lt;/a&gt; and, for large doc efforts, &lt;a href="http://jacobian.org/writing/great-documentation/editors/"&gt;You Need an Editor&lt;/a&gt;. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&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/8696186-8703006434384869848?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/8703006434384869848/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=8703006434384869848' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/8703006434384869848'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/8703006434384869848'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2010/02/your-code-is-other-team-member.html' title='Your Code is the Other Team Member ...'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-1674717652294426468</id><published>2010-02-02T14:55:00.003-04:00</published><updated>2010-02-02T15:47:02.123-04:00</updated><title type='text'>Before sitting down to Eat the Elephant ...</title><content type='html'>&lt;div&gt;In '&lt;a href="http://sandywalsh.blogspot.com/2010/01/tale-of-two-code-bases.html"&gt;A Tale of Two Code Bases&lt;/a&gt;' I described two legacy code bases and how one (Project 1) was a pleasure to work on and the other (Project 2) was a nightmare. I promised to follow up with some hints for what Project 2 could have done to make their code more manageable. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;About a year ago I was looking into wind generators and solar devices for my house ... it can get cold in Nova Scotia. The store owner told me "get your house fully insulated first, then we can talk about efficiency". Great advice. The same applies for Code Management. I think "&lt;a href="http://www.joelonsoftware.com/articles/fog0000000043.html"&gt;The Joel Test&lt;/a&gt;" is a great litmus for whether your house is insulated enough. You shouldn't be struggling with bad source control/development tools, slow development PC's or perpetually looming deadlines before you go into this. You should also have some degree of buy-in from your superiors that you can regularly dedicate a little time to making your code base better. The intention is not to upset the apple-cart, boil the ocean or reinvent the wheel (choose your analogy) ... but rather &lt;a href="http://4.bp.blogspot.com/_ZF8-4lX2SUU/StLPnaMyEdI/AAAAAAAAAHM/AxraB5UvRvU/s320/eating+the+whole+elephant.jpg"&gt;Eat the Elephant&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;I don't want to rehash topics that have already been exhaustively covered, such as TDD or the particulars of writing effective code in a given programming language. Well, I don't want to rehash them in any great detail. My intention is to make these posts about Effective Code Management and not about software development methodologies. That is, not about requirements gathering, feature definition, scheduling or estimating. I feel strongly that without a solid code management foundation whatever development methodology you use will fail over time. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So, I'll assume you've read &lt;a href="http://www.amazon.com/Test-Driven-Development-Kent-Beck/dp/0321146530/ref=pd_sim_b_2"&gt;one&lt;/a&gt; &lt;a href="http://www.amazon.com/Test-Driven-Development-Practical-David-Astels/dp/0131016490/ref=pd_sim_b_20"&gt;of&lt;/a&gt; &lt;a href="http://www.amazon.com/Test-Driven-Development-Microsoft-NET-Professional/dp/0735619484/ref=pd_sim_b_14"&gt;the&lt;/a&gt; &lt;a href="http://www.amazon.com/Test-Driven-Acceptance-Java-Developers/dp/1932394850/ref=sr_1_3?ie=UTF8&amp;amp;s=books&amp;amp;qid=1265138178&amp;amp;sr=1-3"&gt;hundreds&lt;/a&gt; &lt;a href="http://www.amazon.com/Art-Unit-Testing-Examples-Net/dp/1933988274/ref=sr_1_5?ie=UTF8&amp;amp;s=books&amp;amp;qid=1265138178&amp;amp;sr=1-5"&gt;of&lt;/a&gt; TDD books out there and at least one of the "Effective [Foo]" books out there that apply to the programming language you use daily. &lt;a href="http://www.amazon.com/Effective-Specific-Addison-Wesley-Professional-Computing/dp/0201924889"&gt;C++&lt;/a&gt;/&lt;a href="http://www.amazon.com/Effective-STL-Specific-Standard-Template/dp/0201749629"&gt;STL&lt;/a&gt;, &lt;a href="http://www.amazon.com/Effective-Specific-Ways-Improve-Your/dp/0321245660"&gt;C#&lt;/a&gt;, &lt;a href="http://java.sun.com/docs/books/effective/"&gt;Java&lt;/a&gt;, etc. And, because I'm going to assume you will be working with code that is already in the field, I'll also recommend Michael Feathers 2004 book "&lt;a href="http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052"&gt;Working Effectively with Legacy Code&lt;/a&gt;" which gives some nice guidelines for anyone faced with an elephant-meat diet.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Next time, we'll take our first nibble with a look at coding style guides ...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&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/8696186-1674717652294426468?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/1674717652294426468/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=1674717652294426468' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/1674717652294426468'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/1674717652294426468'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2010/02/before-sitting-down-to-eat-elephant.html' title='Before sitting down to Eat the Elephant ...'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-9216772017751928357</id><published>2010-01-26T10:03:00.002-04:00</published><updated>2010-01-26T10:32:30.437-04:00</updated><title type='text'>A Tale of Two Code Bases</title><content type='html'>On a recent project, I inherited a rather large code base. The developers had long since moved on and all the in-house knowledge of the application left with them. Before I could even really get down to business I had some logistical problems to work out. The source control system in place wasn't accessible from my remote location and the build system was very dependent on the network layout. The code had been under development for nearly 10 years and was a mix of PC-based code and cross-platform shared code with the firmware for several hardware products. It was pretty hard to know where one product ended and another began. It was a mix of C++, Python and C. And this code was very technical. Lots of concurrency, thread management, parts made heavy use of COM, rendering stuff, low-level bit-twiddling stuff, you name it.&lt;br /&gt;&lt;br /&gt;But, the code was neat. There was a consistent coding style. It was well structured with clear delineation between modules. In several places there were API's established for third-party integration. There was an architecture and good attempts at getting some automated tests in place. Pattern names were used and standard development idioms were followed. Sure, much of it was organic growth and you could see where the developers had some crosses to bear, but there was clear evidence of intelligent life and a passion for the code base. All in all, it was pretty darn impressive.&lt;br /&gt;&lt;br /&gt;One of my first tasks was to get the code running again. I needed to get it moved over to a new version control system and then get it working with the latest compilers and libraries. From there I could work on getting the much needed new features in place that the the customer needed. It was a big task, but it was fun to dig through a nice code base and see how the previous people did it. It was like discovering a nice old house and walking through the rooms to admire the craftsmanship without a guide.&lt;br /&gt;&lt;br /&gt;With that one under my belt, I got the "lucky" task of being given another legacy code base. This one wasn't as big as the previous. It wasn't as technically complicated either. Yes, there was multi-threading, interprocess communications and some tricky GUI stuff going on there, but all in it nothing that you couldn't wrap your head around. It was just C++ with MFC. Very little COM. Windows only. I had a little bit of guidance from a couple of the last developers to work on it, but once they left I was really on my own to understand all the nooks and crannies of the product. Again, I had to move it over to the new source control system and update the compilers and libraries and make the build system less rigid.&lt;br /&gt;&lt;br /&gt;But this second code base was a mess. There was no coding style. Variable names were cryptic with a mishmash of Hungarian Notation forms. Every class (when classes were used) was tightly coupled to each other. There was no modularity to the architecture. There was no structured exception handling, no provisions for automated tests, no organized logging to speak of. Constants changed. Code was copy pasted everywhere it was needed. One feature I needed to remove, which was essentially a boolean check, touched over 40 files across four applications. Data lived everywhere and had no core data dictionary of usage, so you had to trace the code to find out what the intended use was.&lt;br /&gt;&lt;br /&gt;Basically, the second code base was buried in technical debt.&lt;br /&gt;&lt;br /&gt;This is not to blame the developers or the management. There are no fingers to point here ... there's no one left to point them at anyway. It's like an archaeologist stumbling on a lost city and learning that the citizens died of a common disease ... it wasn't their fault. But we now know that, with some basic medicine and health practices, it could have been avoided.&lt;br /&gt;&lt;br /&gt;I'm an Agile guy. I love the innovations in the software development process of the last ten years. But this experience  opened my eyes to where the real work of software development needs to be done ... in the code. I have no idea what the development methodologies used were when these code bases were being developed. Perhaps they were Waterfall? Perhaps they were some Scrum/XP hybrid? Who knows? Who cares. The code is the only thing left that matters. Developers need to remember that the process, the methodology, should not take precedence over code craftsmanship. Don't get so mired in the busy work to lose track of what you're doing in the first place ... writing code. The code is paramount.&lt;br /&gt;&lt;br /&gt;I'll follow up this post soon with some of my other insights on this experience and recommend some steps that could have been taken to help Project 2 out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8696186-9216772017751928357?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/9216772017751928357/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=9216772017751928357' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/9216772017751928357'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/9216772017751928357'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2010/01/tale-of-two-code-bases.html' title='A Tale of Two Code Bases'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-614764211047010963</id><published>2010-01-08T10:37:00.002-04:00</published><updated>2010-01-08T10:50:15.536-04:00</updated><title type='text'>Installing IronPython 2.6RC1</title><content type='html'>&lt;div&gt;I'm not a .NET guy at all. I'm in the process of working with a third party C# library, but would rather use IronPython instead of C#, so I tried to install IronPython 2.6 RC1 ...&lt;a href="http://lists.ironpython.com/pipermail/users-ironpython.com/2009-October/011407.html"&gt; it didn't go well&lt;/a&gt;. The installer would get to about 90% complete, but then fail and rollback without any info as to what went wrong.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;By manually running the .msi installer we can get a log file:&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;msiexec /i IronPython-2.6.msi /log install.log&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;The offending operation seems to be:&lt;br /&gt;&lt;blockquote&gt;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\&lt;a href="http://msdn.microsoft.com/en-us/library/6t9t5wcf(VS.80).aspx"&gt;ngen.exe&lt;/a&gt; install  C:\Program Files\IronPython 2.6\Microsoft.Scripting.dll /queue:1&lt;/blockquote&gt;The /queue parameter is to kick off the &lt;a href="http://msdn.microsoft.com/en-us/library/ms165074(VS.80).aspx"&gt;.NET Optimizing compiler service&lt;/a&gt; ... but this seemed to be failing. I could verify this when I ran the ngen.exe command directly:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727&gt;ngen queue status &lt;/div&gt;&lt;div&gt;Microsoft (R) CLR Native Image Generator - Version 2.0.50727.3053&lt;br /&gt;Copyright (c) Microsoft Corporation.  All rights reserved.&lt;br /&gt;The specified service does not exist as an installed service. (Exception  from HRESULT: 0x80070424)&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;Hmm, where's my &lt;a href="http://msdn.microsoft.com/en-us/magazine/cc163610.aspx"&gt;JIT&lt;/a&gt;?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Turns out my .NET Runtime Optimization Service v2.0.50727_X86 service is either not running or not installed. In my case it was not installed. Very odd as I have .NET 2.0 -&gt; 3.5.1 installed and everything else works. Oh well. &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;After some &lt;a href="http://www.vernalex.com/tools/services/?info=.NET%20Runtime%20Optimization%20Service%20v*"&gt;poking around&lt;/a&gt; &lt;a href="http://support.microsoft.com/kb/918608"&gt;I found&lt;/a&gt; you can register the service manually via:&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;%WINDIR%\Microsoft.NET\Framework&lt;64&gt;\v2.0.Number\mscorsvw.exe -i&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Or, in my case, C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727&gt;mscorsvw.exe -i&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;That got the service installed and the IronPython install worked fine afterwards.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Hope this saves someone some time.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8696186-614764211047010963?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/614764211047010963/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=614764211047010963' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/614764211047010963'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/614764211047010963'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2010/01/installing-ironpython-26rc1.html' title='Installing IronPython 2.6RC1'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-2219374066402024498</id><published>2009-10-08T13:52:00.004-03:00</published><updated>2009-10-08T19:50:41.845-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='python swig c threads'/><title type='text'>Interfacing multi-threaded C API's with Python using SWIG ...</title><content type='html'>Ran into an interesting problem yesterday. There is a third party C library that I need to interface to using &lt;a href="http://python.org/"&gt;Python&lt;/a&gt;. Normally, this isn't a problem. Just use &lt;a href="http://www.swig.org/"&gt;SWIG&lt;/a&gt; to make a Python Wrapper on the desired API functions and call away. But this library was a little nastier because it spawned other threads and notified the caller via callbacks. Callbacks on their own aren't really a big deal for SWIG, you just have to handle the delegation from C to Python yourself, which is easy to do in the .i file. But when the callback is coming from another thread there are some twists.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/CPython"&gt;CPython&lt;/a&gt; is notorious for the &lt;a href="http://docs.python.org/c-api/init.html#threads"&gt;Global Interpreter Lock (GIL)&lt;/a&gt;. You have to release the GIL whenever you do blocking I/O and re-obtain it when you are done. With a callback it's a little different, you want to acquire the lock, call Python and release it again when your back in C-land.&lt;br /&gt;&lt;br /&gt;Starting off, my .i file looked something like this:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;br /&gt;%module probe&lt;br /&gt;%{&lt;br /&gt;#include "myapi.h"&lt;br /&gt;%}&lt;br /&gt;&lt;br /&gt;%include "windows.i"&lt;windows.i&gt;&lt;br /&gt;&lt;br /&gt;typedef void __stdcall (*HandleDataCallBack)(char*, int);&lt;br /&gt;&lt;br /&gt;int Start(HandleDataCallBack);&lt;br /&gt;int Stop();&lt;br /&gt;int SendInquiry();&lt;br /&gt;&lt;br /&gt;%{&lt;br /&gt;PyObject* python_callback = 0;&lt;br /&gt;&lt;br /&gt;void __stdcall api_start_callback(char* foo, int blah)&lt;br /&gt;{&lt;br /&gt;  PyObject *arglist;&lt;br /&gt;  PyObject *result;&lt;br /&gt;  PyGILState_STATE gstate;&lt;br /&gt;&lt;br /&gt;  if (!PyCallable_Check(python_callback))&lt;br /&gt;  {&lt;br /&gt;      PyErr_SetString(PyExc_TypeError, "Python callback must be callable");&lt;br /&gt;      return;&lt;br /&gt;  }&lt;br /&gt;  arglist = Py_BuildValue("(si)", foo, blah);&lt;br /&gt;&lt;br /&gt;  gstate = PyGILState_Ensure();&lt;br /&gt;&lt;br /&gt;  result = PyEval_CallObject(python_callback, arglist);&lt;br /&gt;&lt;br /&gt;  Py_XDECREF(arglist);&lt;br /&gt;  Py_XDECREF(result);&lt;br /&gt;&lt;br /&gt;  PyGILState_Release(gstate);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;void alt_start(PyObject *pyfunc)&lt;br /&gt;{&lt;br /&gt;  python_callback = pyfunc;&lt;br /&gt;  Start(api_start_callback);&lt;br /&gt;  Py_INCREF(pyfunc);&lt;br /&gt;}&lt;br /&gt;%}&lt;br /&gt;&lt;br /&gt;void alt_start(PyObject*);&lt;/windows.i&gt;&lt;/blockquote&gt;Essentially what I'm doing here is defining a new function &lt;i&gt;alt_start()&lt;/i&gt; to replace the API &lt;i&gt;Start()&lt;/i&gt; function. A well known callback (&lt;i&gt;api_start_callback&lt;/i&gt;) is then handed off the the real &lt;i&gt;Start()&lt;/i&gt;. &lt;i&gt;api_start_callback()&lt;/i&gt; does the heavy lifting of assembling the arguments, acquiring the GIL, calling the Python callback and then giving the GIL back to Python. &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For other places where the threading is an issue, SWIG can take of this itself when you run Swig with the &lt;i&gt;-threads&lt;/i&gt; option. In my case: &lt;i&gt;swig -python -threads probe.i&lt;/i&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The simplified Python code for calling this looks something like this:&lt;/div&gt;&lt;blockquote&gt;import probe&lt;br /&gt;import time&lt;br /&gt;&lt;br /&gt;def ProbeCallback(foo, blah):&lt;br /&gt;....print "Foo: %s, Blah: %d" % (foo, blah)&lt;br /&gt;&lt;br /&gt;probe.alt_start(ProbeCallback)&lt;br /&gt;probe.SendInquiry()&lt;br /&gt;time.sleep(60)&lt;br /&gt;probe.Stop()&lt;br /&gt;&lt;/blockquote&gt;Someday perhaps, I'll be able to call &lt;i&gt;Start()&lt;/i&gt; directly and pass my Python callback handler without the need for this special handling code. Until then, the work around isn't too horrible.&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/8696186-2219374066402024498?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/2219374066402024498/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=2219374066402024498' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/2219374066402024498'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/2219374066402024498'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2009/10/interfacing-multi-threaded-c-apis-with.html' title='Interfacing multi-threaded C API&apos;s with Python using SWIG ...'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-4401696797874306881</id><published>2009-08-14T09:29:00.004-03:00</published><updated>2009-10-08T14:55:10.592-03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='visual studio assemblies 2008 manifest debug mfc c++ runtime'/><title type='text'>Microsoft VC++ SxS Assemblies &amp; Manifests</title><content type='html'>&lt;p&gt;This is true madness. In the process of bringing a legacy VC++ project up to date with Visual Studio 2008 there were some real hurdles to get over.&lt;/p&gt;&lt;p&gt;The biggest issue is that starting with Visual Studio 2005 Microsoft introduced the idea of Side-by-Side Assemblies and Manifests. This is a mechanism whereby different versions of the Visual Studio C runtime, ATL libraries, MFC libraries and other assemblies can be run "side-by-side".&lt;/p&gt;&lt;p&gt;So, while your program may compile and run in debug, it may not be able to be copied to a system with no dev environment on it without serious tap-dancing. You'll get cryptic "The application is not configured correctly and should be reinstalled" messages on XP or a vague hint about &lt;tt&gt;SxS&lt;/tt&gt; on Vista.&lt;/p&gt;&lt;p&gt;After a lot of time spent on the MSDN forums I finally figured out how this mess works.&lt;/p&gt;&lt;p&gt;First off, VC++ apps will include &lt;tt&gt;\Program Files\Microsoft Visual Studio 9.0\VC\include\crtdefs.h&lt;/tt&gt; via &lt;tt&gt;Stdafx.h&lt;/tt&gt;. Look at this header file. It contains lines like this:&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;#include &amp;lt;crtassem.h&gt;&lt;br /&gt;&lt;br /&gt;#ifdef _M_IX86&lt;br /&gt;#ifdef _DEBUG&lt;br /&gt;&lt;br /&gt;#pragma comment(linker,"/manifestdependency:\"type='win32' " \&lt;br /&gt;      "name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".DebugCRT' "         \&lt;br /&gt;      "version='" _CRT_ASSEMBLY_VERSION "' "                          \&lt;br /&gt;      "processorArchitecture='x86' "                                  \&lt;br /&gt;      "publicKeyToken='" _VC_ASSEMBLY_PUBLICKEYTOKEN "'\"")&lt;br /&gt;#else&lt;br /&gt;&lt;br /&gt;#pragma comment(linker,"/manifestdependency:\"type='win32' "            \&lt;br /&gt;      "name='" __LIBRARIES_ASSEMBLY_NAME_PREFIX ".CRT' "              \&lt;br /&gt;      "version='" _CRT_ASSEMBLY_VERSION "' "                          \&lt;br /&gt;      "processorArchitecture='x86' "                                  \&lt;br /&gt;      "publicKeyToken='" _VC_ASSEMBLY_PUBLICKEYTOKEN "'\"")&lt;br /&gt;#endif&lt;br /&gt;&lt;br /&gt;#endif /* _M_IX86 */&lt;br /&gt;&lt;/pre&gt;&lt;p&gt;This will put a little piece of code in the .obj which gets picked up by the linker and the manifest tool. So, if _DEBUG if defined &lt;i&gt;anywhere&lt;/i&gt;, you'll get manifest entries requiring the debug runtimes. So, double/triple check that you don't have any debug files or .libs in your project. The .manifest file looks like this:&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;&amp;lt;assembly xmlns="'urn:schemas-microsoft-com:asm.v1'" manifestversion="'1.0'"&gt;&lt;br /&gt;&amp;lt;trustinfo xmlns="urn:schemas-microsoft-com:asm.v3"&gt;&lt;br /&gt;  &amp;lt;security&gt;&lt;br /&gt;    &amp;lt;requestedprivileges&gt;&lt;br /&gt;      &amp;lt;requestedexecutionlevel level="'asInvoker'" uiaccess="'false'"&gt;&lt;br /&gt;      &amp;lt;/requestedexecutionlevel&gt;&lt;br /&gt;    &amp;lt;/requestedprivileges&gt;  &lt;br /&gt;  &amp;lt;/security&gt;&lt;br /&gt;&amp;lt;/trustinfo&gt;&lt;br /&gt;&amp;lt;dependency&gt;&lt;br /&gt;  &amp;lt;dependentassembly&gt;&lt;br /&gt;    &amp;lt;assemblyidentity type="'win32'" name="'Microsoft.VC90.CRT'" version="'9.0.30729.4148'" processorarchitecture="'x86'" publickeytoken="'1fc8b3b9a1e18e3b'"&gt;&lt;br /&gt;     &amp;lt;/assemblyidentity&gt;&lt;br /&gt;  &amp;lt;/dependentassembly&gt;&lt;br /&gt;&amp;lt;/dependency&gt;&lt;br /&gt;&amp;lt;dependency&gt;&lt;br /&gt;  &amp;lt;dependentassembly&gt;&lt;br /&gt;    &amp;lt;assemblyidentity type="'win32'" name="'Microsoft.VC90.MFC'" version="'9.0.30729.4148'" processorarchitecture="'x86'" publickeytoken="'1fc8b3b9a1e18e3b'"&gt;&lt;br /&gt;  &amp;lt;/assemblyidentity&gt;&lt;br /&gt;  &amp;lt;/dependentassembly&gt;&lt;br /&gt;&amp;lt;/dependency&gt;&lt;br /&gt;&amp;lt;/assembly&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;The big thing to note is the &lt;i&gt;version&lt;/i&gt; of the runtime. How does Visual Studio know which version of the runtime to load? Well, it uses &lt;tt&gt;\Program Files\Microsoft Visual Studio 9.0\VC\include\crtassess.h&lt;/tt&gt; to make this decision. Whenever you install a new Service Pack for Visual Studio this file gets updated.&lt;/p&gt;&lt;p&gt;If you define &lt;tt&gt;_BIND_TO_CURRENT_VCLIBS_VERSION = 1&lt;/tt&gt; in your C++ code, crtassess.h will grab the latest MFC, ATL and CRT libraries, whatever they are. These are the versions that will go into the .manifest file (by the way, set up your code to embed the .manifest in your code to keep things easier).&lt;/p&gt;&lt;p&gt;On the deployment machine, you need to install all the Visual Studio runtime libraries. The best way to do this is by running the latest and greatest vcredist_x86.exe application from the microsoft site. But this has its own problems.&lt;/p&gt;&lt;p&gt;The entire version number of the assembly is important. With VS 2008 SP1, the CRT version was bumped from 9.0.21022.8 to 9.0.30729.4148, but the redist for SP1 installed 9.0.30729.1 and the program wouldn't run on the deployment machine. Turns out there was a Security Update for SP1 and a later redist program for it. I don't know how you're supposed to keep up on this other than watch the msdn forums. Once this was run on the deployment machine the program would run.&lt;/p&gt;&lt;p&gt;Another problem I ran into was the compiler kept putting entries in the manifest for the older 9.0.21022.8 crt even though I had &lt;tt&gt;_BIND_TO_CURRENT_VCLIBS_VERSION&lt;/tt&gt; defined everywhere. The workaround for this is very cryptic. You need to put the following code somewhere in your application (like in &lt;tt&gt;stdafx.h&lt;/tt&gt;)&lt;/p&gt;&lt;pre&gt;&lt;br /&gt;extern "C" { &lt;br /&gt;__declspec(selectany)       int _forceCRTManifestRTM;&lt;br /&gt;__declspec(selectany)       int _forceCRTManifestCUR;&lt;br /&gt;}; &lt;/pre&gt;&lt;p&gt;This will force the compiler to use the latest assemblies.&lt;/p&gt;&lt;p&gt;You can see how the manifests are looked up on your deployment machines by looking in &lt;tt&gt;\Windows\WinSxs&lt;/tt&gt;. You'll see the mapping of the runtime to the .dll's along with the security policies for selecting them. Using this you can quickly spot any discrepancies between your development environment and your deployment environment.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8696186-4401696797874306881?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/4401696797874306881/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=4401696797874306881' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/4401696797874306881'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/4401696797874306881'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2009/08/microsoft-vc-sxs-assemblies-manifests.html' title='Microsoft VC++ SxS Assemblies &amp; Manifests'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8696186.post-5955870379973630124</id><published>2009-08-13T11:20:00.002-03:00</published><updated>2009-08-13T11:21:00.389-03:00</updated><title type='text'>Some Changes ...</title><content type='html'>I've nuked my old blog. Since all my family photos and ramblings are on Facebook I'm going to have this site focus on public industry related topics. Stay tuned.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8696186-5955870379973630124?l=www.sandywalsh.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.sandywalsh.com/feeds/5955870379973630124/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8696186&amp;postID=5955870379973630124' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/5955870379973630124'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8696186/posts/default/5955870379973630124'/><link rel='alternate' type='text/html' href='http://www.sandywalsh.com/2009/08/some-changes.html' title='Some Changes ...'/><author><name>@TheSandyWalsh</name><uri>http://www.blogger.com/profile/17478332939768000715</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='32' src='http://4.bp.blogspot.com/_Al595rN4OWo/S5o-MXFWibI/AAAAAAAAAFk/TKOxZTZ7w4A/S220/me.jpg'/></author><thr:total>0</thr:total></entry></feed>
