<?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-8219433387840123988</id><updated>2011-08-08T06:44:52.720-05:00</updated><category term='Scrum'/><title type='text'>Michael's Technical Blog</title><subtitle type='html'>I am a C#.NET programmer interested in Test-Driven development, Agile methodologies, and Domain-driven design.</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>27</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8219433387840123988.post-720051844736882546</id><published>2010-07-12T13:18:00.007-05:00</published><updated>2010-07-12T15:28:58.033-05:00</updated><title type='text'>Dependency Injection: The Testability Enabler</title><content type='html'>Whenever I talk to a team that wants to do unit testing, the inevitable counterarguments always revolve around testability of existing legacy code.  &lt;a href="http://www.amazon.com/Working-Effectively-Legacy-Michael-Feathers/dp/0131177052"&gt;Michael Feathers'&lt;/a&gt; excellent book on the topic of testing existing code gives a good argument to any counterarguments to unit testing, but I can sum it all up in one post: you can test just about anything with one simple pattern: &lt;a href="http://martinfowler.com/articles/injection.html"&gt;Dependency Injection&lt;/a&gt;.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;When people aren't designing for testability, they often create designs like this:&lt;/div&gt;&lt;br /&gt;&lt;pre class="brush:csharp"&gt;&lt;br /&gt;public class Program&lt;br /&gt;{&lt;br /&gt;  public void UpdateSalaries()&lt;br /&gt;  {&lt;br /&gt;    Database d = new Database("connection-string");&lt;br /&gt;    d.ExecuteSql("UPDATE Employee SET Salary = 1000000 where LastName = 'Hedgpeth');&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;So they come to my meeting talking about testability and say to themselves, "There's no way that can be tested."  That's not true with Dependency Injection.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;With dependency injection, you simply take the responsibility of creating the database object &lt;i&gt;away &lt;/i&gt;from the object you are testing.  Then, in the test environment, you pass in a fake that you control.  So our test becomes:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre class="brush:csharp"&gt;&lt;br /&gt;[Test]&lt;br /&gt;public void UpdateSalaries_ShouldPayMeAMillionDollars()&lt;br /&gt;{&lt;br /&gt;  var database = new Mock&lt;idatabase&gt;();&lt;br /&gt;  Program program = new Program();&lt;br /&gt;  program.UpdateSalaries(database.Object);&lt;br /&gt;&lt;br /&gt;  database.Verify(d =&gt; d.ExecuteSql(Program.MakeMySalaryAMilionDollarsSqlText);&lt;br /&gt;}&lt;br /&gt;&lt;/idatabase&gt;&lt;/pre&gt;&lt;br /&gt;And the code to test:&lt;br /&gt;&lt;pre class="brush:csharp"&gt;&lt;br /&gt;public class Program&lt;br /&gt;{&lt;br /&gt;  public const string MakeMySalaryAMillionDollarsSqlText = "UPDATE Employee SET Salary = 1000000 where LastName = 'Hedgpeth'";&lt;br /&gt;&lt;br /&gt;  public void UpdateSalaries(IDatabase database)&lt;br /&gt;  {&lt;br /&gt;    database.ExecuteSql(MakeMySalaryAMillionDollarsSqlText);&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;You really have little excuse to not test when you know the dependency injection pattern.  While there are more complicated patterns for creating a testable design, I've found that this pattern is all you need a vast majority of the time.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-5055304-2");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8219433387840123988-720051844736882546?l=michaelstechnical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/720051844736882546/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8219433387840123988&amp;postID=720051844736882546' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/720051844736882546'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/720051844736882546'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/2010/07/dependency-injection-testability.html' title='Dependency Injection: The Testability Enabler'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8219433387840123988.post-2340209325030716435</id><published>2009-09-10T06:31:00.002-05:00</published><updated>2009-09-10T06:31:51.946-05:00</updated><title type='text'>Another attempt at being cool</title><content type='html'>Today I'm going to try out a &lt;a href="http://flanders.co.nz/2008/03/08/color-scheme-for-visual-studio-with-resharper-and-ruby-in/"&gt;black theme in Visual Studio&lt;/a&gt;.  Maybe I can be cool like those hipster Ruby people.&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-5055304-2");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8219433387840123988-2340209325030716435?l=michaelstechnical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/2340209325030716435/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8219433387840123988&amp;postID=2340209325030716435' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/2340209325030716435'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/2340209325030716435'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/2009/09/another-attempt-at-being-cool.html' title='Another attempt at being cool'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8219433387840123988.post-7830640533884853233</id><published>2009-09-09T06:11:00.005-05:00</published><updated>2010-07-12T15:31:01.020-05:00</updated><title type='text'>NHibernate collection element has wrong number of columns</title><content type='html'>I recently got this error with NHibernate: &lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:csharp"&gt;&lt;br /&gt;NHibernate.MappingException: collection element mapping has wrong number of columns: ClassName.PropertyName type: component[PropertyName,Expected,Actual]&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I was trying to map an existing structure I had matured without persistence.  The class is:&lt;br /&gt;&lt;br /&gt;&lt;pre  class="brush:csharp"&gt;&lt;br /&gt;public class Difference {&lt;br /&gt;  public string PropertyName { get; set; }&lt;br /&gt;  public object Expected { get; set; }&lt;br /&gt;  public object Actual { get; set; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The problem is NHibernate doesn't know what to do with the objects and so it throws that error.  My solution was to change the class to string values, so NHibernate would know how to persist them:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:csharp"&gt;&lt;br /&gt;public class Difference {&lt;br /&gt;  public string PropertyName { get; set; }&lt;br /&gt;  public string Expected { get; set; }&lt;br /&gt;  public string Actual { get; set; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-5055304-2");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8219433387840123988-7830640533884853233?l=michaelstechnical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/7830640533884853233/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8219433387840123988&amp;postID=7830640533884853233' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/7830640533884853233'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/7830640533884853233'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/2009/09/nhibernate-collection-element-has-wrong.html' title='NHibernate collection element has wrong number of columns'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8219433387840123988.post-6307817826160902086</id><published>2009-09-09T06:04:00.003-05:00</published><updated>2010-07-12T15:31:59.201-05:00</updated><title type='text'>NHibernate instance not of expected entity type error</title><content type='html'>When you get this message in NHibernate:&lt;br /&gt;&lt;pre class="brush:csharp"&gt;&lt;br /&gt;NHibernate.HibernateException: instance not of expected entity type: DerivedClass is not a: IMyInterface&lt;br /&gt;at NHibernate.Persister.Entity.AbstractEntityPersister.GetSubclassEntityPersister(Object instance, ISessionFactoryImplementor factory, EntityMode entityMode) in c:\CSharp\NH\nhibernate\src\NHibernate\Persister\Entity\AbstractEntityPersister.cs: line 3864&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;It means that you're trying to relate to a class that is not mapped in the NHibernate mapping.  This happened to me because I was using a test fake when testing my NHibernate mappings with SQLLite.  The solution is to only use real, mapped classes when testing with NHibernate persistence.&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-5055304-2");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8219433387840123988-6307817826160902086?l=michaelstechnical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/6307817826160902086/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8219433387840123988&amp;postID=6307817826160902086' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/6307817826160902086'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/6307817826160902086'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/2009/09/nhibernate-instance-not-of-expected.html' title='NHibernate instance not of expected entity type error'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8219433387840123988.post-6915127025444956141</id><published>2009-06-30T12:06:00.003-05:00</published><updated>2010-07-12T15:32:27.866-05:00</updated><title type='text'>StaleStateException in Nhibernate with Unexpected Row Count</title><content type='html'>If you get this exception:&lt;br /&gt;&lt;br /&gt;&lt;pre class="brush:csharp"&gt;&lt;br /&gt;NHibernate.StaleStateException: Unexpected row count: 0; expected: 1&lt;br /&gt;at NHibernate.AdoNet.Expectations.BasicExpectation.VerifyOutcomeNonBatched(Int32 rowCount, IDbCommand statement) in c:\CSharp\NH\nhibernate\src\NHibernate\AdoNet\Expectations.cs: line 29&lt;br /&gt;at NHibernate.AdoNet.NonBatchingBatcher.AddToBatch(IExpectation expectation) in c:\CSharp\NH\nhibernate\src\NHibernate\AdoNet\NonBatchingBatcher.cs: line 40&lt;br /&gt;at NHibernate.Persister.Entity.AbstractEntityPersister.Update(Object id, Object[] fields, Object[] oldFields, Object rowId, Boolean[] includeProperty, Int32 j, Object oldVersion, Object obj, SqlCommandInfo sql, ISessionImplementor session) in c:\CSharp\NH\nhibernate\src\NHibernate\Persister\Entity\AbstractEntityPersister.cs: line 2754&lt;br /&gt;at NHibernate.Persister.Entity.AbstractEntityPersister.UpdateOrInsert(Object id, Object[] fields, Object[] oldFields, Object rowId, Boolean[] includeProperty, Int32 j, Object oldVersion, Object obj, SqlCommandInfo sql, ISessionImplementor session) in c:\CSharp\NH\nhibernate\src\NHibernate\Persister\Entity\AbstractEntityPersister.cs: line 2666&lt;br /&gt;at NHibernate.Persister.Entity.AbstractEntityPersister.Update(Object id, Object[] fields, Int32[] dirtyFields, Boolean hasDirtyCollection, Object[] oldFields, Object oldVersion, Object obj, Object rowId, ISessionImplementor session) in c:\CSharp\NH\nhibernate\src\NHibernate\Persister\Entity\AbstractEntityPersister.cs: line 2940&lt;br /&gt;at NHibernate.Action.EntityUpdateAction.Execute() in c:\CSharp\NH\nhibernate\src\NHibernate\Action\EntityUpdateAction.cs: line 78&lt;br /&gt;at NHibernate.Engine.ActionQueue.Execute(IExecutable executable) in c:\CSharp\NH\nhibernate\src\NHibernate\Engine\ActionQueue.cs: line 130&lt;br /&gt;at NHibernate.Engine.ActionQueue.ExecuteActions(IList list) in c:\CSharp\NH\nhibernate\src\NHibernate\Engine\ActionQueue.cs: line 113&lt;br /&gt;at NHibernate.Engine.ActionQueue.ExecuteActions() in c:\CSharp\NH\nhibernate\src\NHibernate\Engine\ActionQueue.cs: line 147&lt;br /&gt;at NHibernate.Event.Default.AbstractFlushingEventListener.PerformExecutions(IEventSource session) in c:\CSharp\NH\nhibernate\src\NHibernate\Event\Default\AbstractFlushingEventListener.cs: line 249&lt;br /&gt;at NHibernate.Event.Default.DefaultFlushEventListener.OnFlush(FlushEvent event) in c:\CSharp\NH\nhibernate\src\NHibernate\Event\Default\DefaultFlushEventListener.cs: line 19&lt;br /&gt;at NHibernate.Impl.SessionImpl.Flush() in c:\CSharp\NH\nhibernate\src\NHibernate\Impl\SessionImpl.cs: line 1477&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Then you should look for an Id Guid that is instantiated by your object as Guid.NewGuid().  Instead, you need to use Guid.Empty (that's how NHibernate looks at an object as new).&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-5055304-2");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8219433387840123988-6915127025444956141?l=michaelstechnical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/6915127025444956141/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8219433387840123988&amp;postID=6915127025444956141' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/6915127025444956141'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/6915127025444956141'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/2009/06/stalestateexception-in-nhibernate-with.html' title='StaleStateException in Nhibernate with Unexpected Row Count'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8219433387840123988.post-8984335715316128193</id><published>2009-05-26T09:16:00.002-05:00</published><updated>2009-05-26T09:22:37.403-05:00</updated><title type='text'>A Great Overview of where I'm at</title><content type='html'>I went to an agile user group a few weeks ago and was left scratching my head a bit.  The people in the group (including the leaders) seemed to be at a place where I was a couple of years ago.  I got very little from attending.  I wondered if I'm all that smart or if I'm just delusional.  I'm sure the answer lies somewhere in the middle.&lt;br /&gt;&lt;br /&gt;Whenever I listen to what &lt;a href="http://codebetter.com/blogs/jeremy.miller/"&gt;Jeremy Miller&lt;/a&gt; has to say, I don't get that same feeling.  I see a person who is right there with where I'm at with software, except he's ahead of me and can give me good direction.  Unfortunately, there isn't much out there to direct people who have adopted my alt.net, tdd style.   &lt;a href="http://www.infoq.com/presentations/Lessons-Learned-Jeremy-Miller"&gt;This video&lt;/a&gt; is a great investment of an hour to listen to the numerous nuggets of wisdom Jeremy has to offer.&lt;br /&gt;&lt;br /&gt;By the way, I've started using &lt;a href="http://structuremap.sourceforge.net/Default.htm"&gt;StructureMap&lt;/a&gt; and love it.  I think I'll post a few blog posts on what I've done to help those who think IoC might help them.&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-5055304-2");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8219433387840123988-8984335715316128193?l=michaelstechnical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/8984335715316128193/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8219433387840123988&amp;postID=8984335715316128193' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/8984335715316128193'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/8984335715316128193'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/2009/05/great-overview-of-where-im-at.html' title='A Great Overview of where I&apos;m at'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8219433387840123988.post-8596971742744034442</id><published>2009-04-15T07:07:00.001-05:00</published><updated>2009-04-15T07:09:10.594-05:00</updated><title type='text'>StackOverflow, my new friend</title><content type='html'>I've been really impressed with how &lt;a href="http://www.stackoverflow.com"&gt;StackOverflow &lt;/a&gt;is laid out.  I've had a few questions answered very quickly with it.  If a short google search doesn't pan out, ask your question on SO and you'll get a specific, good answer within 10 minutes.&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-5055304-2");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8219433387840123988-8596971742744034442?l=michaelstechnical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/8596971742744034442/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8219433387840123988&amp;postID=8596971742744034442' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/8596971742744034442'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/8596971742744034442'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/2009/04/stackoverflow-my-new-friend.html' title='StackOverflow, my new friend'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8219433387840123988.post-4100729168680758446</id><published>2009-04-09T23:18:00.001-05:00</published><updated>2009-04-09T23:19:50.721-05:00</updated><title type='text'>As much as I love Resharper,</title><content type='html'>It probably wasn't a good idea to use 4.5 on the first day it was released.  I've had a few crashes, a lot of slowdowns.  Reminds me of the early days.&lt;br /&gt;&lt;br /&gt;They'll fix it in a week or so...I'm debating whether I should go back to 4.1 or stay where I'm at and suffer...&lt;br /&gt;&lt;br /&gt;On the positive note, the new rename is nice with the auto-complete.&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-5055304-2");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8219433387840123988-4100729168680758446?l=michaelstechnical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/4100729168680758446/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8219433387840123988&amp;postID=4100729168680758446' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/4100729168680758446'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/4100729168680758446'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/2009/04/as-much-as-i-love-resharper.html' title='As much as I love Resharper,'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8219433387840123988.post-2189314227195338320</id><published>2009-03-26T11:40:00.003-05:00</published><updated>2009-03-26T11:46:27.463-05:00</updated><title type='text'>A Matter of Perspective</title><content type='html'>Three people walk up to me.  The first is a developer starting on my project.  He asks, "So how do we do things around here?"  I say, we do &lt;a href="http://www.extremeprogramming.org/"&gt;XP&lt;/a&gt;. &lt;br /&gt;&lt;br /&gt;Next, walks up a new project manager assigned to my project.  He asks, "So what is our process?"  I say, we do &lt;a href="http://www.controlchaos.com/"&gt;Scrum&lt;/a&gt; without time-boxed iterations (or, in another way, with 2-3 day iterations).&lt;br /&gt;&lt;br /&gt;Finally, an executive walks up and asks, "How does your team work?"  I say, we follow &lt;a href="http://www.poppendieck.com/"&gt;Lean Principles&lt;/a&gt; that were inspired by how &lt;a href="http://www.toyota.co.jp/en/vision/production_system/"&gt;Toyota manufactures their vehicles&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;It's all the same process.  It's just a matter of answering to the person in a way that would communicate to their expertise the best way.  I still think XP is the best way to communicate to a developer.  And lean is the best way I've found to communicate to an executive.  As for Scrum, I'm secretly hoping it goes away.&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-5055304-2");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8219433387840123988-2189314227195338320?l=michaelstechnical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/2189314227195338320/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8219433387840123988&amp;postID=2189314227195338320' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/2189314227195338320'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/2189314227195338320'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/2009/03/matter-of-perspective.html' title='A Matter of Perspective'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8219433387840123988.post-7198166845662572368</id><published>2009-03-23T09:06:00.002-05:00</published><updated>2009-03-23T09:10:52.177-05:00</updated><title type='text'>Quality versus Cost</title><content type='html'>I was listening to &lt;span style="font-style: italic;"&gt;The Toyota Way &lt;/span&gt;on my ipod on the way to work today and listened to something interesting today.  The author said, roughly, &lt;span style="font-style: italic;"&gt;If you want to focus on lowering costs, &lt;span style="font-weight: bold;"&gt;don't &lt;/span&gt;focus on lowering costs.  Instead, work to increase quality and your costs will go down&lt;/span&gt;. &lt;br /&gt;&lt;br /&gt;Sounds like a good strategy to me.  In organization, much of the inefficiencies exist as a result of lower quality, so &lt;span style="font-style: italic;"&gt;purposefully &lt;/span&gt;lowering costs (laying off people, not hiring, not buying the right tools for the job) would have the effect of lowering quality, which would make the problem worse.  At best, you would have a net 0 effect.&lt;br /&gt;&lt;br /&gt;But instead, if you look at waste in the process (or value stream as the lean people say), then you will find that much of the waste is due to poor quality.  When you address that issue, the costs go down.  Then you can either let attrition even out your workflow, or do more work and make more moeny.  I would think that most companies given that choice would take the latter.  Thus, a strategy that is good for the company's bottom line and employee's sense of security.&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-5055304-2");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8219433387840123988-7198166845662572368?l=michaelstechnical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/7198166845662572368/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8219433387840123988&amp;postID=7198166845662572368' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/7198166845662572368'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/7198166845662572368'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/2009/03/quality-versus-cost.html' title='Quality versus Cost'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8219433387840123988.post-1597079607373912772</id><published>2009-03-20T15:35:00.003-05:00</published><updated>2009-03-20T15:40:59.553-05:00</updated><title type='text'>Evangelism or Pragmatism?</title><content type='html'>I recently listened to an &lt;a href="http://altnetpodcast.com/episodes/17-the-state-of-alt-net"&gt;Alt.NET podcast&lt;/a&gt; with &lt;a href="http://ampgt.com/"&gt;Scott Bellware&lt;/a&gt; and had some thoughts.&lt;br /&gt;&lt;br /&gt;First, I thought Scott was dead-on when he described the self-indulgence and intellectual snobbery involved in the agile community.  It's bothersome, not productive, and needs to stop.&lt;br /&gt;&lt;br /&gt;Second, I was troubled by Scott's insistence that those who hold alternative views within the .NET community need to evangelize more.  We need to go to companies on nights and early mornings and show them how great this stuff is.  We need to sacrifice.&lt;br /&gt;&lt;br /&gt;Does he have a family?&lt;br /&gt;&lt;br /&gt;How about this.  How about I make a product that is obviously superior, makes my company a lot of money, and transforms my company's way of doing things?  If I do that along with everyone else in this community, don't you think &lt;span style="font-style: italic;"&gt;sooner or later &lt;/span&gt;that the market will notice, and the vast majority of Microsoftians will jump on board?&lt;br /&gt;&lt;br /&gt;This is capitalism.  Wouldn't the pragmatic approach be better than trying to "evangelize"?  I would think so.  But sadly I don't see this line of reasoning used very often...which smells like everyone is full of crap and caught up in their own intellectual thought experiment.  That's not a thought I'd like my managers to have.  And evangelism does nothing to dispel that; only solid, reliable, consistent, and game-changing results will.&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-5055304-2");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8219433387840123988-1597079607373912772?l=michaelstechnical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/1597079607373912772/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8219433387840123988&amp;postID=1597079607373912772' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/1597079607373912772'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/1597079607373912772'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/2009/03/evangelism-or-pragmatism.html' title='Evangelism or Pragmatism?'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8219433387840123988.post-524094634401929561</id><published>2009-02-10T21:53:00.003-06:00</published><updated>2009-02-10T22:01:00.525-06:00</updated><title type='text'>Would you be excited about this?</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://upload.wikimedia.org/wikipedia/en/3/35/Ipod_1G.png"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 201px; height: 320px;" src="http://upload.wikimedia.org/wikipedia/en/3/35/Ipod_1G.png" alt="" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;I was talking today with my colleague his desire to want to add a lot more features to our solution so people can be excited about what we're doing.  I'm all with him, I'd like that too, but it reminds me about how you shouldn't let your desire to really wow your customers get in the way of delivering something that will be useful to a subset of them.  You can then use the feedback they give you and the extra capital to take it even further.&lt;br /&gt;&lt;br /&gt;I'll be honest with you, I wouldn't have bought this piece of crap to my left.  But &lt;span style="font-style: italic;"&gt;someone &lt;/span&gt;did.  And they got excited about it.  Lessons were learned.  Market momentum was created, and I finally &lt;span style="font-style: italic;"&gt;did &lt;/span&gt;reach me.  I've bought two ipod products since.  I'm really glad Apple was smart enough not to keep people waiting for this ugly duckling, so I could have a refined ipod.&lt;br /&gt;&lt;br /&gt;The lesson: find in your customer base the user that's &lt;span style="font-style: italic;"&gt;really &lt;/span&gt;gunning for what you have to offer, then release something to them early and often.  You'll be surprised with how different their values are from yours, and how totally different features excite them than you.&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-5055304-2");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8219433387840123988-524094634401929561?l=michaelstechnical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/524094634401929561/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8219433387840123988&amp;postID=524094634401929561' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/524094634401929561'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/524094634401929561'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/2009/02/would-you-be-excited-about-this.html' title='Would you be excited about this?'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8219433387840123988.post-6568220018841983566</id><published>2009-02-10T07:54:00.003-06:00</published><updated>2010-07-12T15:38:40.650-05:00</updated><title type='text'>Refactoring First</title><content type='html'>The word "refactoring" means different things for different projects, depending on how much &lt;a href="http://en.wikipedia.org/wiki/Technical_debt"&gt;technical debt&lt;/a&gt; one has.  On a project with loads of technical debt, no unit tests, and very little object-orientation, refactoring can mean "get rid of everything here and replace it with something better".  On a typical agile project with good testing but little support for refactoring (i.e. viewing it as a liability), refactoring oftentimes means "the design would be better if we did X", to which the business almost always says "OK, we'll put that on the roadmap/release plan" and then does nothing.&lt;br /&gt;&lt;br /&gt;I have been on such projects in my career and have been frustrated when I could not refactor but felt it was necessary, but it has only been until recently that I've understood my role in creating the situation where technical debt was tolerated.  In the past, I would follow the TDD pattern, but I would test first, fix the test, and...hmmm....no refactoring.  I would get to the end, and I'd be done....no refactoring.  I was right there, I could have spent another day or two making the design sustainable, but I didn't.  And that falls on me.&lt;br /&gt;&lt;br /&gt;But I've learned it isn't even the refactorign &lt;span style="font-style: italic;"&gt;within &lt;/span&gt;the TDD process that's the most important thing.  It's most important that when I do a feature, I refactor the design first (yes, that means changing the design &lt;span style="font-style: italic;"&gt;without &lt;/span&gt;changing the behavior) to make it seem like I planned for the feature in advance.  Let me give an example (disclaimer: I wouldn't actually have done this refactoring, I'm just using a simple example to illustrate my point).  I have this code:&lt;br /&gt;&lt;pre class="brush:csharp"&gt;public void Copy(string sourceDirectory, string temporaryDirectory)&lt;br /&gt;{&lt;br /&gt; // do some stuff&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;So now I need to copy to a second temporary directory on a network as well.  Most of the time, even in a TDD world, we would do this:&lt;br /&gt;&lt;pre class="brush:csharp"&gt;public void Copy(string sourceDirectory, string temporaryDirectory, string networkTemporaryDirectory) { }&lt;br /&gt;&lt;/pre&gt;But in this overly simplistic example, we just added to the method signature.  It's like we said, "Oh crap, I didn't think about the network temporary directory, I'll just add it to the end."&lt;br /&gt;&lt;br /&gt;So why not do an Introduce Parameter Object refactoring &lt;span style="font-style: italic;"&gt;first&lt;/span&gt;:&lt;br /&gt;&lt;pre class="brush:csharp"&gt;public void Copy(string sourceDirectory, TemporaryDirectories temporaryDirectories) { }&lt;br /&gt;&lt;br /&gt;public class TemporaryDirectories {&lt;br /&gt; public string TemporaryDirectory { }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;and &lt;span style="font-style: italic;"&gt;then &lt;/span&gt;add the other one.  When you add it this time, it's like you had planned it all along.  And &lt;span style="font-style: italic;"&gt;this &lt;/span&gt;is what real emergent design looks like.  It doesn't look like bolting a bunch of stuff on as you fly by the seat of your pants (mixed metaphors, sorry).  It means changing your design to fit the requirements in front of you, and &lt;span style="font-style: italic;"&gt;only &lt;/span&gt;those requirements.&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-5055304-2");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8219433387840123988-6568220018841983566?l=michaelstechnical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/6568220018841983566/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8219433387840123988&amp;postID=6568220018841983566' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/6568220018841983566'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/6568220018841983566'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/2009/02/refactoring-first.html' title='Refactoring First'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8219433387840123988.post-9077110334843128854</id><published>2009-02-09T15:04:00.003-06:00</published><updated>2009-02-09T15:38:41.215-06:00</updated><title type='text'>Testing is Bunk and other arguments</title><content type='html'>I'm very pro-test-driven development. In fact, I can't see doing software any other way; it's so effective for me that even if I were on a project that does no unit testing, I'll still unit test to make sure my stuff works.&lt;br /&gt;&lt;br /&gt;It's good though, when you're into something, to read people who disagree with your approach. It helps you think. If I find myself getting immediately offended by opposition to my ideas, that's a huge red flag; I've stopped thinking and have descended into a cultic worship of some idea without regard for reason.&lt;br /&gt;&lt;br /&gt;This is why I enjoyed Joel Spolsky and Jeff Atwood &lt;a href="http://joelonsoftware.com/items/2009/01/31.html"&gt;podcast transcript&lt;/a&gt;. Joel and Jeff went on a huge rant about how dumb TDDers can be with writing so many tests and how clean code and design doesn't really matter. In short, they blasted many ideas I've been into lately.&lt;br /&gt;&lt;br /&gt;It's also good to hear from the people I respect in response to these kinds of rants, because when disagreements flare up they force you to have to make the argument. Bob Martin, who was specifically named in the podcast, had a good rant &lt;a href="http://blog.objectmentor.com/articles/2009/01/31/quality-doesnt-matter-that-much-jeff-and-joel"&gt;here&lt;/a&gt; (but maybe a little too emotional). His best response was in response to a great post by &lt;a href="http://xprogramming.com/blog/2009/02/01/quality-speed-tradeoff-youre-kidding-yourself/"&gt;Ron Jeffries&lt;/a&gt; about &lt;a href="http://blog.objectmentor.com/articles/2009/02/03/speed-kills"&gt;going fast&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Agile's ability to make you go much faster creates a bit of a dillemma for each and every feature you implement. The guy I'm working with and mentoring has commented that he could have gone faster on this particular feature if he didn't have to write the tests. Bob's comments are invaluable:&lt;br /&gt;&lt;blockquote&gt;How do you really get things done quickly? You listen to your grandparents. Remember what they told you? “Slow and steady wins the race.” and “Anything worth doing is worth doing well.” How does a professional craftsman get things done quickly? He/she adopts an attitude of calm, focuses on the problem to be solved, and then step by step solves that problem without rushing, without yielding to the need for speed, without surrendering to the desire for a quick conquest.&lt;/blockquote&gt;That's exactly correct. My colleague and I were at lunch the other day and he commented, "You know what I'm learning here is like the difference between being an amateur and a professional." Bob does a great job of describing what a true craftsman/professional programmer aspires to be.&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-5055304-2");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8219433387840123988-9077110334843128854?l=michaelstechnical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/9077110334843128854/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8219433387840123988&amp;postID=9077110334843128854' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/9077110334843128854'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/9077110334843128854'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/2009/02/testing-is-bunk-and-other-arguments.html' title='Testing is Bunk and other arguments'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8219433387840123988.post-3925015906898901035</id><published>2009-01-29T10:12:00.002-06:00</published><updated>2009-01-29T10:21:24.907-06:00</updated><title type='text'>What's wrong with Agile Part 3: People just don't "get" it</title><content type='html'>One of the frustrations I've had over the years trying to "evangelize" agile is that it doesn't seem very intuitive to most people, at least at first.  Let's take unit testing for example.&lt;br /&gt;&lt;br /&gt;Why would you want developers to do the work of qa?  I reply, well, it isn't like that exactly, they're more making sure their stuff works and has a good testable design.  The skeptic replies, yeah, in a perfect world, but I have deadlines.  I'll sit on the sidelines while you ruin &lt;span style="font-style: italic;"&gt;your &lt;/span&gt;project with that unrealistic, pie in the sky crap.&lt;br /&gt;&lt;br /&gt;This is frustrating because I've seen how well unit testing works and it seems like such a slam dunk to &lt;span style="font-style: italic;"&gt;me, &lt;/span&gt;but for whatever reason people just don't "get" it.  If I take this further, I end up throwing my hands up in the air, and wondering why the world isn't as smart as me.&lt;br /&gt;&lt;br /&gt;Well, maybe there is a &lt;a href="http://www.biblegateway.com/passage/?book_id=66&amp;amp;chapter=4&amp;amp;verse=6&amp;amp;version=31&amp;amp;context=verse"&gt;better way&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;How about this: I unit test on my project and demonstrate marketable features faster than the customer can think them up and make the company a ton of money.  People "get" money, customer satisfaction.  But especially &lt;span style="font-style: italic;"&gt;money&lt;/span&gt;.  And hey, if I can't translate unit testing into cash for my company then I have no business unit testing.&lt;br /&gt;&lt;br /&gt;So now we're off of the ideological ivory tower and even with the rest of the projects out there.  It feels great not having to argue the ideas as much, and just tell people, "I'll deliver defect-free features faster than you know how to ask for them."  Now it's time to deliver...&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-5055304-2");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8219433387840123988-3925015906898901035?l=michaelstechnical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/3925015906898901035/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8219433387840123988&amp;postID=3925015906898901035' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/3925015906898901035'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/3925015906898901035'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/2009/01/whats-wrong-with-agile-part-3-people.html' title='What&apos;s wrong with Agile Part 3: People just don&apos;t &quot;get&quot; it'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8219433387840123988.post-5535923384386230008</id><published>2009-01-29T08:27:00.005-06:00</published><updated>2010-07-12T15:41:12.242-05:00</updated><title type='text'>Actions, Funcs, and Predicates, oh my!</title><content type='html'>For better or worse, C# is going down a path where you will need to become &lt;span style="font-style: italic;"&gt;very &lt;/span&gt;familiar with &lt;a href="http://msdn.microsoft.com/en-us/library/018hxwa8.aspx"&gt;Actions&lt;/a&gt;, &lt;a href="http://msdn.microsoft.com/en-us/library/bb534960.aspx"&gt;Funcs&lt;/a&gt;, and &lt;a href="http://msdn.microsoft.com/en-us/library/bfcke1bz.aspx"&gt;Predicates&lt;/a&gt;.  Not only that, but you'll need to understand them expressed as lambdas.  &lt;a href="http://mtaulty.com/CommunityServer/blogs/mike_taultys_blog/archive/2009/01/28/anonymous-methods-lambdas-confusion.aspx"&gt;This&lt;/a&gt; is a good post to bring you up to speed (H/T: &lt;a href="http://blog.cwa.me.uk/2009/01/29/the-morning-brew-275/"&gt;The Morning Brew&lt;/a&gt;).  Seriously, if you don't get it the first time read it again.  If you still don't get it, fire up Visual Studio 2008 SP1 and try it out yourself.  Much of this stuff (minus the &lt;a href="http://msdn.microsoft.com/en-us/library/bb397687.aspx"&gt;lambdas&lt;/a&gt;) is available in .NET 2.0, if you're willing to write &lt;a href="http://geekswithblogs.net/michelotti/archive/2007/08/15/114702.aspx"&gt;anonymous delegates&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Here's a sample:&lt;br /&gt;&lt;pre class="brush:csharp"&gt;&lt;br /&gt;// code that takes an action&lt;br /&gt;public void PerformActionOnAllElements&lt;t&gt;(IEnumerable&lt;t&gt; elements, Action&lt;t&gt; action)&lt;br /&gt;{&lt;br /&gt; foreach (T item in elements)&lt;br /&gt; {&lt;br /&gt;   action(T);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// the code as lambda&lt;br /&gt;List&lt;decimal&gt; pricesOnCheck = new List&lt;decimal&gt;();&lt;br /&gt;decimal subtotal = 0.0m;&lt;br /&gt;PerformActionOnAllElements(pricesOnCheck, price =&gt; subtotal += price);&lt;br /&gt;&lt;br /&gt;// or if you want to be really cool, just use the .NET built in syntax&lt;br /&gt;pricesOnCheck.ForEach(price =&gt; subtotal += price);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I first learned about this in &lt;a href="http://www.amazon.com/More-Effective-Specific-Software-Development/dp/0321485890/ref=pd_bbs_sr_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1233239447&amp;amp;sr=8-1"&gt;More Effective C#&lt;/a&gt;.  It's here to stay. So even if you hate lambdas and all that they imply, you really owe it to yourself learn it enough to be able to read code created this way. You might even find yourself writing this code after not too long...&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-5055304-2");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8219433387840123988-5535923384386230008?l=michaelstechnical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/5535923384386230008/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8219433387840123988&amp;postID=5535923384386230008' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/5535923384386230008'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/5535923384386230008'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/2009/01/actions-funcs-and-predicates-oh-my.html' title='Actions, Funcs, and Predicates, oh my!'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8219433387840123988.post-246803128823843831</id><published>2009-01-28T07:05:00.002-06:00</published><updated>2009-01-28T07:18:23.706-06:00</updated><title type='text'>What's Wrong with Agile, Part 2: Management Impedance Mismatch</title><content type='html'>In part two, I discuss another problem I see with the traditional agile model, and that's how its basic philosophy is incompatible and at odds with most managers I've met.  When you read the &lt;a href="http://www.agilemanifesto.org"&gt;agile manifesto&lt;/a&gt;, one of the phrases is this:&lt;br /&gt;&lt;blockquote&gt;&lt;span style="font-size:100%;"&gt;Individuals and interactions &lt;/span&gt;&lt;span style="font-size:100%;"&gt;over processes and tools&lt;/span&gt; &lt;/blockquote&gt;I think at some level the manifesto is correct.  It's fundamentally more important that individuals interact correctly and that they and their interactions are valued than a particular process or tool be in place.  The problem here is that most managers I've ever met view their job as putting the right &lt;span style="font-style: italic;"&gt;people &lt;/span&gt;in place within the right &lt;span style="font-style: italic;"&gt;process &lt;/span&gt;using the right &lt;span style="font-style: italic;"&gt;tools&lt;/span&gt;.  So in essence they're trying to create the right environment for others to succeed.&lt;br /&gt;&lt;br /&gt;Then the agile hotshot comes along and tells them that the processes and tools aren't important.  Only the people are.  The manager is left feeling that the agile hotshot is full of crap because she &lt;span style="font-style: italic;"&gt;knows &lt;/span&gt;that processes and tools are important.  Without them you would have leaderless chaos.  And I'm sure many agile projects out there use the manifesto to this end, and to their own detriment.  And so you have a fundamentally different mindset from a pure agile person to a pure competent manager.&lt;br /&gt;&lt;br /&gt;How have I learned to deal with it?  Well, in my new lean world, it turns out that processes and tools are much more important than I thought.  It's not that individuals and interactions are &lt;span style="font-style: italic;"&gt;not &lt;/span&gt;important, it's that they are &lt;span style="font-style: italic;"&gt;all important.&lt;/span&gt; &lt;br /&gt;&lt;br /&gt;If I were starting a project with a competent manager, I would begin by suggesting a development process and how it eliminates &lt;span style="font-style: italic;"&gt;waste &lt;/span&gt;within the product development system.  The process itself would value individuals and interactions (using pair programming, colocated teams if possible, etc.), but &lt;span style="font-style: italic;"&gt;to the manager &lt;/span&gt;that would not be the focus.  To the manager, we are eliminating waste and going from start to usable software as quickly as possible.  We are also decreasing, and even eliminating many of the tradeoffs that keeps him up all night, like whether the product should be high quality or on time (both!) or whether to release this quarter or next (next week!).&lt;br /&gt;&lt;br /&gt;This approach values &lt;span style="font-style: italic;"&gt;individuals and interactions &lt;/span&gt;in a special way–with management, who are individuals just like the rest of us and have their own set of values and philosophies.&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-5055304-2");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8219433387840123988-246803128823843831?l=michaelstechnical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/246803128823843831/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8219433387840123988&amp;postID=246803128823843831' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/246803128823843831'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/246803128823843831'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/2009/01/whats-wrong-with-agile-part-2.html' title='What&apos;s Wrong with Agile, Part 2: Management Impedance Mismatch'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8219433387840123988.post-5784395256395670814</id><published>2009-01-26T23:21:00.003-06:00</published><updated>2009-01-26T23:32:12.343-06:00</updated><title type='text'>What's wrong with Agile, Part 1: Long Feedback Loop</title><content type='html'>For my entire career, I have been very pro-agile.  Agile has done a lot for me; without its principles I wouldn't know much of what I know today.  A couple of years ago, I finally got a chance to experience a project that was "fully" agile.  The results were definately mixed.  Some good, some bad.  I'd like to write a few posts on some of the bad parts of agile.  I'll end each post with a short description of what I've since learned about how to deal with that problem.&lt;br /&gt;&lt;br /&gt;So, in no particular order, the first problem with agile that comes to mind is that it still maintains a long feedback loop within a system that does not maintain enough focus.  In English, this means you start out an iteration with the greatest of intentions, somewhere in the middle things change and everything goes to hell, and then you try to scrape by with a good enough solution at the end, after working way too many hours.  Then you have a retrospective where you think of one or two things to change, and maybe you change, but somehow you relive that hellish existence again.  It's like being trapped in the movie Groundhog Day.  It never stops.&lt;br /&gt;&lt;br /&gt;Then you go to the agile gurus and they tell you that you're not doing it correctly.  Implement the process they say.  All of it.  Hire a coach if you still don't know what they're talking about.  Is it just me, or is there something wrong with a system if you're the problem every time there is a problem?  That kind of reminds me of a cult.  I don't want to be in a cult, so I'm going to reject that.  Can it be that maybe something is fundamentally wrong with how we're doing things in the normal agile environment?&lt;br /&gt;&lt;br /&gt;I think the fundamental change that is needed is to start focusing on keeping less work partially done and on how quickly you can start a feature to it being used by a customer.  This is the basis of lean.  Three week iterations are great, but they only go so far.  By the time you're at the end of them, it's too late and you're ready to go on to the next thing.  Instead, focus on one thing at a time, limit your group to the smallest amount of work possible, and optimize that system to make it the most effective it can be.  Kanban is a great tool for doing this.&lt;br /&gt;&lt;br /&gt;It kind of reminds me of the difference between Pair Programming and Code Reviews.  With the PP way, you're constantly focusing on &lt;span style="font-style: italic;"&gt;right now&lt;/span&gt; and how you can get there the fastest with the best design.  With Code Reviews, you're trying to release the software.  Both have their place, but all other things being equal, I'll go with the continuous improvement and focus on one thing at once.&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-5055304-2");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8219433387840123988-5784395256395670814?l=michaelstechnical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/5784395256395670814/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8219433387840123988&amp;postID=5784395256395670814' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/5784395256395670814'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/5784395256395670814'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/2009/01/whats-wrong-with-agile-part-1-long.html' title='What&apos;s wrong with Agile, Part 1: Long Feedback Loop'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8219433387840123988.post-8292752334056005645</id><published>2009-01-26T08:35:00.002-06:00</published><updated>2009-01-26T08:45:35.745-06:00</updated><title type='text'>Convention over Configuration</title><content type='html'>One of the tenets of Ruby on Rails is "Convention over Configuration", which on its face seems backwards but in practice gives software a lot of power.  &lt;a href="http://129568.nant.codebetter.com/blogs/jeremy.miller/archive/2009/01/24/convention-over-configuration-in-msdn-magazine.aspx"&gt;Jeremy Miller&lt;/a&gt; has written an &lt;a href="http://msdn.microsoft.com/en-us/magazine/dd419655.aspx"&gt;article&lt;/a&gt; in MSDN magazine if you want to read more about it, but I'll offer my views here as well.&lt;br /&gt;&lt;br /&gt;The basic idea with "Convention over Configuration" is that software is much simpler, and much less wasteful if you do the same thing throughout it instead of providing configuration for anything that can possibly be configured.  This seems backwards because you &lt;em&gt;think &lt;/em&gt;that you need to make software flexible so it can easily change.  What one fails to realize here is that the configuration creates waste (in the form of complexity), and that configuration many times does not create business value.&lt;br /&gt;&lt;br /&gt;So how does this translate in the real world?  Recently I released a feature that read some information from a file on the C: drive.  Originally, I wanted to create a user-defined properties file, but I realized that all of my users already had this file on their C: drive and imposing some other way on them would increase the barriers to my feature creating business value.  So I released it reading the file from the C: drive.  You can go right to the code and see "C:\file.txt".  It's in a constant.  It's baked into the software.  No configuration.  Just convention.&lt;br /&gt;&lt;br /&gt;A few hours after I released the feature, one of the users asked why she couldn't use the file in her user directory.  She was doing things &lt;em&gt;better &lt;/em&gt;than the other users.  But again, everyone else was doing it the C: drive way.  And she didn't have any problem changing.  So rather than jump on the configuration bandwagon and make crazy xml files to solve all of these problems, I asked her to move the file from her user folder to the C: drive.  Convention over configuration.  And it works, and I'm off creating features that add value to their work instead of solve a problem for one user that could easily be solved by copying a file with simple file IO.&lt;br /&gt;&lt;br /&gt;You would think that the users would be upset by the inflexible nature of my software at this point.  In reality it's quite the opposite.  I believe this is because (1) I'm delivering them tested, quality features &lt;em&gt;that they want &lt;/em&gt;every few days, and (2) Since there's not a lot of configuration, &lt;em&gt;it just works.  &lt;/em&gt;Nothing to set up, worry about.  No complexity.  No technical speak.  Just press the button.&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-5055304-2");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8219433387840123988-8292752334056005645?l=michaelstechnical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/8292752334056005645/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8219433387840123988&amp;postID=8292752334056005645' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/8292752334056005645'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/8292752334056005645'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/2009/01/convention-over-configuration.html' title='Convention over Configuration'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8219433387840123988.post-3992496542282356943</id><published>2008-09-09T06:42:00.003-05:00</published><updated>2008-09-09T07:09:43.848-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Scrum'/><title type='text'>Hyperproductivity on Distributed Teams</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://newsimg.bbc.co.uk/media/images/44181000/jpg/_44181384_eng_sa_scrum416.jpg"&gt;&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 200px;" src="http://newsimg.bbc.co.uk/media/images/44181000/jpg/_44181384_eng_sa_scrum416.jpg" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.youtube.com/watch?v=Ht2xcIJrAXo"&gt;This&lt;/a&gt; is an excellent presentation (notes &lt;a href="http://agile-carolinas.pbwiki.com/f/Pretty+Good+Scrum+v1.pdf"&gt;here&lt;/a&gt;) by the cofounder of Scrum (Jeff Sutherland) on how to create a hyperproductive state on a distributed team.  He begins by talking about some of the fundamentals of agile development, that XP contains some of the engineering aspects of how to create a hyperproductive state, and how Scrum contains the process aspects.  &lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The process aspects come from the way Toyota runs its business, as described on the book &lt;a href="http://www.amazon.com/Toyota-Way-Jeffrey-Liker/dp/0071392319/ref=pd_bbs_sr_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1220961811&amp;amp;sr=8-1"&gt;The Toyota Way&lt;/a&gt;.  Apparently, when Toyota wants to create a new car, it gives people 90 days to create a working prototype, then it gives them a long list of things to fix on that car.  In another 90 days, when those things are fixed, it comes up with a new list.  And on and on.  &lt;a href="http://thisismichaels.blogspot.com/2008/07/rules-of-negotiation.html"&gt;Take it from me&lt;/a&gt;, you end up with a well designed car at the end of that process.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Sutherland also talks about ScrumButt, when a company says they're doing Scrum, &lt;span class="Apple-style-span" style="font-style: italic;"&gt;but &lt;/span&gt;they leave something out for one reason or another.  He mentions the &lt;a href="http://www.agilecollab.com/the-nokia-test"&gt;Nokia Test&lt;/a&gt; as a good way to determine if you're doing Scrum or not.  He has some interesting metrics on how leaving certain parts of scrum out will affect your productivity (he says it increases it 30% over the waterfall method, but compared to 400% that people can have in the hyperproductive state).  I've grown in my appreciation for how much every aspect of the Scrum process depends on one another.  If you &lt;span class="Apple-style-span" style="font-style: italic;"&gt;but &lt;/span&gt;anything, the synergy that could be created is lost, and you leave productivity on the table.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Finally, Sutherland gets to the distributed teams part of the presentation.  He quickly goes through how much distributed teams cost, which was way too fast for me, but his end result is that on a project he tracked they spent $6M to support spending a $2M to India...not good business sense.  He did note some situations where distributed teams worked (allbeit, in the extreme hyperproductive state, but in one that would make good business sense in some situations).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;He advocates &lt;span class="Apple-style-span" style="font-style: italic;"&gt;not &lt;/span&gt;separating the distributed teams.  The obvious thing to do when having a lot of distributed people is to put them all on one team, so that they're at least not distributed &lt;span class="Apple-style-span" style="font-style: italic;"&gt;to them&lt;/span&gt;, and have two teams: the distributed team and the nondistributed team.  You'll have to watch the video for all of his reasoning there, but he makes a compelling case.  This also involved establishing a "local velocity" with all resources locally and then tracking that velocity when work switched to a distributed environment.  This even won praise by senior management because it appears that the local team spent more time understanding the customer because they had to explain it to someone in another culture and country....Interesting!!! &lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-5055304-2");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8219433387840123988-3992496542282356943?l=michaelstechnical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/3992496542282356943/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8219433387840123988&amp;postID=3992496542282356943' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/3992496542282356943'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/3992496542282356943'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/2008/09/hyperproductivity-on-distributed-teams.html' title='Hyperproductivity on Distributed Teams'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8219433387840123988.post-9092085389741341649</id><published>2008-08-18T08:24:00.005-05:00</published><updated>2008-08-18T08:59:48.626-05:00</updated><title type='text'>Programming's Bottleneck</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://s7ondemand1.scene7.com/is/image/CPWM/394607_chase_6_drawer_dresser_Mary?$278x278_Detail_Image$"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer; width: 200px;" src="http://s7ondemand1.scene7.com/is/image/CPWM/394607_chase_6_drawer_dresser_Mary?$278x278_Detail_Image$" alt="" border="0" /&gt;&lt;/a&gt;I put together a couple of &lt;a href="http://www.worldmarket.com/Furniture/bedroom-furniture/dressers/Chase-6Drawer-Dresser/lev/4/productId/6683/Ne/1100001/sectionId/2868/N/1100056/categoryId/1100056/pCategoryId/1100054/gpCategoryId/1100002/Ns/TOP_SELLER_INDEX%7C1%7C%7CCATEGORY_SEQ_2904%7C0/index.pro"&gt;dressers&lt;/a&gt; we bought at &lt;a href="http://www.worldmarket.com/home.jsp"&gt;World Market&lt;/a&gt; last night which got me thinking of &lt;a href="http://en.wikipedia.org/wiki/Pair_programming"&gt;pair programming&lt;/a&gt;.  Pair programming is when two programmers work on the same problem at the same computer.  It does have an element of being counter-intuitive, because why would it save time to have to people do the same thing rather than one?  As with most things, it depends.  There are three types of projects where pair programming has different degrees of helpfulness.  Fortunately, these types of projects map very nicely to the dressers that I put together yesterday, so I will use them as a metaphor.&lt;br /&gt;&lt;h2&gt;1: Discovery then Repetition&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;Our project was to build two identical dressers.  We opened the first box and read the directions.  We didn't have the first clue as to what to do, but &lt;i&gt;we had good directions&lt;/i&gt;.  It was still difficult to figure out what to do at key points in the process where the directions were ambiguous.  When these came up, Annie and I &lt;i&gt;worked together&lt;/i&gt; to think out the solution.  Once we figured out what to do, we worked independently.  &lt;i&gt;Total time to build: 3 hours.&lt;/i&gt;&lt;br /&gt;&lt;h2&gt;2. Repetition&lt;/h2&gt;&lt;br /&gt;The second dresser that we built was exactly like the first.  We hardly looked at the directions and developed more of an assembly line mentality.  We managed each other and worked independently.  &lt;i&gt;Total time to build: 1.5 hours.&lt;/i&gt;&lt;br /&gt;&lt;h2&gt;3. Initial Prototype&lt;/h2&gt;&lt;br /&gt;We obviously didn't do this, but this is a situation where someone wants to create a dresser but it hasn't been created yet.  It gets designed and the first prototype and directions are created.  &lt;i&gt;Total time to build: days&lt;/i&gt;&lt;br /&gt;&lt;h2&gt;What is the bottleneck?&lt;/h2&gt;&lt;br /&gt;The three types of projects have differing bottlenecks.  In the first project, the major bottleneck was our ignorance.  That's what took us twice the amount of time.  We didn't know what we were doing.  Also, we made a couple of bad mistakes that made us have to unscrew the whole thing.  At one point, we were almost done but had but in a key component in backwards.  We spent the next 45 minutes recovering from that mistake.&lt;br /&gt;&lt;p&gt;In the second project, we didn't work together.  We didn't need to.  The bottleneck here was our ability to screw in screws.  Pairing in this situation would not be helpful.&lt;br /&gt;&lt;p&gt;In the third situation, working together would be essential.  If you've never built a dresser before but had good, solid carpentry skills, you would still need another person there.  The bottleneck is &lt;i&gt;not &lt;/i&gt; cutting the wood and screwing the screws in.  If you make a mistake, &lt;i&gt;you have to start over &lt;/i&gt;at this stage.&lt;br /&gt;&lt;h2&gt;Tying it to Pair Programming&lt;/h2&gt;&lt;br /&gt;Most managers I meet seem to think that programming is a Type 2 project (repetition).  If there is a productivity problem, add more people because you need more hands on the keyboard.  In fact, most if not all projects I've been on are Type 1 projects.  Yeah, there is &lt;i&gt;some &lt;/i&gt;repetitive work, but much of the work done is recovering from stupid mistakes brought about by not solving the problem before.&lt;br /&gt;&lt;p&gt;As a project becomes more agile, however, the project becomes more like a Type 3 project.  You don't have directions.  You have a business case.  You need to solve it.  And you need it to work.  Now.  So, as a project moves more in the agile direction, pair programming becomes even more of a necessity, because the bottleneck becomes less and less about how fast you can type and more and more about how fast you can accurately solve the problem.  In the latter situation, pairing up makes the most sense.&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-5055304-2");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8219433387840123988-9092085389741341649?l=michaelstechnical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/9092085389741341649/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8219433387840123988&amp;postID=9092085389741341649' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/9092085389741341649'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/9092085389741341649'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/2008/08/programmings-bottleneck.html' title='Programming&apos;s Bottleneck'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8219433387840123988.post-7755168970342753503</id><published>2008-08-11T07:18:00.004-05:00</published><updated>2008-08-12T19:41:58.377-05:00</updated><title type='text'>Threading Discoveries</title><content type='html'>I haven't been much of a threading expert throughout my career, but that is starting to be a requirement for what I'm working on, so I thought I would post some aspects of threading as I learned them.&lt;br /&gt;&lt;br /&gt;I had a situation where a worker thread needed to wait for input from the UI thread before it continued working.  I've seen this many times:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;while (true)&lt;br /&gt;{&lt;br /&gt;if (m_Form.IsReadyToContinue)&lt;br /&gt;{&lt;br /&gt;  break;&lt;br /&gt;}&lt;br /&gt;Thread.Current.Sleep(1000);&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;While this does work, it seems wrong, even if you don't know why.  Fortunately, .NET provides the AutoResetEvent.  In the form, you simply create the event as a member variable:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;private readonly AutoResetEvent m_ReadyToContinue = new AutoResetEvent(false);&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The false is the current state of the event.  An AutoResetEvent will reset itself back to "false" every time a Wait is asked for (see below).  So, when you're ready in the form, all you have to do is call the Set method:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;m_ReadyToContinue.Set();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now for the worker thread.  You need to have an instance of the same AutoResetEvent instance as well.  Here, you simply call the WaitOne method:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;// inside worker thread&lt;br /&gt;m_ReadyToContinue.WaitOne();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I wish this interface was a little more &lt;a href="http://www.martinfowler.com/bliki/FluentInterface.html"&gt;fluent&lt;/a&gt;, but what you're saying here is "Wait until one set happens."  If a Set() already happened, it will not wait at all.  This turns the hacky forloop above into a simple and elegant method call.&lt;br /&gt;&lt;br /&gt;One other warning: you should never call WaitOne on the UI thread; it's only for worker threads.  Calling it on the UI thread would cause the UI thread to freeze up.  So if you have interaction between the UI thread and a worker thread, try to make the UI thread the notifier (via the Set() method) and the worker the waiter (via the WaitOne() method).&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-5055304-2");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8219433387840123988-7755168970342753503?l=michaelstechnical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/7755168970342753503/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8219433387840123988&amp;postID=7755168970342753503' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/7755168970342753503'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/7755168970342753503'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/2008/08/threading-discoveries.html' title='Threading Discoveries'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8219433387840123988.post-3062481981753122920</id><published>2008-07-28T07:31:00.006-05:00</published><updated>2008-07-28T07:55:01.331-05:00</updated><title type='text'>Setting up Continuous Integration in 5 minutes</title><content type='html'>I recently had to add a project to TeamCity that had no MSBuild script.  At first, I thought about using the MSBuild script on my project as a starting point and editing it to match what was needed.  That would have taken me a couple of hours.  I didn't have a couple of hours.&lt;br /&gt;&lt;br /&gt;So, I decided to play with the solution-based building with TeamCity and was very impressed.  When you look at that feature, you think "It's going to compile it for me, but that's it."  Then you see this dialog:&lt;br /&gt;&lt;br /&gt;(Click on the image for a larger version)&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_WTfRCVaqLEg/SI28xf3i3_I/AAAAAAAAAFU/WH7Y4PfwfJA/s1600-h/buildRunner.png"&gt;&lt;img style="cursor: pointer" src="http://3.bp.blogspot.com/_WTfRCVaqLEg/SI28xf3i3_I/AAAAAAAAAFU/WH7Y4PfwfJA/s320/buildRunner.png" alt="" id="BLOGGER_PHOTO_ID_5228042301001097202" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;So in five minutes, you can have continuous integration set up with compilation, code analysis, and unit tests running!  You can even add artifacts if you know the path to the artifacts.&lt;br /&gt;&lt;br /&gt;Your needs &lt;span style="font-style: italic;"&gt;will &lt;/span&gt;increase, but for a starter project that has &lt;span style="font-style: italic;"&gt;no &lt;/span&gt;build process, this is a pretty nice and cost-effective introduction.&lt;br /&gt;&lt;br /&gt;By the way, I'm using TeamCity 4.0 EAP.&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-5055304-2");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8219433387840123988-3062481981753122920?l=michaelstechnical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/3062481981753122920/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8219433387840123988&amp;postID=3062481981753122920' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/3062481981753122920'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/3062481981753122920'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/2008/07/setting-up-continuous-integration-in-5.html' title='Setting up Continuous Integration in 5 minutes'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_WTfRCVaqLEg/SI28xf3i3_I/AAAAAAAAAFU/WH7Y4PfwfJA/s72-c/buildRunner.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8219433387840123988.post-6754198371205152272</id><published>2008-07-28T07:21:00.001-05:00</published><updated>2008-07-28T07:24:18.028-05:00</updated><title type='text'>TeamCity Personal Build Behaviors, Part 3</title><content type='html'>I have absolutely loved getting to know the &lt;a href="http://www.jetbrains.com/teamcity/delayed_commit.html"&gt;personal build feature&lt;/a&gt; because using it has saved me so much time this week.  I've found that when you can trust what it's doing, and know when it doesn't do what you expect, you'll use it a lot, even when you know that there are unit tests that are failing.  You'll do this just to give you the information on the ones that you haven't run, or to give you code analysis errors.  It's truly addicting.  After all, why tie up your machine when another machine will do all of the work for you!&lt;br /&gt;&lt;br /&gt;That being said, there are some boundary cases I wanted to share to help you learn what's going on with these features.  Hopefully you'll be able to use the feature more with the gained understanding.&lt;br /&gt;&lt;br /&gt;Scenario 1: &lt;span style="font-weight: bold; color: rgb(0, 153, 0);"&gt;Pass&lt;/span&gt;&lt;br /&gt;Edit File A (don't save)&lt;br /&gt;Run a personal Build&lt;br /&gt;&lt;br /&gt;I would expect it to save the file then run the personal build on that saved file.  It does do that; you don't have to worry about if you've saved your files.&lt;br /&gt;&lt;br /&gt;Scenario 2: &lt;span style="font-weight: bold; color: rgb(204, 0, 0);"&gt;Fail&lt;/span&gt;&lt;br /&gt;Edit File A (save)&lt;br /&gt;Run a personal build&lt;br /&gt;Close visual studio&lt;br /&gt;Wait until build finishes&lt;br /&gt;&lt;br /&gt;I would expect it to check in the files even though you closed visual studio.  It does NOT do that.  The personal build succeeds, and TeamCity says that you have committed the build, but when you look at source control, it did not commit your changeset.  This is because Visual Studio will check in the files on your machine.  If it's not open, it won't even do that.&lt;br /&gt;&lt;br /&gt;Scenario 3: &lt;span style="font-weight: bold; color: rgb(204, 0, 0);"&gt;Fail&lt;/span&gt;&lt;br /&gt;Edit File A (save)&lt;br /&gt;Run a personal build&lt;br /&gt;Close visual studio&lt;br /&gt;Open visual studio&lt;br /&gt;Wait until build finishes&lt;br /&gt;&lt;br /&gt;I would expect it to check in the files when the personal build passes, but it does not do this.  It will only check in the files on your behalf if you keep the session of visual studio open that initiated the personal build.&lt;br /&gt;&lt;br /&gt;This means no reboots while personal builds are running!&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-5055304-2");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8219433387840123988-6754198371205152272?l=michaelstechnical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/6754198371205152272/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8219433387840123988&amp;postID=6754198371205152272' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/6754198371205152272'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/6754198371205152272'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/2008/07/teamcity-personal-build-behaviors-part_4902.html' title='TeamCity Personal Build Behaviors, Part 3'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8219433387840123988.post-155613774887344589</id><published>2008-07-28T07:10:00.003-05:00</published><updated>2008-07-28T07:21:14.142-05:00</updated><title type='text'>TeamCity Personal Build Behaviors, Part 2</title><content type='html'>In my &lt;a href="http://michaelstechnical.blogspot.com/2008/07/teamcity-personal-build-behaviors-part.html"&gt;previous post&lt;/a&gt;, I outlined how &lt;a href="http://www.jetbrains.com/teamcity/index.html"&gt;TeamCity&lt;/a&gt; keeps files checked out when &lt;a href="http://www.jetbrains.com/teamcity/delayed_commit.html"&gt;running a personal build&lt;/a&gt;, and checks them in automatically.&lt;br /&gt;&lt;br /&gt;Which leads to another question: what happens when you need to go back to the changeset you are running a personal build against and fix some problems from &lt;span style="font-style: italic;"&gt;that &lt;/span&gt;build?  That risk may keep you from charging forward and making drastic changes to your code because you wanted to commit at a certain point and don't want your new changes committed yet.&lt;br /&gt;&lt;br /&gt;Fortunately, TeamCity helps you out here.  When you run a personal build, they'll actually shelve that code on &lt;a href="http://msdn.microsoft.com/en-us/library/ms181237%28VS.80%29.aspx"&gt;Team Foundation Server&lt;/a&gt;:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_WTfRCVaqLEg/SI24-i_lpBI/AAAAAAAAAFM/ADkgdtxYgFU/s1600-h/2008-07-28_0717.png"&gt;&lt;img style="cursor: pointer; width: 370px; height: 343px;" src="http://3.bp.blogspot.com/_WTfRCVaqLEg/SI24-i_lpBI/AAAAAAAAAFM/ADkgdtxYgFU/s320/2008-07-28_0717.png" alt="" id="BLOGGER_PHOTO_ID_5228038127131927570" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;The "Delayed commit" is what TeamCity adds to your shelveset.&lt;br /&gt;&lt;br /&gt;If you run into problems, you can simply&lt;br /&gt;&lt;br /&gt;(1) shelve what you're working on,&lt;br /&gt;(2) unshelve the personal build,&lt;br /&gt;(3) fix the problem,&lt;br /&gt;(4) run a new personal build against that code, and&lt;br /&gt;(5) unshelve the code from (1) above and keep working.&lt;br /&gt;&lt;br /&gt;This should be rare and is relatively straightforward, so it's the workflow I have in the back of my mind to keep me from being afraid to run personal builds.&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-5055304-2");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8219433387840123988-155613774887344589?l=michaelstechnical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/155613774887344589/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8219433387840123988&amp;postID=155613774887344589' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/155613774887344589'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/155613774887344589'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/2008/07/teamcity-personal-build-behaviors-part_28.html' title='TeamCity Personal Build Behaviors, Part 2'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_WTfRCVaqLEg/SI24-i_lpBI/AAAAAAAAAFM/ADkgdtxYgFU/s72-c/2008-07-28_0717.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8219433387840123988.post-3490187814309452083</id><published>2008-07-28T06:59:00.003-05:00</published><updated>2008-07-28T07:10:19.228-05:00</updated><title type='text'>TeamCity Personal Build Behaviors, Part 1</title><content type='html'>&lt;img src="file:///C:/DOCUME%7E1/MHEDGP%7E1/LOCALS%7E1/Temp/moz-screenshot-1.jpg" alt="" /&gt;One of the things that keeps me from running more personal builds more often on &lt;a href="http://www.jetbrains.com/teamcity/index.html"&gt;TeamCity&lt;/a&gt; is that it keeps my files checked out on &lt;a href="http://msdn.microsoft.com/en-us/library/ms181237%28VS.80%29.aspx"&gt;Team Foundation Server&lt;/a&gt; while running the &lt;a href="http://www.jetbrains.com/teamcity/delayed_commit.html"&gt;personal build&lt;/a&gt;.  So (the thought went) I had to wait for the personal build to succeed before making any additional changes because it didn't check my files in yet.  Usually a company like &lt;a href="http://www.jetbrains.com/"&gt;Jetbrains&lt;/a&gt; is a little smarter than that, so I decided to do a little test.  Here's what I did:&lt;br /&gt;&lt;br /&gt;(1) Make an edit to File A&lt;br /&gt;(2) Make an edit to File B&lt;br /&gt;(3) Run a personal build with both files checked and "Commit if successful" checked.&lt;br /&gt;(4) Make an additional edit to File B&lt;br /&gt;(5) Make an edit to File C&lt;br /&gt;&lt;br /&gt;So, when the personal build happened, if TeamCity is doing the right thing, I would expect:&lt;br /&gt;File A to be checked in&lt;br /&gt;Only the original change to File B to be checked in&lt;br /&gt;File B still checked out with changes made in (4)&lt;br /&gt;File C still checked out&lt;br /&gt;&lt;br /&gt;This is exactly what happens.  TeamCity is smart enough to check the file in for you but keep the files checked out on your machine that you have changed since you ran your personal build.  So you're free to keep working with a personal build running.  That saves a lot of time!&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-5055304-2");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8219433387840123988-3490187814309452083?l=michaelstechnical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/3490187814309452083/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8219433387840123988&amp;postID=3490187814309452083' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/3490187814309452083'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/3490187814309452083'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/2008/07/teamcity-personal-build-behaviors-part.html' title='TeamCity Personal Build Behaviors, Part 1'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8219433387840123988.post-7416249889441919043</id><published>2008-07-28T05:15:00.003-05:00</published><updated>2008-07-28T05:23:45.247-05:00</updated><title type='text'>Thus, this</title><content type='html'>Over the years, I have had quite a bit to say about technical issues.  I'll often search for an issue I'm working with and find it in a blog and (to myself) thank the person who bothered to post that tidbit of information that ended up saving me quite a bit of time.  Sometimes, I'll realize that &lt;span style="font-style: italic;"&gt;I &lt;/span&gt;should blog that tidbit of information that&lt;span style="font-style: italic;"&gt; &lt;/span&gt;I didn't find with a search, for any other reason than to make the world a better place.&lt;br /&gt;&lt;br /&gt;I've thought about putting those types of posts on my &lt;a href="http://thisismichaels.blogspot.com"&gt;regular blog&lt;/a&gt; before, but it didn't seem right because when I tell most people what I do, the first thing they ask is whether I can fix their printer.  So I've realized that blogging about &lt;a href="http://www.jetbrains.com/teamcity/index.html"&gt;TeamCity&lt;/a&gt; or &lt;a href="http://xunitpatterns.com/"&gt;test-driven development patterns&lt;/a&gt; can only serve to alienate my already depleted readership.&lt;br /&gt;&lt;br /&gt;I've also in the past sent an email out to the colleagues I think would be interested in that information, but that has the drawbacks of (1) not being searchable for the rest of the world, (2) cluttering up their email inbox, and (3) having to guess who would &lt;span style="font-style: italic;"&gt;want &lt;/span&gt;to read what I say.  This way, they can subscribe to the RSS with &lt;a href="http://reader.google.com"&gt;Google Reader&lt;/a&gt; and read it when they want to.&lt;br /&gt;&lt;br /&gt;Thus, this.&lt;div class="blogger-post-footer"&gt;&lt;script type="text/javascript"&gt;
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
&lt;/script&gt;
&lt;script type="text/javascript"&gt;
var pageTracker = _gat._getTracker("UA-5055304-2");
pageTracker._initData();
pageTracker._trackPageview();
&lt;/script&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8219433387840123988-7416249889441919043?l=michaelstechnical.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://michaelstechnical.blogspot.com/feeds/7416249889441919043/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8219433387840123988&amp;postID=7416249889441919043' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/7416249889441919043'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8219433387840123988/posts/default/7416249889441919043'/><link rel='alternate' type='text/html' href='http://michaelstechnical.blogspot.com/2008/07/thus-this.html' title='Thus, this'/><author><name>Michael Hedgpeth</name><uri>http://www.blogger.com/profile/01925933242011983232</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://2.bp.blogspot.com/_WTfRCVaqLEg/TDtb68lBp1I/AAAAAAAAAQA/GDMu50jibHA/S220/Michael.jpg'/></author><thr:total>0</thr:total></entry></feed>
