<?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-18079639</id><updated>2012-01-19T15:21:26.407-05:00</updated><category term='ruby'/><category term='continuous learning'/><category term='tester&apos;s role'/><category term='dependency injection'/><category term='change management'/><category term='IoC'/><category term='refactoring'/><category term='process'/><category term='OOD'/><category term='MVP'/><category term='visual studio'/><category term='objective-c'/><category term='dojo'/><category term='iphone'/><category term='jobs'/><category term='agile'/><category term='ios'/><category term='mocking'/><category term='process improvement'/><category term='twitter'/><category term='rails'/><category term='RoR'/><category term='unit testing'/><category term='quality'/><category term='agile design'/><category term='reshaper'/><category term='testing'/><title type='text'>Life, Teams, and Software Engineering</title><subtitle type='html'>Comments on collaboration, practices, 

and technology on Software projects</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://mlb5000behrend.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://mlb5000behrend.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Matthew Baker</name><uri>http://www.blogger.com/profile/09130722872162097459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_uqEMM3AOKNY/TO141z47zYI/AAAAAAAAACU/03UsFYn4Rxo/S220/41768_9328753_3338_n.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>22</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-18079639.post-6037193819945297623</id><published>2012-01-19T15:21:00.000-05:00</published><updated>2012-01-19T15:21:26.412-05:00</updated><title type='text'>Template Messed Up</title><content type='html'>Ya, so my template is messed up. &amp;nbsp;Apparently backing up and restoring your template in Blogger doesn't guarantee that it will restore exactly as you left it. &amp;nbsp;I'll get to it soon enough, along with some actual content since it's been forever and a half since I posted anything.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18079639-6037193819945297623?l=mlb5000behrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mlb5000behrend.blogspot.com/feeds/6037193819945297623/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18079639&amp;postID=6037193819945297623' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/6037193819945297623'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/6037193819945297623'/><link rel='alternate' type='text/html' href='http://mlb5000behrend.blogspot.com/2012/01/template-messed-up.html' title='Template Messed Up'/><author><name>Matthew Baker</name><uri>http://www.blogger.com/profile/09130722872162097459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_uqEMM3AOKNY/TO141z47zYI/AAAAAAAAACU/03UsFYn4Rxo/S220/41768_9328753_3338_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18079639.post-5001122572884110689</id><published>2011-08-22T19:52:00.001-04:00</published><updated>2011-08-22T19:55:20.481-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quality'/><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'>Quality is Not an Option</title><content type='html'>While I'm hardly the first to talk about the "&lt;a href="http://martinfowler.com/bliki/TradableQualityHypothesis.html"&gt;Tradable Quality Hypothesis&lt;/a&gt;" hopefully I can reinforce in some of my readers (all 10 of you :) ) that Quality is not an option. &amp;nbsp;You cannot choose to lower quality (or forego quality producing/assurance practices) in an effort to get more features "done" or to deliver work more quickly. &amp;nbsp;At least not for any realistic amount of time. &amp;nbsp;If you do this, you might as well plan the rewrite into the schedule now.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;So What if I Do?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Immediately, you will probably feel little consequence from omitting a few test environments or writing up those features without any unit tests. &amp;nbsp;But I promise it will catch up with you. &amp;nbsp;Failing to test (at any level), continuing to use outdated tools (without a transition plan), and knowingly adding functionality of little to no explicit value contribute to decaying codebases where bug counts and cost of change increase, while overall velocity (i.e. the rate of value addition) will decrease. &amp;nbsp;If you skip testing it now, guess what? &amp;nbsp;You'll end up testing it a lot more when those bug reports start rolling in.&lt;br /&gt;&lt;br /&gt;Yes, you might get to be a hero; and everyone loves a hero, right? &amp;nbsp;Maybe. &amp;nbsp;But when a situation arises where heroics are necessary (e.g. long nights &amp;amp; weekends) just to hit normal commitments teams should not celebrate. &amp;nbsp;That person has just set the precedent for what your clients and customers will expect of the team from this point forward. &amp;nbsp;Resist the urge to be a hero and be a member of the team. &amp;nbsp;Pull each other up as best you can to pull it in at the end, but be careful not to introduce large variances that can invalidate your velocity for that iteration.&lt;br /&gt;&lt;br /&gt;If your team is delivering less and less because you're trying to catch up with bug reports you may never be able to make up that time. &amp;nbsp;This can not only harm your organization's reputation, but your personal or professional reputation as well. &amp;nbsp;Considering that, is it really worth the risk?&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;How to avoid the hole and dig out&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;There are many ways to avoid getting into the position of deciding to trade off quality for short-term schedule benefits.&lt;br /&gt;&lt;br /&gt;One word: discipline. &amp;nbsp;Be&amp;nbsp;vigilant that everything you contribute is tested in multiple ways (unit, integration, UI, etc.), have as many people as possible review your work and provide input, and make sure those things keep happening. &amp;nbsp;Yes it's hard and can look to the uninitiated as if you're moving more slowly, but when that thing you just wrote inevitably changes next week you'll appreciate putting forth the extra effort.&lt;br /&gt;&lt;br /&gt;Next is education. &amp;nbsp;Everyone should understand (though not necessarily intimately) what goes into delivering functionality. &amp;nbsp;Establish your definition of done and make it well known. &amp;nbsp;Hang it on the walls. &amp;nbsp;Recite it at the beginning of each daily standup. &amp;nbsp;I don't care how people remember it, just that they do. &amp;nbsp;Whenever something is untested, it's not really done yet.&lt;br /&gt;&lt;br /&gt;If you've found yourself in this unenviable position, the first step is to admit that you have a problem. &amp;nbsp;Seriously. &amp;nbsp;We're all proud of our solutions but sometimes they need cut down and replanted. &amp;nbsp;There's no shame in it, I promise. &amp;nbsp;There's only shame in voluntary insanity (doing the same thing over and over again and expecting different results).&lt;br /&gt;&lt;br /&gt;Next, come up with a plan of how to tackle what is most commonly the real problem: technical debt. &amp;nbsp;Technical debt is any sub-par component of your entire solution space. &amp;nbsp;This could be anything from an inflexible test harness, to untestable or scary to change code, to relying on outdated or unsupported software packages. &amp;nbsp;If it causes you pain on or disappointment on the development side, it likely falls in here. &amp;nbsp;Environmental or issues external to the team should be raised to the team's manager (e.g. Scrum Master) for them to deal with outside the team. &amp;nbsp;You need to identify and manage this technical debt before there is any hope of a sustainable pace of quality and value.&lt;br /&gt;&lt;br /&gt;Don't try to make it perfect, just make it better. &amp;nbsp;Don't feel bad about it, what worked for a team of 5 and 100000 lines of code may just not scale to a larger team or codebase. &amp;nbsp;Our products grow and so our development support infrastructure must grow around them.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;Remember, we're the professionals&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It may give the higher ups warm fuzzies to hear that it can all fit neatly into a little box, but no one will like the feeling later. &amp;nbsp;We do them no favors by making commitments we know we can never keep within any reasonable standard of long term success. &amp;nbsp;Clients can and should set constraints on delivery and tell us what they want delivered, but it's our job to define how best to get there. &amp;nbsp;I don't tell other professionals how to do their jobs when I pay for their services, and I would hope they would advise me on the consequences of taking shortcuts, while avoiding them completely. &amp;nbsp;That is after all, why I'm paying them. &amp;nbsp;They know better than I do.&lt;br /&gt;&lt;br /&gt;If there are doubts about making commitments, or about quality, don't be afraid to tell your clients (or your teammates) the truth, or at least what you observe. &amp;nbsp;That's what you're paid for, speak up. &amp;nbsp;Ultimately, even if the clients don't say so, I'm sure if you asked whether or not you should test this feature you just gave them they'd be scared you even asked the question. Quality is always a requirement even if our clients don't list it as a deliverable.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18079639-5001122572884110689?l=mlb5000behrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mlb5000behrend.blogspot.com/feeds/5001122572884110689/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18079639&amp;postID=5001122572884110689' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/5001122572884110689'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/5001122572884110689'/><link rel='alternate' type='text/html' href='http://mlb5000behrend.blogspot.com/2011/08/quality-is-not-option.html' title='Quality is Not an Option'/><author><name>Matthew Baker</name><uri>http://www.blogger.com/profile/09130722872162097459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_uqEMM3AOKNY/TO141z47zYI/AAAAAAAAACU/03UsFYn4Rxo/S220/41768_9328753_3338_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18079639.post-5037186102710076898</id><published>2011-06-29T20:24:00.000-04:00</published><updated>2011-06-29T20:24:21.549-04:00</updated><title type='text'>C++ C Function Wrappers - Introducing CFunctionWrapperGenerator</title><content type='html'>Dependency-injection in C++ is not convenient, especially when you bring "Free" C functions into the mix. There are several approaches you can use to isolate these functions, but the one I've had the most success with is to create C++ classes whose sole purpose is to wrap calls to C functions. This approach works quite well, both in minimizing the impact to the production code, and simplifying unit testing, particularly when paired with the &lt;a href="http://code.google.com/p/googlemock/"&gt;googlemock C++ Mocking framework&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I've been doing this for some time and have started to feel some pain in the maintenance area. Wrapper functions are starting to be duplicated between wrapper modules, and classes depending on wrappers are importing functions that they'll never call. But most of all, building out and maintaining these wrapper classes takes time and is extremely tedious. So being the lazy developer that I am, I wrote &lt;a href="https://github.com/mlb5000/CFunctionWrapperGenerator"&gt;C Function Wrapper Generator (CFWG)&lt;/a&gt; to do the heavy lifting for me.&lt;br /&gt;&lt;br /&gt;Basically it's a collection of Python scripts that generate C++ classes whose sole responsibility are to provide interfaces to C Functions. &amp;nbsp;They provide a transparent API to the C functions so you don't have to change how you're calling them (much), but the main advantage they provide is during unit testing: you now have a seam to control side-effects and return values of C functions that you would otherwise have had to deal with by hand.&lt;br /&gt;&lt;br /&gt;The main interface is a YAML configuration file that looks like this:&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, Arial, sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="yaml" style="background-color: #f0f0f0; border-bottom-color: rgb(160, 160, 160); border-bottom-style: dotted; border-bottom-width: 1px; border-left-color: rgb(160, 160, 160); border-left-style: dotted; border-left-width: 1px; border-right-color: rgb(160, 160, 160); border-right-style: dotted; border-right-width: 1px; border-top-color: rgb(160, 160, 160); border-top-style: dotted; border-top-width: 1px; color: #0000bb; font-family: 'Courier New', Courier, monospace; font-size: 13px; line-height: 14px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;"&gt;&lt;ol&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;span class="co4" style="color: #007f45;"&gt;Functions&lt;/span&gt;:&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;span class="co3" style="color: green;"&gt;&amp;nbsp; &amp;nbsp; - name&lt;/span&gt;&lt;span class="sy2" style="color: brown; font-weight: bold;"&gt;:&amp;nbsp;&lt;/span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;CreateFileA&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;span class="co3" style="color: green;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; real_header&lt;/span&gt;&lt;span class="sy2" style="color: brown; font-weight: bold;"&gt;:&amp;nbsp;&lt;/span&gt;&amp;nbsp; winbase.h&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;span class="co3" style="color: green;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; include_header&lt;/span&gt;&lt;span class="sy2" style="color: brown; font-weight: bold;"&gt;:&amp;nbsp;&lt;/span&gt;windows.h&lt;/div&gt;&lt;/li&gt;&lt;li class="li2" style="background-color: #e0e0e0; color: #000090; font-family: 'Courier New', Courier, monospace; font-weight: bold; line-height: 11px; padding-bottom: 2px;"&gt;&lt;div class="de2" style="color: #000060; font-weight: normal;"&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;span class="co3" style="color: green;"&gt;&amp;nbsp; &amp;nbsp; - name&lt;/span&gt;&lt;span class="sy2" style="color: brown; font-weight: bold;"&gt;:&amp;nbsp;&lt;/span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;CloseHandle&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;span class="co3" style="color: green;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; real_header&lt;/span&gt;&lt;span class="sy2" style="color: brown; font-weight: bold;"&gt;:&amp;nbsp;&lt;/span&gt;&amp;nbsp; winbase.h&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;span class="co3" style="color: green;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; include_header&lt;/span&gt;&lt;span class="sy2" style="color: brown; font-weight: bold;"&gt;:&amp;nbsp;&lt;/span&gt;windows.h&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li2" style="background-color: #e0e0e0; color: #000090; font-family: 'Courier New', Courier, monospace; font-weight: bold; line-height: 11px; padding-bottom: 2px;"&gt;&lt;div class="de2" style="color: #000060; font-weight: normal;"&gt;&lt;span class="co3" style="color: green;"&gt;&amp;nbsp; &amp;nbsp; - name&lt;/span&gt;&lt;span class="sy2" style="color: brown; font-weight: bold;"&gt;:&amp;nbsp;&lt;/span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;WriteFile&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;span class="co3" style="color: green;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; real_header&lt;/span&gt;&lt;span class="sy2" style="color: brown; font-weight: bold;"&gt;:&amp;nbsp;&lt;/span&gt;&amp;nbsp; winbase.h&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;span class="co3" style="color: green;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; include_header&lt;/span&gt;&lt;span class="sy2" style="color: brown; font-weight: bold;"&gt;:&amp;nbsp;&lt;/span&gt;windows.h&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;span class="co3" style="color: green;"&gt;&amp;nbsp; &amp;nbsp; - name&lt;/span&gt;&lt;span class="sy2" style="color: brown; font-weight: bold;"&gt;:&amp;nbsp;&lt;/span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;CreateEnvironmentBlock&lt;/div&gt;&lt;/li&gt;&lt;li class="li2" style="background-color: #e0e0e0; color: #000090; font-family: 'Courier New', Courier, monospace; font-weight: bold; line-height: 11px; padding-bottom: 2px;"&gt;&lt;div class="de2" style="color: #000060; font-weight: normal;"&gt;&lt;span class="co3" style="color: green;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; real_header&lt;/span&gt;&lt;span class="sy2" style="color: brown; font-weight: bold;"&gt;:&amp;nbsp;&lt;/span&gt;&amp;nbsp; userenv.h&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;span class="co3" style="color: green;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; include_header&lt;/span&gt;&lt;span class="sy2" style="color: brown; font-weight: bold;"&gt;:&amp;nbsp;&lt;/span&gt;userenv.h&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;span class="co4" style="color: #007f45;"&gt;Aggregators&lt;/span&gt;:&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;span class="co3" style="color: green;"&gt;&amp;nbsp; &amp;nbsp; - name&lt;/span&gt;&lt;span class="sy2" style="color: brown; font-weight: bold;"&gt;:&amp;nbsp;&lt;/span&gt;FileExists&lt;/div&gt;&lt;/li&gt;&lt;li class="li2" style="background-color: #e0e0e0; color: #000090; font-family: 'Courier New', Courier, monospace; font-weight: bold; line-height: 11px; padding-bottom: 2px;"&gt;&lt;div class="de2" style="color: #000060; font-weight: normal;"&gt;&lt;span class="co4" style="color: #007f45;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; functions&lt;/span&gt;&lt;span class="sy2" style="color: brown; font-weight: bold;"&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- CreateFileA&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;- CloseHandle&lt;/div&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;br /&gt;This basically tells CFWG what functions you want to wrap, where it can find them, and what header should be included in real code that calls it. &amp;nbsp;You can also specify custom aggregators if you want. &amp;nbsp;This allows you to pull in just the functions you need. &amp;nbsp;In the case of shared libraries this will prevent callers from getting linkage they don't actually use.&lt;br /&gt;&lt;br /&gt;CFWG generates three files:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;ICWrappers.h - Contains an interface for each C function in the form ICFunction (e.g. ICreateFileA). &amp;nbsp;This also contains an IMasterCWrapper (which multiply inherits from the individual ICFunctions) which comes in handy for unit testing (and my examples) and an interface for each aggregator specified in the configuration. &amp;nbsp;You want your production code to depend on these interfaces.&lt;/li&gt;&lt;li&gt;Component/CWrappers.h - Contains the implementation for each interface listed in ICWrappers.h. &amp;nbsp;These actually call the real C function, simply passing the arguments down. &amp;nbsp;You pass an instance of one of these to any production code that needs the function (or functions in the case of an aggregator).&lt;/li&gt;&lt;li&gt;Mock/CWrappers.h - Contains GMock implementations for IMasterCWrapper in ICWrappers.h and one for each Aggregate interface specified in the configuration file.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, Arial, sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="cpp" style="background-color: #f0f0f0; border-bottom-color: rgb(160, 160, 160); border-bottom-style: dotted; border-bottom-width: 1px; border-left-color: rgb(160, 160, 160); border-left-style: dotted; border-left-width: 1px; border-right-color: rgb(160, 160, 160); border-right-style: dotted; border-right-width: 1px; border-top-color: rgb(160, 160, 160); border-top-style: dotted; border-top-width: 1px; color: #0000bb; font-family: 'Courier New', Courier, monospace; font-size: 13px; line-height: 14px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; white-space: nowrap;"&gt;&lt;ol&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, Arial, sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;span class="coMULTI" style="color: red; font-style: normal;"&gt;/* Unit class (has dependencies) */&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;span class="Apple-style-span" style="font-family: Verdana, Arial, sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;span class="kw2" style="color: blue;"&gt;class&lt;/span&gt;&amp;nbsp;Unit&lt;span class="sy4" style="color: teal;"&gt;::&lt;/span&gt;&lt;span class="me2" style="color: #007788;"&gt;Foo&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;span class="br0" style="color: green;"&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;span class="kw2" style="color: blue;"&gt;public&lt;/span&gt;&lt;span class="sy4" style="color: teal;"&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li2" style="background-color: #e0e0e0; color: #000090; font-family: 'Courier New', Courier, monospace; font-weight: bold; line-height: 11px; padding-bottom: 2px;"&gt;&lt;div class="de2" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; Foo&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;ICreateFileA&amp;nbsp;&lt;span class="sy3" style="color: #000040;"&gt;&amp;amp;&lt;/span&gt;createFileA, IWriteFile&amp;nbsp;&lt;span class="sy3" style="color: #000040;"&gt;&amp;amp;&lt;/span&gt;writeFile, ICloseHandle&amp;nbsp;&lt;span class="sy3" style="color: #000040;"&gt;&amp;amp;&lt;/span&gt;closeHandle&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="sy4" style="color: teal;"&gt;:&lt;/span&gt;&amp;nbsp;m_createFileA&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;createFileA&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;, m_writeFile&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;writeFile&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;, m_closeHandle&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;closeHandle&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="br0" style="color: green;"&gt;{&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="kw4" style="color: blue;"&gt;void&lt;/span&gt;&amp;nbsp;bar&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;span class="sy4" style="color: teal;"&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li2" style="background-color: #e0e0e0; color: #000090; font-family: 'Courier New', Courier, monospace; font-weight: bold; line-height: 11px; padding-bottom: 2px;"&gt;&lt;div class="de2" style="color: #000060; font-weight: normal;"&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;span class="kw2" style="color: blue;"&gt;private&lt;/span&gt;&lt;span class="sy4" style="color: teal;"&gt;:&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; ICreateFileA&amp;nbsp;&lt;span class="sy3" style="color: #000040;"&gt;&amp;amp;&lt;/span&gt;m_createFileA&lt;span class="sy4" style="color: teal;"&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; IWriteFile&amp;nbsp;&lt;span class="sy3" style="color: #000040;"&gt;&amp;amp;&lt;/span&gt;m_writeFile&lt;span class="sy4" style="color: teal;"&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; ICloseHandle&amp;nbsp;&lt;span class="sy3" style="color: #000040;"&gt;&amp;amp;&lt;/span&gt;m_closeHandle&lt;span class="sy4" style="color: teal;"&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li2" style="background-color: #e0e0e0; color: #000090; font-family: 'Courier New', Courier, monospace; font-weight: bold; line-height: 11px; padding-bottom: 2px;"&gt;&lt;div class="de2" style="color: #000060; font-weight: normal;"&gt;&lt;span class="br0" style="color: green;"&gt;}&lt;/span&gt;&lt;span class="sy4" style="color: teal;"&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;span class="kw4" style="color: blue;"&gt;void&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;Unit&lt;span class="sy4" style="color: teal;"&gt;::&lt;/span&gt;&lt;span class="me2" style="color: #007788;"&gt;Foo&lt;/span&gt;&lt;span class="sy4" style="color: teal;"&gt;::&lt;/span&gt;&lt;span class="me2" style="color: #007788;"&gt;Bar&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;span class="br0" style="color: green;"&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li2" style="background-color: #e0e0e0; color: #000090; font-family: 'Courier New', Courier, monospace; font-weight: bold; line-height: 11px; padding-bottom: 2px;"&gt;&lt;div class="de2" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; HANDLE handle&amp;nbsp;&lt;span class="sy1" style="color: navy;"&gt;=&lt;/span&gt;&amp;nbsp;m_createFileA.&lt;span class="me1" style="color: #007788;"&gt;myCreateFileA&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="st0" style="color: red;"&gt;"testFile.txt"&lt;/span&gt;,&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; GENERIC_WRITE,&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="nu0" style="color: #0000dd;"&gt;0&lt;/span&gt;,&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="nu0" style="color: #0000dd;"&gt;0&lt;/span&gt;,&lt;/div&gt;&lt;/li&gt;&lt;li class="li2" style="background-color: #e0e0e0; color: #000090; font-family: 'Courier New', Courier, monospace; font-weight: bold; line-height: 11px; padding-bottom: 2px;"&gt;&lt;div class="de2" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; CREATE_NEW,&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; FILE_ATTRIBUTE_NORMAL,&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="nu0" style="color: #0000dd;"&gt;0&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;span class="sy4" style="color: teal;"&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="kw1" style="color: blue;"&gt;if&lt;/span&gt;&amp;nbsp;&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;INVALID_HANDLE_VALUE&amp;nbsp;&lt;span class="sy1" style="color: navy;"&gt;==&lt;/span&gt;&amp;nbsp;handle&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="br0" style="color: green;"&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li2" style="background-color: #e0e0e0; color: #000090; font-family: 'Courier New', Courier, monospace; font-weight: bold; line-height: 11px; padding-bottom: 2px;"&gt;&lt;div class="de2" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="kw1" style="color: blue;"&gt;throw&lt;/span&gt;&amp;nbsp;std&lt;span class="sy4" style="color: teal;"&gt;::&lt;/span&gt;&lt;span class="me2" style="color: #007788;"&gt;exception&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;&lt;span class="st0" style="color: red;"&gt;"CreateFileA failed!"&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;span class="sy4" style="color: teal;"&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="br0" style="color: green;"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="kw4" style="color: blue;"&gt;const&lt;/span&gt;&amp;nbsp;&lt;span class="kw4" style="color: blue;"&gt;char&lt;/span&gt;&amp;nbsp;&lt;span class="sy2" style="color: #000040;"&gt;*&lt;/span&gt;toWrite&amp;nbsp;&lt;span class="sy1" style="color: navy;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span class="st0" style="color: red;"&gt;"yay!!"&lt;/span&gt;&lt;span class="sy4" style="color: teal;"&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; DWORD numBytesWritten&amp;nbsp;&lt;span class="sy1" style="color: navy;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span class="nu0" style="color: #0000dd;"&gt;0&lt;/span&gt;&lt;span class="sy4" style="color: teal;"&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li2" style="background-color: #e0e0e0; color: #000090; font-family: 'Courier New', Courier, monospace; font-weight: bold; line-height: 11px; padding-bottom: 2px;"&gt;&lt;div class="de2" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="kw1" style="color: blue;"&gt;if&lt;/span&gt;&amp;nbsp;&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;&lt;span class="sy3" style="color: #000040;"&gt;!&lt;/span&gt;m_writeFile.&lt;span class="me1" style="color: #007788;"&gt;myWriteFile&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; handle,&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; toWrite,&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="kw3" style="color: #0000dd;"&gt;strlen&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;toWrite&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;,&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="sy3" style="color: #000040;"&gt;&amp;amp;&lt;/span&gt;numBytesWritten,&lt;/div&gt;&lt;/li&gt;&lt;li class="li2" style="background-color: #e0e0e0; color: #000090; font-family: 'Courier New', Courier, monospace; font-weight: bold; line-height: 11px; padding-bottom: 2px;"&gt;&lt;div class="de2" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="nu0" style="color: #0000dd;"&gt;0&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&amp;nbsp;&lt;span class="sy3" style="color: #000040;"&gt;||&lt;/span&gt;&amp;nbsp;numBytesWritten&amp;nbsp;&lt;span class="sy3" style="color: #000040;"&gt;!&lt;/span&gt;&lt;span class="sy1" style="color: navy;"&gt;=&lt;/span&gt;&amp;nbsp;&lt;span class="kw3" style="color: #0000dd;"&gt;strlen&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;toWrite&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="br0" style="color: green;"&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; m_closeHandle.&lt;span class="me1" style="color: #007788;"&gt;myCloseHandle&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;handle&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;span class="sy4" style="color: teal;"&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="kw1" style="color: blue;"&gt;throw&lt;/span&gt;&amp;nbsp;std&lt;span class="sy4" style="color: teal;"&gt;::&lt;/span&gt;&lt;span class="me2" style="color: #007788;"&gt;exception&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;&lt;span class="st0" style="color: red;"&gt;"WriteFile failed!"&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;span class="sy4" style="color: teal;"&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;span class="br0" style="color: green;"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li2" style="background-color: #e0e0e0; color: #000090; font-family: 'Courier New', Courier, monospace; font-weight: bold; line-height: 11px; padding-bottom: 2px;"&gt;&lt;div class="de2" style="color: #000060; font-weight: normal;"&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; m_closeHandle.&lt;span class="me1" style="color: #007788;"&gt;myCloseHandle&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;handle&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;span class="sy4" style="color: teal;"&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;span class="br0" style="color: green;"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;span class="kw4" style="color: blue;"&gt;int&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li2" style="background-color: #e0e0e0; color: #000090; font-family: 'Courier New', Courier, monospace; font-weight: bold; line-height: 11px; padding-bottom: 2px;"&gt;&lt;div class="de2" style="color: #000060; font-weight: normal;"&gt;main&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;span class="br0" style="color: green;"&gt;{&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; Component&lt;span class="sy4" style="color: teal;"&gt;::&lt;/span&gt;&lt;span class="me2" style="color: #007788;"&gt;MasterCWrapper&lt;/span&gt;&amp;nbsp;wrapper&lt;span class="sy4" style="color: teal;"&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; Unit&lt;span class="sy4" style="color: teal;"&gt;::&lt;/span&gt;&lt;span class="me2" style="color: #007788;"&gt;Foo&lt;/span&gt;&amp;nbsp;foo&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;wrapper, wrapper, wrapper&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;span class="sy4" style="color: teal;"&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li2" style="background-color: #e0e0e0; color: #000090; font-family: 'Courier New', Courier, monospace; font-weight: bold; line-height: 11px; padding-bottom: 2px;"&gt;&lt;div class="de2" style="color: #000060; font-weight: normal;"&gt;&amp;nbsp; &amp;nbsp; foo.&lt;span class="me1" style="color: #007788;"&gt;Bar&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;span class="sy4" style="color: teal;"&gt;;&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;div class="de1" style="color: #000060; font-weight: normal;"&gt;&lt;span class="br0" style="color: green;"&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/li&gt;&lt;/span&gt;&lt;/ol&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;Now you can write unit tests for Foo and easily test all these conditions. &amp;nbsp;Well, you could before too, now you just don't have to maintain all those boilerplate wrappers anymore.&lt;br /&gt;&lt;br /&gt;&lt;a href="https://github.com/mlb5000/CFunctionWrapperGenerator"&gt;Check it out on Github&lt;/a&gt; and let me know what you think!&lt;br /&gt;&lt;br /&gt;P.S. This depends heavily on the &lt;a href="http://code.google.com/p/cppclean/"&gt;cppclean&lt;/a&gt; C++ AST generator, so props to those guys for providing a great tool.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18079639-5037186102710076898?l=mlb5000behrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mlb5000behrend.blogspot.com/feeds/5037186102710076898/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18079639&amp;postID=5037186102710076898' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/5037186102710076898'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/5037186102710076898'/><link rel='alternate' type='text/html' href='http://mlb5000behrend.blogspot.com/2011/06/c-c-function-wrappers-introducing.html' title='C++ C Function Wrappers - Introducing CFunctionWrapperGenerator'/><author><name>Matthew Baker</name><uri>http://www.blogger.com/profile/09130722872162097459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_uqEMM3AOKNY/TO141z47zYI/AAAAAAAAACU/03UsFYn4Rxo/S220/41768_9328753_3338_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18079639.post-220687735617530117</id><published>2011-02-02T18:18:00.000-05:00</published><updated>2011-02-02T18:18:57.708-05:00</updated><title type='text'>Why "User Stories" Failed Us</title><content type='html'>NOTE: Please read this entire post, I don't aspire to become the &lt;a href="http://pascal.gugenberger.net/thoughts/waterfall-accident.html"&gt;Winston Royce&lt;/a&gt; of User Stories. :)&lt;br /&gt;&lt;br /&gt;About 7 or 8 months ago our teams decided to try using &lt;a href="http://www.google.com/url?sa=t&amp;amp;source=web&amp;amp;cd=1&amp;amp;ved=0CCUQFjAA&amp;amp;url=http%3A%2F%2Fen.wikipedia.org%2Fwiki%2FUser_story&amp;amp;ei=7eRJTYqYNoT48Aay8InJDg&amp;amp;usg=AFQjCNEur9zpYr3J-fWFpLlrUu4d7u4Tsw"&gt;User Stories&lt;/a&gt; as our primary mechanism for capturing requirements. &amp;nbsp;Since then, we have taken our lessons learned and have moved away from them. &amp;nbsp;The reason for their "failure" is laughable really: people couldn't get past the name. &amp;nbsp;There were team members and customers that just couldn't get beyond the fact that they're called "User Stories". &amp;nbsp;People would make cracks about Epics and ask whether it's more like&amp;nbsp;&lt;i&gt;Odyssey&lt;/i&gt;&amp;nbsp;or &lt;i&gt;Gilgamesh&lt;/i&gt;. &amp;nbsp;In the beginning this was funny, and we had a laugh, but some people just couldn't get past it, and we have since decided to phase out the use of that &lt;i&gt;term&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;The levels of success with User Stories in our group vary greatly, but as with any two projects you can't really compare them based on a single part of their process. &amp;nbsp;The team I am supporting has delivered value consistently since the project started and we have done so not because we used User Stories (we did, and to great effect I might add) but because we were (and are) disciplined. &amp;nbsp;Other teams call functionality "done" without having high level tests against it that can be easily repeated. &amp;nbsp;I blame myself for those failings if for no other reason than I should have noticed the signs. &amp;nbsp;Someone has to, right? &lt;br /&gt;&lt;br /&gt;On my current team when one of us starts to get lazy the other half of the pair straightens them out and makes sure that everything they thought to test has been tested, and that it's in the appropriate place for our automation infrastructure to get at it. &amp;nbsp;We commit a change and within an hour we've validated (yes, that's validated, not just verified) that latest version against all our user stories to date, against all supported configurations, including protecting ourselves from regression. &amp;nbsp;We are able to answer the question "when will version X be done?" using real-time data because we keep Jira up to date and because we understand what "done" means. &amp;nbsp;We don't fool ourselves into thinking we can do more work in 3 weeks than we've historically proven we can do, and we don't let management pressure us into committing as such. &amp;nbsp;We've learned to how to adjust our sprint caps for personnel fluctuation as team members are temporarily stripped away to work on other things, which happens quite often.&lt;br /&gt;&lt;br /&gt;Like I said, it's not the tool's fault. &amp;nbsp;It's unfortunate that something so trivial could kill its use in our process. &amp;nbsp;Now we work on "Features"...that contain shorts blurbs about something succinct that the system should do...and are estimated using points... &amp;nbsp;Sound familiar? &amp;nbsp;User Stories are no more or less valuable as an artifact than "shall" statements in more traditional requirements management methodologies, but they're tight, to the point, and no one fools themselves into thinking they can craft the perfect sequence of words to build the perfect statement. &amp;nbsp;No one even tries. &amp;nbsp;Instead, the focus becomes the user's intent, not the words in the requirements document. &amp;nbsp;And intent is best captured with higher bandwidth forms of communication, like getting everyone in the same room and talking it out. &amp;nbsp;That, I've learned, is the true power of User Stories; even if they're called Features.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18079639-220687735617530117?l=mlb5000behrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mlb5000behrend.blogspot.com/feeds/220687735617530117/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18079639&amp;postID=220687735617530117' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/220687735617530117'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/220687735617530117'/><link rel='alternate' type='text/html' href='http://mlb5000behrend.blogspot.com/2011/02/why-user-stories-failed-us.html' title='Why &quot;User Stories&quot; Failed Us'/><author><name>Matthew Baker</name><uri>http://www.blogger.com/profile/09130722872162097459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_uqEMM3AOKNY/TO141z47zYI/AAAAAAAAACU/03UsFYn4Rxo/S220/41768_9328753_3338_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18079639.post-5816988785560079267</id><published>2010-09-30T18:24:00.024-04:00</published><updated>2010-11-22T21:13:21.236-05:00</updated><title type='text'>AAA vs BDD Structuring in Unit Tests</title><content type='html'>UPDATE: I updated this to include updates to the BDD example's test function name. &amp;nbsp;I'm starting to dislike having the called interface in the test name. &amp;nbsp;It's inflexible and unnecessary and ultimately doesn't help the reader all that much.&lt;br /&gt;&lt;br /&gt;It's always good when there are people on your team whom you can both learn from and teach things to. Such is the case with my current team. A couple team members have never done unit testing as it's known in the industry today. Mostly just "pound at the interface until I'm comfortable and throw it over to testing to deal with" unit testing.&lt;br /&gt;&lt;br /&gt;During our first code review there were a lot of issues with unit tests. I actually prefer to let it pan out this way; this way people actually get in there and try it out, to later see what works, what didn't, and (hopefully) get some ideas from the rest of the team about how to improve it. One recurring theme was that there was a lot of redundant code throughout test suites. Setup and teardown were outright missing! That's good, because now they've seen the problem, and part of the solution is to use those. Another thing was how the test cases themselves were structured. I've come across two widely accepted ways of structuring unit tests:&lt;br /&gt;&lt;br /&gt;Arrange - Act - Assert&lt;br /&gt;Given - When - Then&lt;br /&gt;&lt;br /&gt;I've personally used both in the same codebase when it makes sense, but I'm wondering if there's more to it than just semantics and readability. With AAA you are more likely to interact with the class under test directly inside your test function:&lt;br /&gt;&lt;br /&gt;&lt;div class="cpp" style="background-color: #f0f0f0; border-bottom-color: rgb(160, 160, 160); border-bottom-style: dotted; border-bottom-width: 1px; border-left-color: rgb(160, 160, 160); border-left-style: dotted; border-left-width: 1px; border-right-color: rgb(160, 160, 160); border-right-style: dotted; border-right-width: 1px; border-top-color: rgb(160, 160, 160); border-top-style: dotted; border-top-width: 1px; font-family: 'Courier New', Courier, monospace; font-size: 13px; line-height: 14px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 15px; padding-right: 0px; padding-top: 0px; white-space: nowrap;"&gt;&lt;ol style="list-style-image: initial; list-style-position: outside; list-style-type: decimal;"&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;span class="kw4" style="color: blue;"&gt;void&lt;/span&gt;&amp;nbsp;interface_context_somethingHappens&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;span class="Apple-style-span" style="color: green;"&gt;{&lt;/span&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class="co1" style="color: #666666; font-style: normal;"&gt;//arrange&lt;/span&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;span class="Apple-style-span" style="color: #000060;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;mock1&lt;/span&gt;&lt;span class="sy2" style="color: #000040;"&gt;-&lt;/span&gt;&lt;span class="sy2"&gt;&lt;span class="Apple-style-span" style="color: navy;"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #000060;"&gt;setCallShouldSucceed&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;&lt;span class="kw2" style="color: blue;"&gt;false&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;span class="sy4" style="color: teal;"&gt;;&lt;/span&gt;&lt;/li&gt;&lt;li class="li2" style="background-color: #e0e0e0; font-family: 'Courier New', Courier, monospace; font-weight: bold; line-height: 11px; padding-bottom: 2px;"&gt;&lt;span class="Apple-style-span" style="font-weight: normal;"&gt;&lt;span class="Apple-style-span" style="color: #000060;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;mock2&lt;/span&gt;&lt;span class="sy2" style="color: #000040;"&gt;-&lt;/span&gt;&lt;span class="sy2"&gt;&lt;span class="Apple-style-span" style="color: navy;"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #000060;"&gt;addFakeValue&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;&lt;span class="st0" style="color: red;"&gt;"Value"&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;span class="sy4" style="color: teal;"&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li class="li2" style="background-color: #e0e0e0; color: #000090; font-family: 'Courier New', Courier, monospace; font-weight: bold; line-height: 11px; padding-bottom: 2px;"&gt;&lt;span class="Apple-style-span" style="color: #000060; font-weight: normal; line-height: 14px;"&gt;&lt;span class="co1" style="font-style: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li class="li2" style="background-color: #e0e0e0; color: #000090; font-family: 'Courier New', Courier, monospace; font-weight: bold; line-height: 11px; padding-bottom: 2px;"&gt;&lt;span class="Apple-style-span" style="color: #000060; font-weight: normal;"&gt;&lt;span class="sy4" style="color: teal;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #000060; font-weight: normal; line-height: 14px;"&gt;&lt;span class="co1" style="font-style: normal;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;span class="co1" style="color: #666666; font-style: normal;"&gt;//act&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;span class="Apple-style-span" style="color: #000060;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;out&lt;/span&gt;&lt;span class="sy2" style="color: #000040;"&gt;-&lt;/span&gt;&lt;span class="sy2"&gt;&lt;span class="Apple-style-span" style="color: navy;"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #000060;"&gt;interface&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;span class="sy4" style="color: teal;"&gt;;&lt;/span&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;span class="Apple-style-span" style="line-height: 11px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;span class="sy4" style="color: teal;"&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="line-height: 11px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;span class="co1" style="color: #666666; font-style: normal;"&gt;//assert&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;span class="Apple-style-span" style="line-height: 11px;"&gt;&lt;span class="co1" style="color: #666666; font-style: normal;"&gt;&lt;/span&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;CPPUNIT_ASSERT&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;somethingHappened&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;span class="sy4" style="color: teal;"&gt;;&lt;/span&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;span class="Apple-style-span" style="color: green;"&gt;}&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;br /&gt;However, I've started to notice that if you read your tests, I mean really read them, then using the Behavior-Driven-Development (BDD) Given-When-Then structuring will actually nudge you towards factoring the real test preparation and calls to the class under test out of your test case:&lt;br /&gt;&lt;br /&gt;&lt;div class="cpp" style="background-color: #f0f0f0; border-bottom-color: rgb(160, 160, 160); border-bottom-style: dotted; border-bottom-width: 1px; border-left-color: rgb(160, 160, 160); border-left-style: dotted; border-left-width: 1px; border-right-color: rgb(160, 160, 160); border-right-style: dotted; border-right-width: 1px; border-top-color: rgb(160, 160, 160); border-top-style: dotted; border-top-width: 1px; font-family: 'Courier New', Courier, monospace; font-size: 13px; line-height: 14px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 15px; padding-right: 0px; padding-top: 0px; white-space: nowrap;"&gt;&lt;ol style="list-style-image: initial; list-style-position: outside; list-style-type: decimal;"&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;span class="kw4" style="color: blue;"&gt;void&lt;/span&gt;&amp;nbsp;SomethingShouldHappenInSomeContext&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;span class="br0" style="color: green;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;givenSomeContext&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;span class="sy4" style="color: teal;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;span class="Apple-style-span" style="color: #000090;"&gt;&lt;span class="Apple-style-span" style="line-height: 11px;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="color: #000060;"&gt;&lt;span class="Apple-style-span" style="font-weight: normal; line-height: 14px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li class="li2" style="background-color: #e0e0e0; color: #000090; font-family: 'Courier New', Courier, monospace; line-height: 11px; padding-bottom: 2px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;whenActionPerformed&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;span class="sy4" style="color: teal;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;thenSomethingShouldHappen&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;span class="sy4" style="color: teal;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;span class="br0" style="color: green;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;span class="Apple-style-span" style="color: #000090;"&gt;&lt;span class="Apple-style-span" style="line-height: 11px;"&gt;&lt;b&gt;&lt;span class="Apple-style-span" style="color: #000060;"&gt;&lt;span class="Apple-style-span" style="font-weight: normal; line-height: 14px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li class="li2" style="background-color: #e0e0e0; color: #000090; font-family: 'Courier New', Courier, monospace; line-height: 11px; padding-bottom: 2px;"&gt;&lt;span class="kw4" style="color: blue;"&gt;void&lt;/span&gt;&amp;nbsp;givenSomeContext&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;span class="br0" style="color: green;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;span class="co1" style="color: #666666; font-style: normal;"&gt;//configure context&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;span class="Apple-style-span" style="color: #000060;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;mock1&lt;/span&gt;&lt;span class="sy2" style="color: #000040;"&gt;-&lt;/span&gt;&lt;span class="sy2"&gt;&lt;span class="Apple-style-span" style="color: navy;"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #000060;"&gt;setCallShouldSucceed&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;&lt;span class="kw2" style="color: blue;"&gt;false&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;span class="sy4" style="color: teal;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;span class="Apple-style-span" style="color: #000060;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;mock2&lt;/span&gt;&lt;span class="sy2" style="color: #000040;"&gt;-&lt;/span&gt;&lt;span class="sy2"&gt;&lt;span class="Apple-style-span" style="color: navy;"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #000060;"&gt;addFakeValue&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;&lt;span class="st0" style="color: red;"&gt;"Value"&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;span class="sy4" style="color: teal;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class="li2" style="background-color: #e0e0e0; color: #000090; font-family: 'Courier New', Courier, monospace; line-height: 11px; padding-bottom: 2px;"&gt;&lt;span class="br0" style="color: green;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;span class="kw4" style="color: blue;"&gt;void&lt;/span&gt;&amp;nbsp;whenActionPerformed&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;span class="br0" style="color: green;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;span class="co1" style="color: #666666; font-style: normal;"&gt;//execute action&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class="li2" style="background-color: #e0e0e0; font-family: 'Courier New', Courier, monospace; line-height: 11px; padding-bottom: 2px;"&gt;&lt;span class="Apple-style-span" style="color: #000090;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;out&lt;/span&gt;&lt;span class="sy2" style="color: #000040;"&gt;-&lt;/span&gt;&lt;span class="sy2"&gt;&lt;span class="Apple-style-span" style="color: navy;"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #000090;"&gt;interface&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;span class="sy4" style="color: teal;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;span class="br0" style="color: green;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;span class="kw4" style="color: blue;"&gt;void&lt;/span&gt;&amp;nbsp;thenSomethingShouldHappen&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;span class="br0" style="color: green;"&gt;{&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class="li2" style="background-color: #e0e0e0; color: #000090; font-family: 'Courier New', Courier, monospace; line-height: 11px; padding-bottom: 2px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;&lt;span class="co1" style="color: #666666; font-style: normal;"&gt;//check that what should happen happened&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&amp;nbsp;&amp;nbsp; &amp;nbsp;CPPUNIT_ASSERT&lt;span class="br0" style="color: green;"&gt;(&lt;/span&gt;didSomething&lt;span class="br0" style="color: green;"&gt;)&lt;/span&gt;&lt;span class="sy4" style="color: teal;"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New', Courier, monospace; padding-bottom: 2px;"&gt;&lt;span class="br0" style="color: green;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;br /&gt;Yes, it's more code, and yes, it may just be semantics, but I see something more. The naming alone has suggested that maybe I should remove the details from the test. Not only does this produce well-factored code but, but it pulls communication with the class under test to the boundary of my test suite and away from my test cases. Now, if the usage of this class changes for some reason, I only have to update it in one or two places in my test suite, rather than in every single test case. Obviously this approach may not be suited for every single situation, but like I said, I use both where it feels right. Granted, this is considered a good practice when using AAA as well, but you've got to name those newly extracted functions something don't you?&lt;br /&gt;&lt;br /&gt;I'd love to get some feedback on this. What convention does your team follow? Are my observations valid or can it be chalked up to something else?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18079639-5816988785560079267?l=mlb5000behrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mlb5000behrend.blogspot.com/feeds/5816988785560079267/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18079639&amp;postID=5816988785560079267' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/5816988785560079267'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/5816988785560079267'/><link rel='alternate' type='text/html' href='http://mlb5000behrend.blogspot.com/2010/09/aaa-vs-bdd-structuring-in-unit-tests.html' title='AAA vs BDD Structuring in Unit Tests'/><author><name>Matthew Baker</name><uri>http://www.blogger.com/profile/09130722872162097459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_uqEMM3AOKNY/TO141z47zYI/AAAAAAAAACU/03UsFYn4Rxo/S220/41768_9328753_3338_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18079639.post-429649427553458450</id><published>2010-09-25T18:47:00.004-04:00</published><updated>2010-09-26T11:35:34.666-04:00</updated><title type='text'>Autotest for Compiled Languages (C#, C++) using Watchr</title><content type='html'>When I was learning Rails I set up &lt;a href="http://blog.codefront.net/2007/04/01/get-your-testing-results-via-growl-notifications/"&gt;Autotest on Ubuntu with Growl notifications&lt;/a&gt;, which I thought was a pretty slick idea. On Ruby this whole technique is super easy and efficient because Ruby is an interpreted language; there's no compile time to slow you down, and no other files to pollute your directory tree.  Compiled languages don't have that advantage, but I think we deserve some continuous feedback too.  Here I'll describe how to configure &lt;a href="http://github.com/mynyml/watchr"&gt;Watchr&lt;/a&gt;, a generic Autotest utility, to run compiled tests whenever a source file in the path is updated.  This tutorial will use a C# example, but it's trivial to have it trigger on different file types.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Getting Started&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;First, we'll need to install Ruby and Watchr.&amp;nbsp; Because I'm using Windows I just downloaded &lt;a href="http://rubyinstaller.org/downloads/"&gt;RubyInstaller&lt;/a&gt;.&amp;nbsp; Make sure you put the Ruby/bin directory in your PATH.&lt;br /&gt;&lt;br /&gt;Next, download &lt;a href="http://github.com/mynyml/watchr/downloads"&gt;Watchr from Github&lt;/a&gt;, extract the archive and navigate to that directory.&amp;nbsp; Or you can just download the gem directly, but some people might want to run the tests locally first.  The following command will install the gem from the local directory:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;C:\mynyml-watchr-17fa9bf\&amp;gt;gem install Watchr&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: large;"&gt;Configuring Watchr&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Now that we have all the dependencies installed, we need to configure Watchr.  This process is easiest if you already have a single point of entry for your continuous build process, but if you don't it's not that bad and you'll probably want one anyway. Now, at the same level as the directory(ies) containing your source code, create a text file. I usually call this &lt;i&gt;autotest.watchr&lt;/i&gt;, but you could call it &lt;i&gt;autotest.unit&lt;/i&gt; or &lt;i&gt;autotest.integration&lt;/i&gt; if you're into that sort of thing. For now, just put in the following line in:&lt;br /&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="ruby" style="background-color: #f0f0f0; border: 1px dotted rgb(160, 160, 160); color: #0000bb; font-family: 'Courier New',Courier,monospace; font-size: 13px; line-height: 14px; margin: 0px; padding: 0px; white-space: nowrap;"&gt;&lt;ol&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New',Courier,monospace; padding-bottom: 2px;"&gt;watch&lt;span class="br0" style="color: #006600; font-weight: bold;"&gt;(&lt;/span&gt;&lt;span class="st0" style="color: #996600;"&gt;'./.*/(.*)&lt;span class="es0" style="color: #000099; font-weight: normal;"&gt;\.&lt;/span&gt;cs$'&lt;/span&gt;&lt;span class="br0" style="color: #006600; font-weight: bold;"&gt;)&lt;/span&gt;&lt;span class="Apple-converted-space"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="br0" style="color: #006600; font-weight: bold;"&gt;{&lt;/span&gt;&lt;span class="kw3" style="color: #cc0066; font-weight: bold;"&gt;system&lt;/span&gt;&lt;span class="Apple-converted-space"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="st0" style="color: #996600;"&gt;"cd build &amp;amp;&amp;amp; buildAndRunTests.bat &amp;amp;&amp;amp; cd ..&lt;span class="es0" style="color: #000099; font-weight: normal;"&gt;\\&lt;/span&gt;"&lt;/span&gt;&lt;span class="br0" style="color: #006600; font-weight: bold;"&gt;}&lt;/span&gt; &lt;/li&gt;&lt;/span&gt;&lt;/span&gt;&lt;/ol&gt;&lt;/div&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;Yes, it's that easy. What this is doing is telling Watchr to monitor any files that match the regular expression (in this case a recursive directory search for .cs files) inside the watch() call, and then execute the command on the right. I also have it configured to return to the same directory when it's finished, but I don't know if that's actually necessary. The watch() pattern is what you would modify for different environments. For example, you could use &lt;code&gt;watch('./.*/(.*)\.[h|cpp|hpp|c]$')&lt;/code&gt; for a Mixed C/C++ system, or &lt;code&gt;watch('./.*/(.*)\.[cs|vb|cpp|h]$')&lt;/code&gt; for a .NET project with components built in different languages.  An important thing to note is the &lt;b&gt;$&lt;/b&gt; at the end of the regex.  Because it's likely that there will be a lot of intermediary files generated during the build process, we don't want a file which happens to match this pattern that's generated at build time to trigger an infinite loop of build &amp;amp; test (like happened to me). The heavy lifting is done here, but the stuff specific to your project happens in &lt;i&gt;build/buildAndRunTests.bat&lt;/i&gt;. Let's take a look at that:&lt;br /&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="php" style="background-color: #f0f0f0; border: 1px dotted rgb(160, 160, 160); color: #0000bb; font-family: 'Courier New',Courier,monospace; font-size: 13px; line-height: 14px; margin: 0px; padding: 0px; white-space: nowrap;"&gt;&lt;ol&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New',Courier,monospace; padding-bottom: 2px;"&gt;pushd&lt;span class="Apple-converted-space"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="sy0" style="color: #339933;"&gt;..&lt;/span&gt;\ &lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New',Courier,monospace; padding-bottom: 2px;"&gt;&lt;span class="kw1" style="color: #b1b100;"&gt;echo&lt;/span&gt;&lt;span class="Apple-converted-space"&gt;&amp;nbsp;&lt;/span&gt;Building tests &lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New',Courier,monospace; padding-bottom: 2px;"&gt;&lt;span class="st0" style="color: blue;"&gt;"C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\devenv.com"&lt;/span&gt;&lt;span class="Apple-converted-space"&gt;&amp;nbsp;&lt;/span&gt;Tests&lt;span class="sy0" style="color: #339933;"&gt;.&lt;/span&gt;Unit\Tests&lt;span class="sy0" style="color: #339933;"&gt;.&lt;/span&gt;Unit&lt;span class="sy0" style="color: #339933;"&gt;.&lt;/span&gt;csproj&lt;span class="Apple-converted-space"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="sy0" style="color: #339933;"&gt;/&lt;/span&gt;rebuild Release &lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New',Courier,monospace; padding-bottom: 2px;"&gt;popd &lt;/li&gt;&lt;li class="li2" style="background-color: #e0e0e0; color: #000090; font-family: 'Courier New',Courier,monospace; font-weight: bold; line-height: 11px; padding-bottom: 2px;"&gt;&lt;br /&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New',Courier,monospace; padding-bottom: 2px;"&gt;pushd&lt;span class="Apple-converted-space"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="sy0" style="color: #339933;"&gt;..&lt;/span&gt;\Tests&lt;span class="sy0" style="color: #339933;"&gt;.&lt;/span&gt;Unit\bin\Release&lt;br /&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New',Courier,monospace; padding-bottom: 2px;"&gt;&lt;span class="kw1" style="color: #b1b100;"&gt;echo&lt;/span&gt;&lt;span class="Apple-converted-space"&gt;&amp;nbsp;&lt;/span&gt;Running tests through nunit&lt;span class="sy0" style="color: #339933;"&gt;-&lt;/span&gt;console &lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New',Courier,monospace; padding-bottom: 2px;"&gt;nunit&lt;span class="sy0" style="color: #339933;"&gt;-&lt;/span&gt;console&lt;span class="sy0" style="color: #339933;"&gt;.&lt;/span&gt;exe Tests&lt;span class="sy0" style="color: #339933;"&gt;.&lt;/span&gt;Unit&lt;span class="sy0" style="color: #339933;"&gt;.&lt;/span&gt;dll&lt;span class="Apple-converted-space"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="sy0" style="color: #339933;"&gt;/&lt;/span&gt;run&lt;span class="sy0" style="color: #339933;"&gt;=&lt;/span&gt;Tests&lt;span class="sy0" style="color: #339933;"&gt;.&lt;/span&gt;Unit &lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New',Courier,monospace; padding-bottom: 2px;"&gt;popd &lt;/li&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/ol&gt;&lt;/div&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;You'll obviously want to customize this to the specifics of your project, but right now it's hard-coded to call Visual Studio 2008's devenv.com (on a 64-bit OS) and build a project called Tests.Unit. For brevity it also assumes that nunit-console.exe is available on the PATH.  Not terribly interesting, but that's the rest of the work.&lt;br /&gt;&lt;br /&gt;Now to have all the magic happen. Run the following command in a new console window from your project directory:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;C:\Projects\MyProject&amp;gt;Watchr autotest.watchr&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;That's it! Watchr is now monitoring for changes to files that match your pattern. Simply modify any file matching the pattern and watch the whole process set off. Once it finishes, you can hopefully see the results and it will wait for the next change.&lt;br /&gt;&lt;br /&gt;Now there's one less thing you have to do during your heavy refactoring sessions, or just with day-to-day development.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18079639-429649427553458450?l=mlb5000behrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mlb5000behrend.blogspot.com/feeds/429649427553458450/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18079639&amp;postID=429649427553458450' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/429649427553458450'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/429649427553458450'/><link rel='alternate' type='text/html' href='http://mlb5000behrend.blogspot.com/2010/09/autotest-for-compiled-languages-c-c.html' title='Autotest for Compiled Languages (C#, C++) using Watchr'/><author><name>Matthew Baker</name><uri>http://www.blogger.com/profile/09130722872162097459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_uqEMM3AOKNY/TO141z47zYI/AAAAAAAAACU/03UsFYn4Rxo/S220/41768_9328753_3338_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18079639.post-6874947828966692643</id><published>2010-09-18T00:47:00.020-04:00</published><updated>2010-09-25T17:30:28.558-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ios'/><category scheme='http://www.blogger.com/atom/ns#' term='twitter'/><category scheme='http://www.blogger.com/atom/ns#' term='iphone'/><category scheme='http://www.blogger.com/atom/ns#' term='objective-c'/><title type='text'>SA_OAuthTwitterEngine Search Error 400</title><content type='html'>It may be deliberate that this function doesn't work but that doesn't make much sense. &amp;nbsp;I'm trying to use SA_OAuthTwitterEngine as the &lt;b&gt;sole&lt;/b&gt; Twitter engine in my app but I'm having problems with the &lt;code&gt;getSearchResultsForQuery:&lt;/code&gt; method (yes, I've hooked up the YAJL library). &amp;nbsp;Every single time I send a request using the &lt;code&gt;getSearchResultsForQuery:&lt;/code&gt; selector on my SA_OAuthTwitterEngine I'm get the following error:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;"The operation couldn’t be completed. (HTTP error 400.)"&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;MGTwitterEngine produces no such error. &amp;nbsp;You wouldn't think calling this selector would be a problem since it inherits directly from MGTwitterClient and therefore provides the interface, but actually it is. &amp;nbsp;The problem lies in&amp;nbsp;SA_OAuthTwitterEngine's implementation of&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="objc" style="background-color: #f0f0f0; border: 1px dotted rgb(160, 160, 160); color: #0000bb; font-family: 'Courier New',Courier,monospace; font-size: 13px; line-height: 14px; margin: 0px; padding: 0px; white-space: nowrap;"&gt;&lt;ol&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 12px;"&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New',Courier,monospace;"&gt;&lt;span class="sy0" style="color: #002200;"&gt;-&lt;/span&gt;&lt;span class="Apple-converted-space"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="br0" style="color: #002200;"&gt;(&lt;/span&gt;&lt;a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/" style="color: #000066;"&gt;&lt;span class="kw5" style="color: #400080;"&gt;NSString&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-converted-space"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="sy0" style="color: #002200;"&gt;*&lt;/span&gt;&lt;span class="br0" style="color: #002200;"&gt;)&lt;/span&gt;_sendRequestWithMethod&lt;span class="sy0" style="color: #002200;"&gt;:&lt;/span&gt;&lt;span class="br0" style="color: #002200;"&gt;(&lt;/span&gt;&lt;a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/" style="color: #000066;"&gt;&lt;span class="kw5" style="color: #400080;"&gt;NSString&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-converted-space"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="sy0" style="color: #002200;"&gt;*&lt;/span&gt;&lt;span class="br0" style="color: #002200;"&gt;)&lt;/span&gt;method &lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; path&lt;span class="sy0" style="color: #002200;"&gt;:&lt;/span&gt;&lt;span class="br0" style="color: #002200;"&gt;(&lt;/span&gt;&lt;a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/" style="color: #000066;"&gt;&lt;span class="kw5" style="color: #400080;"&gt;NSString&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-converted-space"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="sy0" style="color: #002200;"&gt;*&lt;/span&gt;&lt;span class="br0" style="color: #002200;"&gt;)&lt;/span&gt;path &lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; queryParameters&lt;span class="sy0" style="color: #002200;"&gt;:&lt;/span&gt;&lt;span class="br0" style="color: #002200;"&gt;(&lt;/span&gt;&lt;a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSDictionary_Class/" style="color: #000066;"&gt;&lt;span class="kw5" style="color: #400080;"&gt;NSDictionary&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-converted-space"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="sy0" style="color: #002200;"&gt;*&lt;/span&gt;&lt;span class="br0" style="color: #002200;"&gt;)&lt;/span&gt;params &lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; body&lt;span class="sy0" style="color: #002200;"&gt;:&lt;/span&gt;&lt;span class="br0" style="color: #002200;"&gt;(&lt;/span&gt;&lt;a href="http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/" style="color: #000066;"&gt;&lt;span class="kw5" style="color: #400080;"&gt;NSString&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-converted-space"&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="sy0" style="color: #002200;"&gt;*&lt;/span&gt;&lt;span class="br0" style="color: #002200;"&gt;)&lt;/span&gt;body &lt;/li&gt;&lt;li class="li2" style="background-color: #e0e0e0; color: #000090; font-family: 'Courier New',Courier,monospace; font-weight: bold; line-height: 11px;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;nbsp; &lt;span style="font-weight: normal;"&gt;requestType&lt;/span&gt;&lt;span class="sy0" style="color: #002200; font-weight: normal;"&gt;:&lt;/span&gt;&lt;span class="br0" style="color: #002200; font-weight: normal;"&gt;(&lt;/span&gt;&lt;span style="font-weight: normal;"&gt;MGTwitterRequestType&lt;/span&gt;&lt;span class="br0" style="color: #002200; font-weight: normal;"&gt;)&lt;/span&gt;&lt;span style="font-weight: normal;"&gt;requestType&lt;/span&gt; &lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New',Courier,monospace;"&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; responseType&lt;span class="sy0" style="color: #002200;"&gt;:&lt;/span&gt;&lt;span class="br0" style="color: #002200;"&gt;(&lt;/span&gt;MGTwitterResponseType&lt;span class="br0" style="color: #002200;"&gt;)&lt;/span&gt;responseType; &lt;/li&gt;&lt;/span&gt;&lt;/span&gt;&lt;/ol&gt;&lt;/div&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 12px;"&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;which overrides the default in the base MGTwitterEngine. &amp;nbsp;It's described quite nicely in a comment but does nothing to explain the consequences of doing it this way.&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 12px;"&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="objc" style="background-color: #f0f0f0; border: 1px dotted rgb(160, 160, 160); color: #0000bb; font-family: 'Courier New',Courier,monospace; font-size: 13px; line-height: 14px; margin: 0px; padding: 0px; white-space: nowrap;"&gt;&lt;ol&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 12px;"&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 12px;"&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New',Courier,monospace;"&gt;&lt;span class="co2" style="color: #11740a; font-style: italic;"&gt;// -------------------------------------------------------------------------------&lt;/span&gt; &lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New',Courier,monospace;"&gt;&lt;span class="co2" style="color: #11740a; font-style: italic;"&gt;// mdificatfrom the base clase&lt;/span&gt; &lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New',Courier,monospace;"&gt;&lt;span class="co2" style="color: #11740a; font-style: italic;"&gt;// the base class appends parameters here&lt;/span&gt; &lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New',Courier,monospace;"&gt;&lt;span class="co2" style="color: #11740a; font-style: italic;"&gt;// -------------------------------------------------------------------------------&lt;/span&gt; &lt;/li&gt;&lt;li class="li2" style="background-color: #e0e0e0; color: #000090; font-family: 'Courier New',Courier,monospace; font-weight: bold; line-height: 11px;"&gt;&lt;span class="co2" style="color: #11740a; font-style: italic;"&gt;// &amp;nbsp; &amp;nbsp;if (params) {&lt;/span&gt; &lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New',Courier,monospace;"&gt;&lt;span class="co2" style="color: #11740a; font-style: italic;"&gt;// &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;fullPath = [self _queryStringWithBase:fullPath parameters:params prefixed:YES];&lt;/span&gt; &lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New',Courier,monospace;"&gt;&lt;span class="co2" style="color: #11740a; font-style: italic;"&gt;// &amp;nbsp; &amp;nbsp;}&lt;/span&gt; &lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New',Courier,monospace;"&gt;&lt;span class="co2" style="color: #11740a; font-style: italic;"&gt;// -------------------------------------------------------------------------------&lt;/span&gt; &lt;/li&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/ol&gt;&lt;/div&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 12px;"&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The problem is that it doesn't consider which type of &lt;code&gt;MGTwitterRequestType&lt;/code&gt; is being used before making the decision to construct an OAuth request. &amp;nbsp;Certain actions simply don't require an OAuth-formatted request, and in this case it just plain doesn't work. &amp;nbsp;MGTwitterSearchRequest and&amp;nbsp;MGTwitterSearchCurrentTrendsRequest are two types that I don't believe require authentication, and therefore have no use for OAuth requests. &amp;nbsp;To fix the problem for this particular request type add the following code to the beginning of&amp;nbsp;SA_OAuthTwitterEngine's implementation of &lt;code&gt;_sendRequestWithMethod:&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 12px;"&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;div class="objc" style="background-color: #f0f0f0; border: 1px dotted rgb(160, 160, 160); color: #0000bb; font-family: 'Courier New',Courier,monospace; font-size: 13px; line-height: 14px; margin: 0px; padding: 0px; white-space: nowrap;"&gt;&lt;ol&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 12px;"&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 12px;"&gt;&lt;span class="Apple-style-span" style="font-family: monospace;"&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New',Courier,monospace;"&gt;&lt;span class="co2" style="color: #11740a; font-style: italic;"&gt;//Defer work to super because these requests don't support OAuth&lt;/span&gt; &lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New',Courier,monospace;"&gt; &lt;span class="kw1" style="color: #a61390;"&gt;if&lt;/span&gt;&amp;nbsp;&lt;span class="br0" style="color: #002200;"&gt;(&lt;/span&gt;requestType&amp;nbsp;&lt;span class="sy0" style="color: #002200;"&gt;==&lt;/span&gt;&amp;nbsp;MGTwitterSearchRequest || requestType&amp;nbsp;&lt;span class="sy0" style="color: #002200;"&gt;==&lt;/span&gt;&amp;nbsp;MGTwitterSearchCurrentTrendsRequest&lt;span class="br0" style="color: #002200;"&gt;)&lt;/span&gt;&amp;nbsp;&lt;span class="br0" style="color: #002200;"&gt;{&lt;/span&gt; &lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New',Courier,monospace;"&gt;  &lt;span class="kw1" style="color: #a61390;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return&lt;/span&gt;&amp;nbsp;&lt;span class="br0" style="color: #002200;"&gt;[&lt;/span&gt;super _sendRequestWithMethod&lt;span class="sy0" style="color: #002200;"&gt;:&lt;/span&gt;method path&lt;span class="sy0" style="color: #002200;"&gt;:&lt;/span&gt;path queryParameters&amp;lt;&lt;span class="sy0" style="color: #002200;"&gt;:&lt;/span&gt;params body&lt;span class="sy0" style="color: #002200;"&gt;:&lt;/span&gt;body requestType&lt;span class="sy0" style="color: #002200;"&gt;:&lt;/span&gt;requestType responseType&lt;span class="sy0" style="color: #002200;"&gt;:&lt;/span&gt;responseType&lt;span class="br0" style="color: #002200;"&gt;]&lt;/span&gt;;&lt;br /&gt;&lt;/li&gt;&lt;li class="li1" style="background-color: #e0e0e0; color: #000060; font-family: 'Courier New',Courier,monospace;"&gt;  &lt;span class="br0" style="color: #002200;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/ol&gt;&lt;/div&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 12px;"&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;span class="Apple-style-span" style="border-collapse: separate; color: black; font-family: 'Times New Roman'; font-size: medium; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px;"&gt;&lt;span class="Apple-style-span" style="font-family: Verdana,Arial,sans-serif; font-size: 12px; line-height: 18px;"&gt;&lt;/span&gt;&lt;/span&gt; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This certainly beats lugging around an instance of each class, one for reading and one for writing. &amp;nbsp;Hopefully this helps someone out, it was driving me nuts.&lt;br /&gt;&lt;br /&gt;After using GeSHi I have now decided that I need a new blogger theme....but one thing at a time. &amp;nbsp;Back to XCode.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18079639-6874947828966692643?l=mlb5000behrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mlb5000behrend.blogspot.com/feeds/6874947828966692643/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18079639&amp;postID=6874947828966692643' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/6874947828966692643'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/6874947828966692643'/><link rel='alternate' type='text/html' href='http://mlb5000behrend.blogspot.com/2010/09/saoauthtwitterengine-search-error-400.html' title='SA_OAuthTwitterEngine Search Error 400'/><author><name>Matthew Baker</name><uri>http://www.blogger.com/profile/09130722872162097459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_uqEMM3AOKNY/TO141z47zYI/AAAAAAAAACU/03UsFYn4Rxo/S220/41768_9328753_3338_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18079639.post-6980475546104946976</id><published>2010-09-12T21:10:00.002-04:00</published><updated>2010-09-12T21:11:28.487-04:00</updated><title type='text'>OCMock iPhone 4.1 SDK</title><content type='html'>I imagine that this is a common&amp;nbsp;occurrence&amp;nbsp;when a new version of the iPhone SDK comes out but I figured I'd put it out there for the droves of development teams who will take the plunge with the update this coming week.&lt;br /&gt;&lt;br /&gt;If your iOS project relies on OCMock and you just upgraded to the iOS 4.1 SDK (and you upped the Base SDK on the target to 4.1) then chances are your unit test projects aren't building. &amp;nbsp;To get it working again:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Checkout the OCMock trunk:&amp;nbsp;&lt;span class="Apple-style-span" style="color: #565656; font-family: Verdana, Tahoma, Arial, sans-serif; font-size: 11px; line-height: 15px;"&gt;&lt;a class="smarterwiki-linkify" href="http://svn.mulle-kybernetik.com/OCMock/trunk" style="color: #b8b9bb;"&gt;http://svn.mulle-kybernetik.com/OCMock/trunk&lt;/a&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="color: #565656; font-family: Verdana, Tahoma, Arial, sans-serif; font-size: 11px; line-height: 15px;"&gt;&lt;a class="smarterwiki-linkify" href="http://svn.mulle-kybernetik.com/OCMock/trunk" style="color: #b8b9bb;"&gt;&lt;/a&gt;&lt;/span&gt;Open the OCMock project in XCode&lt;/li&gt;&lt;li&gt;Change the Base SDK on the OCMockPhoneSim target to iOS Simulator 4.1 (see &lt;a href="http://stackoverflow.com/questions/1358033/iphone-base-vs-active-vs-deployment-target/1358314#1358314"&gt;Base SDK vs. Active SDK&lt;/a&gt;&amp;nbsp;for why).&lt;/li&gt;&lt;li&gt;Build the target.&lt;/li&gt;&lt;li&gt;Copy libOCMock.a and Headers from the build/$(CONFIG)-iphonesimulator folder to wherever you were keeping them before.&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;That should allow you to link and run but if your experience is anything like mine you'll be getting a bunch of unexplained errors like "An internal error&amp;nbsp;occurred&amp;nbsp;when handling command output: -[XCBuildLogCommandInvocationSection testName]: unrecognized selector sent to instance". &amp;nbsp;Highly annoying but ultimately it will still report "X out of X tests passed" although with all those errors I'm less inclined to trust it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Thanks to &lt;a href="http://blog.octo.com/en/xcode-3-2-3-ios4-and-ocmock/"&gt;Vincent Daubry&lt;/a&gt; for pointing me in the right direction when he experienced the problem during the last major update.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18079639-6980475546104946976?l=mlb5000behrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mlb5000behrend.blogspot.com/feeds/6980475546104946976/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18079639&amp;postID=6980475546104946976' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/6980475546104946976'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/6980475546104946976'/><link rel='alternate' type='text/html' href='http://mlb5000behrend.blogspot.com/2010/09/ocmock-iphone-41-sdk.html' title='OCMock iPhone 4.1 SDK'/><author><name>Matthew Baker</name><uri>http://www.blogger.com/profile/09130722872162097459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_uqEMM3AOKNY/TO141z47zYI/AAAAAAAAACU/03UsFYn4Rxo/S220/41768_9328753_3338_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18079639.post-7005230046127067430</id><published>2010-09-08T17:18:00.000-04:00</published><updated>2010-09-08T17:18:25.035-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile design'/><title type='text'>Agile Design: Ask, is it still valuable?</title><content type='html'>Today I got some feedback from my lead on an early draft HLD document. Being new to the team, I asked whether or not they intended to keep the overall UML static class diagram which there was a placeholder for. He said that he wanted to keep it. I agreed because it could be a good first exposure for someone trying to ramp up on how the system works. What we disagreed on was how and when that diagram is created.&lt;br /&gt;&lt;br /&gt;I explained that I have no issue with the diagram as long as it is  generated from the code, as opposed to it being created before any code is  written. He responded with "up-front design is a software engineering best practice". Right away I could see this was a philosophical difference. I responded that while I agree in principle, I have never seen an end system look like the UML diagram that came before it. There's nothing wrong with that, the team just learns more about the system as it's implemented and takes action to improve the design. They let it evolve. We can spend all day diagramming, but I'd rather not spend time documenting and diagramming details that have a high probability of not reflecting reality when it's all said and done. It just makes the document misleading, and what's more, we'll end up having to reverse-engineer the diagrams from source to sync them up anyway. &lt;br /&gt;&lt;br /&gt;In his defense, I'm sure he's not really talking about the same big design up front that agilists abhor, but I still believe that up-front design all the way down to the static class diagram level is silly. If it's a thought-exercise, fine, it's usually helpful to at least identify your high level components in order to develop your metaphor, but don't begin the process with the expectation that it will reflect the final system. You'll be disappointed.&lt;br /&gt;&lt;br /&gt;Is all design analysis wasteful? Heck. No. My stance would have been different if there were a lot of unknowns with technology or various functional behavior. The additional analysis can be used to further mitigate the risk of a costly failed implementation. Most of all, it allows the team to learn more before diving in.&amp;nbsp; However, even in this scenario I would recommended a different approach, such as Spiking the feature or developing some examples to drive TDD. I prefer an approach that provides real feedback that I'm on the right track. Diagrams aren't very good at this.&lt;br /&gt;&lt;br /&gt;If the team is learning more about the system, that's the value in performing &lt;b&gt;some&lt;/b&gt; up front design, but only when the time isn't spent on something they would have easily discovered on their own if they had just gone ahead. When faced with a choice of more up-front design analysis, ask yourself, "Is this still valuable?" If your team will gain something from it then go for it without remorse (there's nothing un-agile about being responsible), but once mostly everyone is comfortable, move on and get to the real (and fun) work.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18079639-7005230046127067430?l=mlb5000behrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mlb5000behrend.blogspot.com/feeds/7005230046127067430/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18079639&amp;postID=7005230046127067430' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/7005230046127067430'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/7005230046127067430'/><link rel='alternate' type='text/html' href='http://mlb5000behrend.blogspot.com/2010/09/agile-design-ask-is-it-still-valuable.html' title='Agile Design: Ask, is it still valuable?'/><author><name>Matthew Baker</name><uri>http://www.blogger.com/profile/09130722872162097459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_uqEMM3AOKNY/TO141z47zYI/AAAAAAAAACU/03UsFYn4Rxo/S220/41768_9328753_3338_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18079639.post-4269690383750287007</id><published>2010-04-05T20:36:00.000-04:00</published><updated>2010-04-05T20:36:43.324-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='process improvement'/><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='process'/><title type='text'>Processes That Work For You</title><content type='html'>All processes have their pluses and minuses. &amp;nbsp;Many teams on each side of the 'agile boundary' think they've got it right, and they may, but it's not which side of the boundary they're on that matters. &amp;nbsp;What matters is that they've managed to find processes that work in context. &lt;br /&gt;&lt;br /&gt;Maybe you're on one of these teams. &amp;nbsp;Maybe they're mythical to you. &amp;nbsp;Either way, what a stripped down process framework like Scrum gets you is an opportunity to find what works for your team not just because your processes/practices haven't failed you yet, but because you've felt the pain the absence of that process/practice causes. &amp;nbsp;I'll say that again because I think it's worth repeating. &amp;nbsp;We want to be able to say our processes work not because they haven't yet failed us, but because we know exactly what will happen if we remove them; because we've experienced it first hand. &amp;nbsp;A major advantage of the shortened feedback loops of Scrum (or any iterative process) is that it allows you to frequently look at your problems, find their root cause, and come up with a way to fix it. &amp;nbsp;I've seen time and again that existing "traditional" practices are quite often the remedy. &amp;nbsp;I'm not the first to suggest "home-grown" processes but I do believe it's a good approach, perhaps the best if you can afford the effort and really dedicate to it. &amp;nbsp;Just like we wait to plan and estimate until we have the best information we're going to have (i.e. 'the last responsible moment'), why not apply the same methods to process adoption?&lt;br /&gt;&lt;br /&gt;Now I'm not suggesting we start from ground zero, that would be foolish. &amp;nbsp;Obviously we use version control, somehow elicit and track requirements, some form of configuration/requirements management, etc, but those are all just tools. &amp;nbsp;The processes and practices that you choose to employ (i.e. &lt;a href="http://en.wikipedia.org/wiki/Process_area_(CMMI)"&gt;Process Areas&lt;/a&gt;) should come from need. &amp;nbsp;Choose a responsible starting point and grow your processes as you find need for them from that point on. &amp;nbsp;If it's required that you meet CMMI Level 3, so be it, but you should still revisit your processes frequently (and hope that whatever governing body levied that requirement is willing to accept the added cost and possible, or inevitable, waste).&lt;br /&gt;&lt;br /&gt;It's also perfectly acceptable to discard processes that cost more than the value they add, or to replace them with more appropriate ones. &amp;nbsp;That's the beauty of retrospective. &amp;nbsp;After all, a failure across two weeks or even a month is better than a failure after a year of churning. &amp;nbsp;That is if you can course-correct as necessary. &lt;br /&gt;&lt;br /&gt;No matter what side of the agile boundary your team works on, you should regularly evaluate your practices and processes. &amp;nbsp;Ask these questions with your team:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Do we really need to be doing this? &amp;nbsp;What happens if we omit this? &amp;nbsp;Would it be responsible to omit this?&lt;/li&gt;&lt;li&gt;Can we be doing this better? &amp;nbsp;If so, is there anything specific we can implement immediately? &amp;nbsp;Anything we need to investigate further?&lt;/li&gt;&lt;li&gt;Does it feel like we're missing something? &amp;nbsp;Is there a practice or process we can introduce to fill the void?&lt;/li&gt;&lt;li&gt;Is something consistently going wrong? &amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/5_Whys"&gt;Why x 5&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;I've found that keeping a consistent eye on these things allows us to make changes quickly and effectively without sacrificing overall quality, or any number of other benefits various processes can provide. &amp;nbsp;All processes aren't all right for all situations. &amp;nbsp;Build what works from experience, from pain, from failure, not just because some book or group tells you so.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18079639-4269690383750287007?l=mlb5000behrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mlb5000behrend.blogspot.com/feeds/4269690383750287007/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18079639&amp;postID=4269690383750287007' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/4269690383750287007'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/4269690383750287007'/><link rel='alternate' type='text/html' href='http://mlb5000behrend.blogspot.com/2010/04/processes-that-work-for-you.html' title='Processes That Work For You'/><author><name>Matthew Baker</name><uri>http://www.blogger.com/profile/09130722872162097459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_uqEMM3AOKNY/TO141z47zYI/AAAAAAAAACU/03UsFYn4Rxo/S220/41768_9328753_3338_n.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18079639.post-7837454767519405108</id><published>2010-03-21T16:09:00.003-04:00</published><updated>2010-03-21T16:13:05.579-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='continuous learning'/><category scheme='http://www.blogger.com/atom/ns#' term='dojo'/><title type='text'>Giving Back to the Professional Community</title><content type='html'>&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;Inspiration&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;My brain has had a month or so to think about &lt;a href="http://www.agileuniversity.org/trainer.jsp?id=514"&gt;Jean Tabaka&lt;/a&gt;'s article,&amp;nbsp;&lt;i&gt;&lt;a href="http://www.nxtbook.com/nxtbooks/sqe/bettersoftware_1109/index.php?startid=18#/20"&gt;Countdown to Agility: 10 Characteristics of an Agile Organization&lt;/a&gt;,&lt;/i&gt;&amp;nbsp;in the&amp;nbsp;November/December 2009 issue of &lt;i&gt;Better Software Magazine&lt;/i&gt;&amp;nbsp;(I only read it last month). &amp;nbsp;This, combined with my recent exposure to talk of &lt;a href="http://codingdojo.org/"&gt;Coding Dojos&lt;/a&gt;, &lt;a href="http://coderetreat.ning.com/"&gt;Code Retreats&lt;/a&gt;, and &lt;a href="http://weekendtesting.com/"&gt;Weekend Testing&lt;/a&gt; in the TwitterVerse have inspired me to get my thoughts connecting these two down in writing. &amp;nbsp;Specifically I'd like to talk about #7 in the article, "&lt;i&gt;Contributing to the Community and Maintaining a Profitable Company&lt;/i&gt;".&lt;br /&gt;&lt;br /&gt;A recurring theme in the article is the marriage of seemingly competing interests, Work/Life Balance and Constant Delivery, Servant and Leader, Sustainable and Successful, the list goes on. &amp;nbsp;It's a good article, give it a read and see how your organization stacks up. &amp;nbsp;At first glance, giving back to the community seems like it will cost you while doing nothing more than generating good PR. &amp;nbsp;The article describes three communities to contribute to: the local community, the global community, and the professional community. &lt;br /&gt;&lt;br /&gt;When you hear "giving back to the community" usually you think of community service. &amp;nbsp;Usually this happens locally and there are a lot of companies that do a fantastic job of this so I won't harp on it. &amp;nbsp;I personally wouldn't know where to start giving back to the global community. &amp;nbsp;Perhaps contributing to relief efforts in areas like Haiti, Chile, and Japan given the recent earthquakes? &amp;nbsp;But something I don't hear a lot about is how organizations give back to the professional community. &lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;&lt;span class="Apple-style-span" style="font-size: medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;Types of Events&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I'm going to focus mainly on three types of events here; Code Retreats, Coding Dojos, and Weekend Testing, but anything that carries the spirit and intent of these events I feel should be handled the same by an organization. &amp;nbsp;I describe these as:&lt;br /&gt;&lt;blockquote&gt;A deliberate, purposeful (i.e. goal-oriented) gathering of like-minded professionals coming together to better themselves, their craft, and each other. &amp;nbsp;&lt;/blockquote&gt;I'm going to make a few observations about these events, interpret it as you will. &amp;nbsp;All data is as of this writing (March 20, 2010). I'm going to put more focus on the US groups because I'm biased:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Coding Dojos - Map available &lt;a href="http://maps.google.com/maps/ms?ie=UTF&amp;amp;msa=0&amp;amp;msid=116400871369678060090.000453a8d6ee3a6d3b8fe"&gt;here&lt;/a&gt;&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Lots of groups in Europe and South America&lt;/li&gt;&lt;li&gt;2 groups in Canada&lt;/li&gt;&lt;li&gt;Only 5 groups in the US&amp;nbsp;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Redmond (only open to Microsoft employees...)&lt;/li&gt;&lt;li&gt;University of Houston - appears to have gone dormant as of 2007&lt;/li&gt;&lt;li&gt;Oklahoma City&lt;/li&gt;&lt;li&gt;Pittsburgh Dojo - Last met Sept 2009&lt;/li&gt;&lt;li&gt;Albany, New York&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;br /&gt;Just looking at the map, the US is pretty far behind with this.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Code Retreats&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Boulder, Colorado&lt;/li&gt;&lt;li&gt;Pittsburgh, Pennsylvania&lt;/li&gt;&lt;li&gt;Philadelphia, Pennsylvania&lt;/li&gt;&lt;li&gt;Detroit, Michigan&lt;/li&gt;&lt;li&gt;Floyd, Virginia&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;These are just the ones listed on their homepage as coming up. &amp;nbsp;Noticeably Pittsburgh is on both lists and noticeably this list is all US. &amp;nbsp;That's pretty great and hopefully the list keeps growing.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Weekend Testing&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;4 chapters since inception in August 2009 in&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Chennai, India&amp;nbsp;&lt;/li&gt;&lt;li&gt;Hyderabad, India&lt;/li&gt;&lt;li&gt;Europe&lt;/li&gt;&lt;li&gt;Mumbai, India&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;The US is completely missing from this list. &amp;nbsp;I know we have talented testers that would love an opportunity like this to share their knowledge and expand their horizons. &amp;nbsp;I don't know what it would take to get chapters started throughout the US, but given the structure the group has taken on, local or regional technology councils seem like they would be a good place to start.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;As an Officer, why should I care?&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;By "officer" I mean someone holding a position of power and decision-making in an organization. &amp;nbsp;So why should you care? &amp;nbsp;Someone is bound to start one of these up in my area&amp;nbsp;&lt;i&gt;sometime&lt;/i&gt;, why should it be us? &amp;nbsp;Here are some big reasons that come to mind:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Your employees will get better (on their own time no less!)&lt;/li&gt;&lt;li&gt;People attending from outside see that you are supportive of your employees and their goals&lt;/li&gt;&lt;li&gt;Networks and ideas will develop between the people attending. &amp;nbsp;And we all know what comes from ideas.&lt;/li&gt;&lt;li&gt;Attendees will be more likely to consider your organization when they look for their next opportunity.&lt;/li&gt;&lt;li&gt;and perhaps more altruistically, you'll be contributing to the advancement of the craft. &amp;nbsp;Something everyone can always benefit from.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;So instead of "why should it?", "why &lt;i&gt;shouldn't&lt;/i&gt; it?". &amp;nbsp;It just means that when that next big advancement reveals itself you and yours will be ahead of the curve.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;Suggestions for Implementation&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So hopefully I've piqued your interest. &amp;nbsp;Now you ask, "how can I make it easier for everyone to get off the blocks and get one of these started?" &amp;nbsp; I'm glad you asked. &amp;nbsp;Here are some suggestions:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Do NOT&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Force your employees to host one or more of these events. &amp;nbsp;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;It may seem like a great recruiting and marketing opportunity, and it can be if approached correctly, but don't make it your primary goal. &amp;nbsp;Pursue it with this as your end goal and it's doomed from the onset. &amp;nbsp;These movements should be grassroots, initiated by people with a genuine desire to implement continuous learning and just&amp;nbsp;&lt;i&gt;get better&lt;/i&gt;. &amp;nbsp;You get better with practice, which is what these groups provide; an environment for software professionals to practice.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;Do&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Encourage people who wish to host events like these.&lt;/li&gt;&lt;li&gt;Remove barriers. &amp;nbsp;Make it easy for people to reserve spaces and market the events in your organization's name. &amp;nbsp;Some lunch money wouldn't hurt either :).&lt;/li&gt;&lt;li&gt;Provide support and resources. &amp;nbsp;&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Do these things and you're sure to see the long-term benefits I've described above.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What about your company? &amp;nbsp;Does it support efforts like this? &amp;nbsp;Do you have any additional suggestions for employees wanting to start one of these up?&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18079639-7837454767519405108?l=mlb5000behrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mlb5000behrend.blogspot.com/feeds/7837454767519405108/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18079639&amp;postID=7837454767519405108' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/7837454767519405108'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/7837454767519405108'/><link rel='alternate' type='text/html' href='http://mlb5000behrend.blogspot.com/2010/03/giving-back-to-professional-community.html' title='Giving Back to the Professional Community'/><author><name>Matthew Baker</name><uri>http://www.blogger.com/profile/09130722872162097459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_uqEMM3AOKNY/TO141z47zYI/AAAAAAAAACU/03UsFYn4Rxo/S220/41768_9328753_3338_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18079639.post-8515810667548682361</id><published>2010-03-04T20:45:00.001-05:00</published><updated>2010-03-04T20:46:21.321-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='visual studio'/><category scheme='http://www.blogger.com/atom/ns#' term='process improvement'/><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><category scheme='http://www.blogger.com/atom/ns#' term='change management'/><category scheme='http://www.blogger.com/atom/ns#' term='refactoring'/><title type='text'>Is tooling only for the youth?</title><content type='html'>Disclaimer: This post maybe have no basis in reality at all outside my team, it's just a question.  This post is done with information on a case study of &lt;span class="Apple-style-span"  style="font-size:large;"&gt;1&lt;/span&gt;.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I moved to the wide world of ANSI C++ after working in C# with the love of ReSharper for the better part of 2 years.  I managed but I definitely felt the absence of the great refactoring tool that took the things that should be easy and trivial and made them so.  C++ is not that way, especially with old IDEs.  So I started searching this past weekend for a C++ refactoring tool that actually supported my IDE.  I found one that claimed to support it, Visual Assist X, so I installed it and started playing around with it.  It works pretty well for what I need it to do but I haven't fully explored it yet.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Either way, this post isn't about Visual Assist X.  Today after I set up my keyboard shortcuts (to match ReSharper, no less) I called my team's senior developer over and showed him what it could do.  &lt;/div&gt;&lt;div&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;Him: Another tool?!? *shakes head* I don't trust tools to do much of anything.  They're just more systems with their own bugs.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Me: Yes but what they do they do well.  Why not take it for what it is and accept that nothing is perfect?&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;/div&gt;&lt;div&gt;Notice these are not direct quotes.  I remember better what he said than my own response (mostly because I was surprised by his reaction), but that was the general nature of the conversation.  He then proceeded to call me "Mr. Tool" and was quick to dismiss it.  I was a bit confused by this, but didn't think much of it at the time.  I had work to do so I went on my way.  &lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now, sitting in my living room catching up on back episodes of &lt;i&gt;Legend of the Seeker&lt;/i&gt; something creeps up from the back of my mind.  Do I really rely on that many tools?  Let's list them out:&lt;br /&gt;&lt;br /&gt;Development: &lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Visual Studio&lt;/li&gt;&lt;li&gt;CppUnit (is that really a "tool"?)&lt;/li&gt;&lt;li&gt;Rational PureCoverage for capturing code coverage&lt;/li&gt;&lt;li&gt;Hudson for Continuous Integration&lt;/li&gt;&lt;li&gt;CppDepend, CCCC, CppCheck, SourceMonitor for various static analysis (some do things better/more simply than others)&lt;/li&gt;&lt;li&gt;And now Visual Assist X for refactoring support.&lt;/li&gt;&lt;/ol&gt;Process:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Jira + GreenHopper&lt;/li&gt;&lt;li&gt;Confluence&lt;/li&gt;&lt;li&gt;Crucible&lt;/li&gt;&lt;li&gt;Fisheye&lt;/li&gt;&lt;/ol&gt;&lt;ol&gt;&lt;/ol&gt;&lt;div&gt;I don't think this list is unreasonable at all. OK, so maybe the static analysis tools are a bit excessive but I like data, especially when it costs me next to nothing to get it through Continuous Integration.&lt;br /&gt;&lt;br /&gt;Let's look back to September 2008 when I joined the team.  They were using exactly ONE of these tools, Visual Studio.  No unit testing, no continuous integration, no process support tools, certainly no automated testing, and worst of all no feedback mechanisms of any kind until a project ended and you handed it over to the customer to say "I hope this is what you wanted".&lt;br /&gt;&lt;br /&gt;Flash to today.  We have 20+ configurations in Hudson, our latest project has 90%+ unit test coverage at all times, our system testing is as automated as it can be so our test team isn't overwhelmed, all our documentation is maintained in Confluence, and all our issues and tasks are tracked in Jira.&lt;br /&gt;&lt;br /&gt;I feel like each of the tools listed above plays an integral part in my day-to-day work as a developer.  Obviously as developers we spend less time in the management systems and use very limited features of them, but does that make them any less important?  No.  If management can just jump out to Jira to check our status or out to Confluence to answer their question, that's one less thing they had to bother me or my team about.  It makes me happy and I don't even know it, and I'm sure they appreciate it too.&lt;br /&gt;&lt;br /&gt;Now I finally get to the question.  Is the reason for his reaction a generational thing or am I completely off base?  Are the youth more likely to find a tool-based solution to a pain point while the more seasoned have just learned to deal with it?&lt;br /&gt;&lt;br /&gt;Then there's the other possibility, am I over-reliant on tools?  Maybe I could simplify, but do I understand how they work, their purpose?  Absolutely.  I know what the scope of their functionality is, how they do what they do, what they're NOT meant to do, and how to bend them to my will &lt;b&gt;within the constraints of the tool&lt;/b&gt;.  Each one of them adds value and there are only 3 of them that any developer on the team really has to know or use; Visual Studio, CppUnit, and PureCoverage...I take that back, PureCoverage isn't necessary for them to understand, they just need to have it installed since every time they run a build it runs the unit tests with coverage.  They could completely ignore the results and I wouldn't know the difference.&lt;br /&gt;&lt;br /&gt;What do you think?  I'm sure there are exceptions as there are with any rule, but are the youth more likely to blaze new trails?&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18079639-8515810667548682361?l=mlb5000behrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mlb5000behrend.blogspot.com/feeds/8515810667548682361/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18079639&amp;postID=8515810667548682361' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/8515810667548682361'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/8515810667548682361'/><link rel='alternate' type='text/html' href='http://mlb5000behrend.blogspot.com/2010/03/is-tooling-only-for-youth.html' title='Is tooling only for the youth?'/><author><name>Matthew Baker</name><uri>http://www.blogger.com/profile/09130722872162097459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_uqEMM3AOKNY/TO141z47zYI/AAAAAAAAACU/03UsFYn4Rxo/S220/41768_9328753_3338_n.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18079639.post-4869800199429987647</id><published>2010-02-10T19:25:00.012-05:00</published><updated>2010-02-10T22:41:58.893-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='process improvement'/><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='change management'/><title type='text'>From Waterfall to Agile: How we got there</title><content type='html'>&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;Upon Arrival&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;When I arrived on my contract in September/October 2008 things were much different than today.  &lt;div&gt;&lt;ul&gt;&lt;li&gt;Projects took on average 3-6 months to complete, with few checkpoints in between.  Stakeholders couldn't get any value out of the systems until the end of the project even if they wanted to.&lt;/li&gt;&lt;li&gt;Projects were developed by a single person with very little, if any, collaboration.  &lt;/li&gt;&lt;li&gt;The test group was far disconnected from the development team and was not involved with the project until it was thrown over the fence for testing.  The testers also had little to no technical background.  This isn't necessarily a bad thing, but for our particular group the need to understand the domain and the systems is important.&lt;/li&gt;&lt;li&gt;Requirements (and the rest of the documentation) were written by the developers, usually after the system was implemented.  The only reason it was documented at all was because it was required by the client.&lt;/li&gt;&lt;li&gt;While we were co-located with our customer, there was little involvement for validation purposes and contact with users was difficult and I didn't see the team press for it.&lt;/li&gt;&lt;li&gt;Developer verification wasn't being done on a regular basis, if at all.  No unit testing at all, at least not on my team.  Another group was using it minimally but I don't know if it was a core part of their practice.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;Immediate Feedback&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;The first thing I do when I start with a new team is see how they operate.  If there are things that aren't being done well, or not at all, I make it a point to find the reasons.  This helps to point me in the best direction for fixing existing processes and implementing new things while creating the least friction.  The reasons can vary, anything from management pressure, general uncertainty, to god forbid, complacency.  &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Most of the practices the team had no familiarity with.  Things like developer unit testing, continuous integration, testing throughout the lifecycle, etc.  But other things, specifically the documentation problems, were chalked up to a "sad truth" that we just had to accept as a cost of doing business.  We'll see about that.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;The simplest practices to implement were those that I could stand up and use myself and introduce my team to later.  Those were Continuous Integration and Developer Unit Testing.  I stood up a CruiseControl instance on a spare server and integrated CUnit/CppUnit with our current projects and any new projects moving forward.  This took some work, especially stripping the core functionality into its own library so CppUnit could use it, but we got there.  There was some cost involved with educating the team on how to write unit tests and to check CI often but it was minimal.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;To be clear, Continuous Integration came before I introduced unit testing to the team.  I did this because I feel automated unit testing adds the most value when the developers can't just forget about it (intentionally or not).  This is particularly important when everyone is still learning.  CI acts as a failsafe to make sure the unit tests pass on an independent machine.  The CI server doesn't care about your feelings. If something is broken, it will tell you with some emails and a nice red block on the build status page (and &lt;a href="http://wiki.hudson-ci.org/display/HUDSON/Emotional+Hudson+Plugin"&gt;Emotional Hudson&lt;/a&gt; in Hudson's case).&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;Testing Throughout the Lifecycle&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Having just received my CTFL from the ASTQB the idea of testing throughout the lifecycle was fresh in my mind.  It wasn't the first time I've heard of the concept (my Software Engineering Principles course in school touched on it briefly) but for the first time I had something actionable that I could readily apply.  We were using the V-Model so the transition from project states was a perfect place to implement it. Using the states on the V-Model diagram below (from &lt;a href="http://en.wikipedia.org/wiki/V-Model"&gt;Wikipedia&lt;/a&gt;) we implemented static analysis on documents after the Requirements and Architecture activities (SRS), and the Detailed Design Activities (HLD), while building Test Plans, Procedures, and Cases concurrently with development efforts.  The effect of this was two fold&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;It immediately increased the quality of our systems and their documentation.&lt;/li&gt;&lt;li&gt;It got the test team closer to the development team and got both those groups closer to the customer.&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;/div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://upload.wikimedia.org/wikipedia/commons/2/22/Systems_Engineering_Process_II.gif"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 624px; height: 324px;" src="http://upload.wikimedia.org/wikipedia/commons/2/22/Systems_Engineering_Process_II.gif" border="0" alt="" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;Growing Pains&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;All of this change didn't come without its problems.  After a couple months of leveraging CruiseControl some of the other groups started to take interest.  They wanted in on the party!  However, CruiseControl was becoming a pain to maintain.  Adding new projects required modifying the XML configuration by hand and then restarting the server.  This wasn't the worst of it though.  I was the only person who knew how to do this, making me the guru.  Max Pool at CodeSqueeze has written about gurus &lt;a href="http://www.codesqueeze.com/why-office-gurus-are-bad-and-the-buses-who-hit-them/"&gt;before&lt;/a&gt; and they're not ideal, especially when they're you.  Anyway, after inquiring with the development community at my firm I was introduced to &lt;a href="http://www.husdon-ci.org/"&gt;Hudson&lt;/a&gt; and my life has never been the same.  Hudson made it dead simple for teams to add their own projects and do whatever they wanted with them, all without having to come to me for help.  &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;Project Opacity&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;After introducing better engineering practices I now turned my focus to project visibility.  The management team had a hard time getting a grasp on where our projects were.  That is, our project visibility was very low.  We had weekly status meetings that were always to the tune of "what have you done for me this week?".  The meetings were often unhelpful to everyone and have only recently been done away with (within the last month or so), probably as a result of the increase in project visibility.  At least I'd like to think so :).  This led me to start rolling out Atlassian's &lt;a href="http://www.atlassian.com/software/jira/"&gt;Jira&lt;/a&gt;.  It allows management to break down work and see exactly what was being worked on in real-time, all without having to bother the delivery team.  This didn't come without purchasing hurtles (it cost more than $0) but we've been using it in production for the last two months.  &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;Documentation Management&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Our team has some pretty lofty documentation requirements levied upon us by our stakeholders, at least relative to other agile teams.  They take our systems and documentation and perform further third-party evaluations to make sure we meet their standards.  We are required to provide them with our ConOps, SRSs, HLDs (sometimes), test plans, test procedures, test reports, and user's guides.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Anyone who has attempted to maintain Office documents in Subversion knows how much of a pain it can be.  This got me started on the long path of trying to find a better solution.  At first, I tried building documentation inside Trac, our wiki at the time, but I quickly learned that it didn't support exporting all that well.  Wiki2PDF kind of worked, but broke anytime someone sneezed.  That clearly wasn't going to work so I moved on.  Then I attended a talk given by another organization on the Atlassian tool suite where I was introduced to &lt;a href="http://www.atlassian.com/software/confluence/"&gt;Confluence&lt;/a&gt;.  I was hesitant to consider changing our wiki system at first since Trac was an integral part of our day-to-day work, but Confluence's build in support for Word, PDF, and HTML export changed my mind.  Confluence's built in features combined with the Universal Wiki Converter (and some select SQL update statements) made this transition a breeze allowing me to export everything from Trac and import it into Confluence.  Everyone left on Friday using Trac and began using Confluence on Monday.  &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Since then we have imported all our old Word documentation into Confluence and deleted them from our Subversion repositories (a happy day indeed!).  We now build and maintain all our documentation for all our projects inside Confluence where we can get it our for distribution at any time.  I like to think of the knowledge inside of Confluence as being the Configuration Items and the consequent document exports to be "compiling" that knowledge.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;Release Management&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Our release management process used to be defined in a very heavyweight (70+ page) CM Plan document that was way heavier than it needed to be.  Now it's documented on a single Confluence page that describes how to&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style=" ;font-size:medium;"&gt;Tag a build using Hudson&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style=" ;font-size:medium;"&gt;Export the documentation from Confluence as PDFs and &lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style=" ;font-size:medium;"&gt;Store the Hudson binaries and PDFs in version control as a release tag. &lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Why does it need to be any more complicated than that?&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;Implementing Agile&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;While all paths led here it wasn't absolutely necessary to implement agile.  The reason for choosing to go with an agile methodology, Scrum specifically, was bullet #1 at the beginning of this post.  Ultimately we're responsible for delivering software systems.  In the old process 5 months into a 6 month project we had nothing to speak of, yet we would have thrown 5 months worth of funding at it.  More specifically, our clients had.  If they have a need to use some features 5 months into the project why shouldn't they be able to?  We may have implemented those features in month 1, but we can't assure they work since testing wouldn't have started for another week or two.  The risk we had was that they would want to do just this.  If they came to us in a situation like this our value is likely to be questioned, and in this economy who can afford that? &lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Enter Scrum.  Now we maintain a Product backlog with high level user stories that are prioritized at the beginning of each Sprint.  We commit to a small subset of the requirements at the beginning of each sprint and (ideally) take all the stories to "done" within our sprints (typically 2-3 weeks, we're still finding our sweet spot), performing our release processes at the end of each sprint.  For us, done means&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Documentation has been updated (ConOp, SRS, HLD, User's Guides, Test Plan/Procedures)&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Code has been implemented with high (90%+) unit test code coverage (where reasonable) and has been checked in for Hudson to build.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Test procedures that are candidates for automation have been automated in one way or another.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Code and documentation has been review by the team and stakeholders, as appropriate.  We use &lt;a href="http://www.atlassian.com/software/crucible/"&gt;Crucible &lt;/a&gt;for code reviews.&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;See, documentation and Agile can coexist!  You just need to include it in your definition of done and be sure your team includes that work in its estimates.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: x-large;"&gt;Conclusion&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;So to wrap things up, here are my suggestions to anyone wanting to implement agile, especially Scrum since it doesn't prescribe engineering practices.  Many of these probably hold true for implementing change in general.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Implement engineering practices first.  You'll see the fastest impact here, and you'll need these come time to implement Scrum.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Lead by example.  Start using the new tools/practices on your own and your team will hopefully catch on.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Align project teams (development, QA) and stakeholders prior to implementing Scrum or you'll have some problems.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;If you can, ease your team into it.  It's all the better if they can arrive at the same conclusions as you on their own as to why the change is needed and how your fix will make things better.&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Don't force change if it can be avoided.  Provide a good reason for why this is being done.  My predecessor meant well but they forced many heavyweight processes on teams that had no say or warning, leading to processes that were not used.  If teams discover its use on their own, or are at least kept in the loop, they're more likely to accept and continue using them.&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:medium;"&gt;Do you have any additional suggestions on rolling out change on your teams?  Please comment below!&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18079639-4869800199429987647?l=mlb5000behrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mlb5000behrend.blogspot.com/feeds/4869800199429987647/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18079639&amp;postID=4869800199429987647' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/4869800199429987647'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/4869800199429987647'/><link rel='alternate' type='text/html' href='http://mlb5000behrend.blogspot.com/2010/02/from-waterfall-to-agile-how-we-got.html' title='From Waterfall to Agile: How we got there'/><author><name>Matthew Baker</name><uri>http://www.blogger.com/profile/09130722872162097459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_uqEMM3AOKNY/TO141z47zYI/AAAAAAAAACU/03UsFYn4Rxo/S220/41768_9328753_3338_n.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18079639.post-7649138807244334379</id><published>2010-01-11T22:23:00.000-05:00</published><updated>2010-01-11T22:23:37.551-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><category scheme='http://www.blogger.com/atom/ns#' term='mocking'/><category scheme='http://www.blogger.com/atom/ns#' term='OOD'/><title type='text'>Revisited: Reducing code duplication in rhinomocks</title><content type='html'>I've been wanting to come back to this for some time now but, quite frankly, I'm a bit ashamed to even look at it again.  I'm sure that by now I'm far enough away from it to be able to observe my work as if it were someone else's, and that's exactly how I'm going to structure this post.&lt;br /&gt;&lt;br /&gt;About a year and a half ago I wrote a post titled &lt;a href="http://www.bakermatt.com/2008/07/reducing-code-duplication-in-rhinomocks.html"&gt;Reducing Code Duplication in RhinoMocks Tests&lt;/a&gt; that now makes me want to scratch my eyeballs out.  Take a look, it will make you feel better about yourself :).  I suppose there would be nothing if not for progress so I'm revisiting it to go over what I (and most of you I'm sure) see as being entirely wrong with the approach described in that post, and talk about what I've learned since then about mocking and unit testing.&lt;br /&gt;&lt;br /&gt;The approach described in that post has several glaring issues; smells if you will:&lt;br /&gt;&lt;ol&gt;&lt;li style="font-weight: bold;"&gt;Branching&lt;span style="font-weight: normal;"&gt; unit tests, which is a general no-no&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;The tests are &lt;span style="font-weight: bold;"&gt;over-specified&lt;/span&gt;.  The close relationship between test code and the code under test greatly reduces the value of the tests and will make the tests very &lt;span style="font-weight: bold;"&gt;fragile&lt;/span&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The mocks are over-relied upon and have become a &lt;a href="http://en.wikipedia.org/wiki/Law_of_the_instrument"&gt;Maslow's Hammer&lt;/a&gt;.  I was trying so hard to isolate the presenter class that I missed the point.  I was shooting for metrics while  ignoring the business logic the MVP implementation is supposed to realize.&lt;span style="font-weight: bold;"&gt; &lt;/span&gt; I should have been focusing on the interactions between the classes, and should have only isolated to directly test specific, complex logic.  Only if the presentation logic was sufficiently complex should the model have been mocked away (and in such a case may not even belong in the presenter :)).&lt;br /&gt;&lt;/li&gt;&lt;li&gt;This code isn't really testing the classes in a way that is &lt;span style="font-weight: bold;"&gt;as close as possible to the way they'll be integrated in production&lt;/span&gt;&lt;span&gt;, and as a result&lt;/span&gt;&lt;span&gt; are very likely to miss things&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;.&lt;/span&gt;&lt;/li&gt;&lt;/ol&gt;So what have I been doing about it?  I've been away from .NET development for the better part of a year working in C++ which I think has been really good for me.  C++ has the bare-essential constructs necessary to perform object-oriented design and as a result some of the more modern frameworks are less available.  I've only been able to find a single mocking framework for C++, googlemock, but I haven't used it yet.  Not because I don't want to, but because it hasn't been necessary.&lt;br /&gt;&lt;br /&gt;Since reading Steve Freeman and Nat Pryce's &lt;a href="http://www.growing-object-oriented-software.com/"&gt;Growing Object-Oriented Software Guided by Tests&lt;/a&gt; I've been approaching my unit testing differently.  I've started treating my unit tests as an executable specification that is defined before the "green" code is ever written, and now I can't do it any other way.  Yes, it's just TDD, but Freeman and Pryce's explanation felt more natural to me.   Anyway, their approach calls for acceptance-level tests to be written followed by smaller, more specific, unit tests that verify the details of your specification.   So how does this relate to mocking?  Simple, following this approach allows my design to naturally evolve into something where mocking becomes the final step, not the first, stretching my test fixtures to the point where run-time information is necessary.  Just mock out the necessary classes, provide the stimulus, and we're good.  Further, it enables me to keep my classes linked together in the way they'll really be used in production and send my stimuli all the way through the system to verify the final effects/output.  Obviously you'll want tests in the deeper regions of your classes, but I've gotten more value from my tests implementing them in this way.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18079639-7649138807244334379?l=mlb5000behrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mlb5000behrend.blogspot.com/feeds/7649138807244334379/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18079639&amp;postID=7649138807244334379' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/7649138807244334379'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/7649138807244334379'/><link rel='alternate' type='text/html' href='http://mlb5000behrend.blogspot.com/2009/08/revisited-reducing-code-duplication-in.html' title='Revisited: Reducing code duplication in rhinomocks'/><author><name>Matthew Baker</name><uri>http://www.blogger.com/profile/09130722872162097459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_uqEMM3AOKNY/TO141z47zYI/AAAAAAAAACU/03UsFYn4Rxo/S220/41768_9328753_3338_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18079639.post-1942281682242508760</id><published>2009-08-15T20:55:00.003-04:00</published><updated>2009-08-15T21:57:46.452-04:00</updated><title type='text'>Implicit or not...</title><content type='html'>I was in the weekly status meeting for one of our projects when I uncovered an integration requirement that wasn't defined anywhere in our requirements documentation.  When I asked the product owner why this was the case, he said that it was an implicit requirement, and that all software we develop should have it.  &lt;br /&gt;&lt;br /&gt;I'm sure we've all been here at one point or another but when it comes down to it, it's not the PO's fault.  It's our job when gathering requirements to bring these types of assumptions to the surface.  Requirements documentation doesn't care whether a requirement is assumed or hand delivered from the president, it just needs to be there.  Getting the stakeholders involved (really involved) in the requirements process is another blog post altogether.  Anyway, implicit or not, make sure it's out there for everyone to see.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18079639-1942281682242508760?l=mlb5000behrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mlb5000behrend.blogspot.com/feeds/1942281682242508760/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18079639&amp;postID=1942281682242508760' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/1942281682242508760'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/1942281682242508760'/><link rel='alternate' type='text/html' href='http://mlb5000behrend.blogspot.com/2009/08/implicit-or-not.html' title='Implicit or not...'/><author><name>Matthew Baker</name><uri>http://www.blogger.com/profile/09130722872162097459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_uqEMM3AOKNY/TO141z47zYI/AAAAAAAAACU/03UsFYn4Rxo/S220/41768_9328753_3338_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18079639.post-1491037233155036735</id><published>2009-04-08T18:46:00.004-04:00</published><updated>2009-12-30T17:15:18.981-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tester&apos;s role'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'>Software Testing: A Tester's Role, Part 2</title><content type='html'>&lt;font size="4"&gt;During Implementation&lt;/font&gt;&lt;br /&gt;A tester's role during implementation depends on how close the tester wants to be to the actual implementation of the system under test (SUT). If they are meant to be an independent tester, then treat the code as your Kryptonite. Don't go near it! The less you know about &lt;font style="font-style: italic;"&gt;how&lt;/font&gt; it's implemented the better. Ideally you should know nothing, but depending upon your operating environment that just might not be possible. At the very least, you had better be able to forget about the &lt;font style="font-style: italic;"&gt;how&lt;/font&gt; when you go to verify that the system does &lt;font style="font-style: italic;"&gt;what&lt;/font&gt; it's supposed to.&lt;br /&gt;&lt;br /&gt;During the implementation phase of the project, the test team can take a built version of the system and exercise it inside its intended operating conditions. Testing should be performed from the perspective of all human actors in the defined use cases. This protects against the team concentrating too hard on one actor's perspective. These "stagings" can be performed weekly, bi-weekly, monthly, or even daily if they so choose. How often depends on how quickly we want/need to receive feedback.&lt;br /&gt;&lt;br /&gt;Hopefully the developers are performing test-first development (for all our sakes), but if they aren't the test team will need to be extra vigilant during these stagings because they are effectively performing the unit and unit integration testing.&lt;br /&gt;&lt;br /&gt;An added benefit to staging is that by the time the system tests roll around the test team should be well versed in the system. They should know what it's intended to do, how to make it do those things, and what caused the most frequent failures in the past.&lt;br /&gt;&lt;br /&gt;A note on communication. Test plans and procedures should be "public domain" on your project. Everyone should be able to access them at any time, specifically the development team. If the developers know how you intend to exercise the system, they can make sure the system works in those cases. Remember that the point isn't to catch the mistakes of the developers to humilitate them. There is no line drawn in the sand, we're on the same team! The point is to catch problems across the board to protect the project and the people working on it.&lt;br /&gt;&lt;font style="font-weight: bold;"&gt;&lt;blockquote&gt;The sooner we catch these problems, the easier they are to fix.&lt;br /&gt;The easier they are to fix, the cheaper they are.&lt;br /&gt;The cheaper they are, the less overhead we incur.&lt;br /&gt;The less overhead we incur, the more work we can perform with that excess.&lt;/blockquote&gt;&lt;/font&gt;Or we could just take that money to the bank.  Either way, less money spent can be allocated elsewhere.&lt;font size="4"&gt;&lt;br /&gt;&lt;/font&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18079639-1491037233155036735?l=mlb5000behrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mlb5000behrend.blogspot.com/feeds/1491037233155036735/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18079639&amp;postID=1491037233155036735' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/1491037233155036735'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/1491037233155036735'/><link rel='alternate' type='text/html' href='http://mlb5000behrend.blogspot.com/2009/04/software-testing-testers-role-part-2.html' title='Software Testing: A Tester&apos;s Role, Part 2'/><author><name>Matthew Baker</name><uri>http://www.blogger.com/profile/09130722872162097459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_uqEMM3AOKNY/TO141z47zYI/AAAAAAAAACU/03UsFYn4Rxo/S220/41768_9328753_3338_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18079639.post-5369641884906898065</id><published>2009-04-08T17:10:00.019-04:00</published><updated>2009-12-30T17:15:04.341-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tester&apos;s role'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'>Software Testing: A Tester's Role, The Prelude</title><content type='html'>I recently gave a presentation to the test group at work that discusses how our project approaches testing.  I'm going to be posting the sections from that presentation over the next month or so.  It actually facilitated so much conversation that I only got through 2 of the 5 sections in twice the amount of time I initially set aside for the meeting.  But that's good, if people are talking about these process changes/improvements, they're more likely to be utilized.  Especially when those talking are managers :).&lt;br /&gt;&lt;br /&gt;Anyway, over the next month or so I'll post a new section once a week (maybe more often, no promises), covering what I've talked about.  Hopefully I can get some good feedback from people here (if anyone even reads my blog!). I split it up into smaller chunks to reduce the size of the individual posts.  These posts are to cover:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A Tester's Role, through the entire lifecycle (3 separate posts)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Test Level Entry/Exit Criteria&lt;br /&gt;&lt;/li&gt;&lt;li&gt;System Test Procedure Generation&lt;/li&gt;&lt;li&gt;Test Case Input Generation&lt;/li&gt;&lt;/ul&gt;So here we go.&lt;br /&gt;&lt;br /&gt;&lt;font size="5"&gt;A Tester's Role&lt;/font&gt;&lt;br /&gt;The job of a tester is different at every stage in development, but the overall goal is to promote and facilitate quality.  Traditionally, the role of tester was to click the button...after the system had already been implemented.  Today, however, that alone just doesn't cut it.  To be effective, testers need to be involved in all stages of the project lifecycle (aka. testing throughout the lifecycle).&lt;br /&gt;&lt;br /&gt;Different case studies have found that a bug found after release can cost 500 to 1500 times more to fix than if that same bug had been found at requirements.  Obviously this implies that the bug was &lt;font style="font-style: italic;"&gt;introduced &lt;/font&gt;during requirements, but this isn't always the case and is beside the point.  What if someone had been there to challenge what everyone assumed that particular requirement meant?  What if they asked the tough and often times, obvious questions?  Normally this is the job of the requirements analyst(s) on the project, but if you work on a smaller team like mine, there isn't one.  In this case, it must become the tester's responsibility.&lt;br /&gt;&lt;br /&gt;&lt;font size="4"&gt;During Requirements&lt;/font&gt;&lt;br /&gt;Requirements lay the foundation for everything the software is to become. If a foundation is weak, what happens to the building placed on it? Right, it either fails to be built at all, quickly crumbles to the ground, or costs tons of money to fix.  A tester's goal during requirements is to ask questions to get everyone on the same page.  If two developers each make an assumption about a requirement, they could each make a &lt;font style="font-style: italic;"&gt;different&lt;/font&gt; assumption. Worse yet, what if both of their assumptions are incorrect? Now we have two pieces of the system to fix instead of just one, not to mention that those pieces will likely be incompatible with each other to begin with (Continuous Integration can help with this problem, among other things).&lt;br /&gt;&lt;blockquote&gt;An Example:  We have a requirement which states: "The house shall have a front door."&lt;/blockquote&gt;Is this requirement ambiguous? You bet it is! This is an easy one to make an assumption about, but what is the correct solution? Consider the following (yeah, yeah I know the pictures suck):&lt;br /&gt;&lt;font style="text-decoration: underline;"&gt;&lt;br /&gt;&lt;/font&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_uqEMM3AOKNY/Sd01vy3AVUI/AAAAAAAAAAk/6q6nth0l0fs/s1600-h/used1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 295px; height: 162px;" src="http://3.bp.blogspot.com/_uqEMM3AOKNY/Sd01vy3AVUI/AAAAAAAAAAk/6q6nth0l0fs/s320/used1.png" alt="" id="BLOGGER_PHOTO_ID_5322469429844399426" border="0"&gt;&lt;/a&gt;&lt;br /&gt;Each of these solutions is valid by the above requirement, but which is the correct solution? Even this one could be more correct, depending on the customer's intentions:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_uqEMM3AOKNY/Sd005CIf_sI/AAAAAAAAAAc/L7LKfMKHiP0/s1600-h/house3.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 121px; height: 160px;" src="http://3.bp.blogspot.com/_uqEMM3AOKNY/Sd005CIf_sI/AAAAAAAAAAc/L7LKfMKHiP0/s320/house3.png" alt="" id="BLOGGER_PHOTO_ID_5322468489051504322" border="0"&gt;&lt;/a&gt;&lt;br /&gt;The point is that based on the above requirement, all these solutions are valid. At this point, the tester can ask his/her self, how would I verify this? Just check if it has a door on the front of the house? But &lt;font style="font-style: italic;"&gt;Where&lt;/font&gt;?&lt;br /&gt;&lt;blockquote&gt;From a testing perspective, all requirements should be &lt;font style="font-style: italic;"&gt;verifiable&lt;/font&gt; and &lt;font style="font-style: italic;"&gt;quantifiable&lt;/font&gt;.&lt;/blockquote&gt;Who is qualified to answer this question? The architect? The homeowner? The contractor? The painter? Chances are that in this case the homeowner would have the final say (they're paying for it aren't they?), but what if they're building the house for someone else? The requirement should be refined by the primary actor/actors in the use case(s) mapped to this requirement. In this case, it's probably safe to say that the homeowner is the best choice (unless they really are building the house for someone else, in which case we would go to them). So, we contact the stakeholder and ask them to be more specific, and we get the following refined requirement.&lt;br /&gt;&lt;blockquote&gt;The house shall have a front door on the first level.&lt;br /&gt;&lt;/blockquote&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_uqEMM3AOKNY/Sd02qclTZ9I/AAAAAAAAAAs/HQIUco48SO4/s1600-h/used2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 357px; height: 122px;" src="http://4.bp.blogspot.com/_uqEMM3AOKNY/Sd02qclTZ9I/AAAAAAAAAAs/HQIUco48SO4/s320/used2.png" alt="" id="BLOGGER_PHOTO_ID_5322470437476853714" border="0"&gt;&lt;/a&gt;Which is the first level?&lt;br /&gt;&lt;blockquote&gt;The house shall have a front door on the ground floor of the building.&lt;/blockquote&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_uqEMM3AOKNY/Sd01vy3AVUI/AAAAAAAAAAk/6q6nth0l0fs/s1600-h/used1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 295px; height: 162px;" src="http://3.bp.blogspot.com/_uqEMM3AOKNY/Sd01vy3AVUI/AAAAAAAAAAk/6q6nth0l0fs/s320/used1.png" alt="" id="BLOGGER_PHOTO_ID_5322469429844399426" border="0"&gt;&lt;/a&gt;Where on the ground floor?&lt;br /&gt;&lt;blockquote&gt;The house shall have a front door on the ground floor of the building, in between the two front windows.&lt;/blockquote&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_uqEMM3AOKNY/Sd026yvt18I/AAAAAAAAAA0/nSPV7BsCEf0/s1600-h/house1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 126px; height: 165px;" src="http://4.bp.blogspot.com/_uqEMM3AOKNY/Sd026yvt18I/AAAAAAAAAA0/nSPV7BsCEf0/s320/house1.png" alt="" id="BLOGGER_PHOTO_ID_5322470718304016322" border="0"&gt;&lt;/a&gt;And we have a winner!&lt;br /&gt;&lt;br /&gt;This requirement appeared obvious at first (as so many do), but upon further inspection couldn't have been much worse. As testers, requirements are our most precious artifact. They give us the means to verify everything that comes after it. In the absence of a dedicated requirements team or requirements analyst dedicated to our team, we need to make sure these requirements allow us to do our jobs. Ideally the developers shouldn't have to guess even once during their implementation, but when they inevitably do they should know who to get in contact with to have their questions answered.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18079639-5369641884906898065?l=mlb5000behrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mlb5000behrend.blogspot.com/feeds/5369641884906898065/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18079639&amp;postID=5369641884906898065' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/5369641884906898065'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/5369641884906898065'/><link rel='alternate' type='text/html' href='http://mlb5000behrend.blogspot.com/2009/04/software-testing-testers-role-prelude.html' title='Software Testing: A Tester&apos;s Role, The Prelude'/><author><name>Matthew Baker</name><uri>http://www.blogger.com/profile/09130722872162097459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_uqEMM3AOKNY/TO141z47zYI/AAAAAAAAACU/03UsFYn4Rxo/S220/41768_9328753_3338_n.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_uqEMM3AOKNY/Sd01vy3AVUI/AAAAAAAAAAk/6q6nth0l0fs/s72-c/used1.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18079639.post-3305205389103901167</id><published>2009-01-18T11:26:00.002-05:00</published><updated>2009-01-18T12:24:35.169-05:00</updated><title type='text'>Is the Windows 7 Process to Thank for its Beta Success?</title><content type='html'>We all know that a beta release does not necessarily speak to the final product, but it doesn't stop people from raising expectations.  If recent praise is any indication, the hype surrounding Windows 7 should get it off to a positive start.  A recent post over at &lt;a href="http://arstechnica.com/journals/microsoft.ars/2009/01/16/what-killed-vista-will-make-windows-7-fly"&gt;ars technica&lt;/a&gt; talks about how the recent (positive) media hype should have the opposite effect of the media surrounding Vista at about this point in its release cycle.&lt;br /&gt;&lt;br /&gt;I, like Emil, am one of the Vista users who haven't had many problems with Vista since adopting it, but what is the root cause of Windows 7's media praise?  Is it simply because there was nowhere to go but up, or were there fundamental process changes that increased quality across the board?  If you have any interest in software process and haven't read Larry Osterman's &lt;a href="http://blogs.msdn.com/e7/archive/2008/10/15/engineering-7-a-view-from-the-bottom.aspx"&gt;post&lt;/a&gt; about how Windows 7 handles changes/features, you should do it now.&lt;br /&gt;&lt;br /&gt;The question I have is this.  Does Microsoft have the new configuration management and Winmain branch merge controls, resulting in fewer bugs actually reaching the beta, to thank for its recent success?  Or is it simply the media blowing things out of proportion again as it did back with Vista?  Or something else entirely?&lt;br /&gt;&lt;br /&gt;I can't speak from personal experience since I haven't used the beta myself (I'm not an MSDN or TechNet member) but I'm interested in getting people's opinions on this.  Come to think of it, the fact that I'm calling it "success" without any first hand experience may be exactly the point.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18079639-3305205389103901167?l=mlb5000behrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mlb5000behrend.blogspot.com/feeds/3305205389103901167/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18079639&amp;postID=3305205389103901167' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/3305205389103901167'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/3305205389103901167'/><link rel='alternate' type='text/html' href='http://mlb5000behrend.blogspot.com/2009/01/is-windows-7-process-to-thank-for-its.html' title='Is the Windows 7 Process to Thank for its Beta Success?'/><author><name>Matthew Baker</name><uri>http://www.blogger.com/profile/09130722872162097459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_uqEMM3AOKNY/TO141z47zYI/AAAAAAAAACU/03UsFYn4Rxo/S220/41768_9328753_3338_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18079639.post-8707423523204503998</id><published>2008-11-23T14:12:00.004-05:00</published><updated>2009-12-30T17:14:23.792-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='RoR'/><category scheme='http://www.blogger.com/atom/ns#' term='rails'/><title type='text'>ActiveRecord::StatementInvalid: Mysql::Error: Unknown column</title><content type='html'>So I've just recently started teaching myself Ruby On Rails and have had my share of hurdles.  Most of them have involved the magical world of ActiveRecord, because that's where I've spent the majority of my time in the rails MVC architecture.  Also because the model is the foundation of any solid application.  Anyway, to the point.  I have encountered this error several times while running my tests when it goes to populate the test database using the fixtures.&lt;br /&gt;&lt;br /&gt;ActiveRecord::StatementInvalid: Mysql::Error: Unknown column 'user' in 'field list': INSERT INTO `users_posts` (`user`, `thread`, `body`, `active`) VALUES ('aaron', 'one', 'Some Text', true)&lt;br /&gt;&lt;br /&gt;This coming from the fixture users_posts.yml which would read something like:&lt;br /&gt;&lt;br /&gt;post1:&lt;br /&gt;&amp;nbsp;&amp;nbsp;user: aaron&lt;br /&gt;&amp;nbsp;&amp;nbsp;thread: one&lt;br /&gt;&amp;nbsp;&amp;nbsp;body: Some Text&lt;br /&gt;&amp;nbsp;&amp;nbsp;active: true&lt;br /&gt;&lt;br /&gt;aaron is an entry in users.yml, and 'one' is an entry in threads.yml.  This is a simple example, but the idea is that users and threads can have many posts.  You'll notice from the SQL that was printed out, that ActiveRecord was looking for a column called user, when in reality it's user_id.  This is something that ActiveRecord does on its own under the covers, so why didn't it work? &lt;br /&gt;&lt;br /&gt;ActiveRecord relies on the associations laid out in your models, so if you mess up or omit the associations inside your models, ActiveRecord will get stuck and assume that the data contained in your fixture is literal (i.e. columnName: data).  So the users_posts model should look something like this:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;class UsersPosts &lt; ActiveRecord::Base&lt;br /&gt;&amp;nbsp;&amp;nbsp;belongs_to :user&lt;br /&gt;&amp;nbsp;&amp;nbsp;belongs_to :thread&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;and the Users model can look something like this&lt;br /&gt;&lt;code&gt;&lt;br /&gt;class User &lt; ActiveRecord::Base&lt;br /&gt;&amp;nbsp;&amp;nbsp;has_many :users_posts&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;and the Threads model something like this&lt;br /&gt;&lt;code&gt;&lt;br /&gt;class Thread &lt; ActiveRecord::Base&lt;br /&gt;&amp;nbsp;&amp;nbsp;has_many :users_posts&lt;br /&gt;&amp;nbsp;&amp;nbsp;has_many :contributing_users, :class_name 'User', :through =&gt; :users_posts&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;But even after setting up these models in this fashion the fixture still messes up?  Why?  The problem goes back to fundamentals, model names should be singular.  Because I named my model users_posts, ActiveRecord choked when it tried to use it to get data into the database.  After replacing that model with one called user_post, everything works as expected.  &lt;br /&gt;&lt;br /&gt;It all falls back to that wonderful Rails principle of convention over configuration.  If you stick to convention everything will work just fine.  Deviate from it (even a little bit) and you'll be chasing ghosts for hours.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18079639-8707423523204503998?l=mlb5000behrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mlb5000behrend.blogspot.com/feeds/8707423523204503998/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18079639&amp;postID=8707423523204503998' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/8707423523204503998'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/8707423523204503998'/><link rel='alternate' type='text/html' href='http://mlb5000behrend.blogspot.com/2008/11/activerecordstatementinvalid-mysqlerror.html' title='ActiveRecord::StatementInvalid: Mysql::Error: Unknown column'/><author><name>Matthew Baker</name><uri>http://www.blogger.com/profile/09130722872162097459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_uqEMM3AOKNY/TO141z47zYI/AAAAAAAAACU/03UsFYn4Rxo/S220/41768_9328753_3338_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18079639.post-6717049365195804822</id><published>2008-09-02T08:29:00.011-04:00</published><updated>2009-12-30T17:13:25.572-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='MVP'/><category scheme='http://www.blogger.com/atom/ns#' term='reshaper'/><category scheme='http://www.blogger.com/atom/ns#' term='refactoring'/><title type='text'>An Adventure in Refactoring Part 1</title><content type='html'>In this N-Part series I'm going to chronicle the refactoring efforts of my team and I on my current project and pose some questions that fall in the realm of DDD, refactoring, testing, etc.  I don't really have a road map for this series but here is a basic idea of what I'm planning on hitting:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Part 1 - Project History &amp;amp; Overall Goals&lt;/li&gt;&lt;li&gt;Part 2 - Finding Focus - Refactoring, Where To Start?&lt;/li&gt;&lt;li&gt;Part 3 - The Big Picture - Utilizing Visualization Tools to Target Refactoring and Find Patterns&lt;br /&gt;  &lt;/li&gt;&lt;li&gt;Part 4 - A Flood of Information - What is NDepend Trying to Tell Me?&lt;br /&gt;  &lt;/li&gt;&lt;/ul&gt; &lt;span style="font-weight: bold;"&gt;&lt;/span&gt;Lately on my project there have been a lot of good things happening. TeamCity has been brought in for Continuous Integration, NUnit has begun to be used for automated regression testing (paired with WatiN for web testing), Sandcastle has been implemented at build time (nightly) to keep up to date project documentation, and I've been trying to sell NDepend as a refactoring/inspection tool the more I learn how to use it, and more importantly, understand what it's trying to tell me.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Background&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;Before you can really understand where I'm trying to go and what it's going to take to get there you need some background on where this application came from and what its current state is. The project was initiated more than a decade ago by a group of people who knew how to program, but really weren't developers. It was originally written in ColdFusion and was later ported to VB.NET when the need for a newer technology presented itself. This was a great first step and is necessary for any long term project to survive and continue evolving.&lt;br /&gt;&lt;br /&gt;The problem was that while the application now existed in a new object oriented language, the scripting mentality came along for the ride. Therefore a solid object model was not developed at the time of the port and over time any architectural changes that were meant to be enforced fell by the wayside when a release drew near. Since software is simply a means to an end within our organization (software is not our core business) best practices are sometimes not in place or, if they are in place they're not the highest priority. &lt;br /&gt;&lt;br /&gt;Flash to today and the team is populated with people who know software.  Even the PM has a background in software, specifically with this project.  I've been fortunate in the short time I've been here to be placed with a group of open-minded people who are willing to see both sides of an argument and accept (and follow) a path to positive change for both process and design.  I've heard horror stories about people being set in their ways and resisting change, even when the benefits are obvious. &lt;br /&gt;&lt;br /&gt;The story I've heard over and over again is "we're aware of the design problems with that [class], [assembly], [subsystem], etc. but we just haven't found the time to get in and change it."  I imagine that this is a problem in the majority of projects out there that ship a product in iterations (and probably some that don't).  You promise X at the beginning of an iteration, implement it during the iteration and then ship out at the end with little to no slack time. &lt;br /&gt;&lt;br /&gt;This is all well and good if your definition of 'Done' is implemented, tested and refactored because your estimates will have taken these things into account.  However, if your estimates don't include testing and refactoring more than likely you will exhaust your estimate and run out of time.  This is the first thing that has to change when attempting to implement these changes with a group who has never worked with them before.  Their definition of 'Done' needs to change, otherwise we'll never have the time to really test and refactor.&lt;br /&gt;&lt;br /&gt;Ok, I'm going to stop right there.  In all fairness, we did/do have QA on our team and our iterations end with a two week system testing buffer, but this testing effort was purely at the system acceptance level.  There was no developer testing going on at all, so even when a problem was discovered, assuming it wasn't obvious, it would take a little while to track it down.  You could even end up with the worst case where you're running in circles because the error you found is the result of another, more serious error.  Now, however, we have regression tests for most of the new functionality and for the pages we've managed to refactor, but there's still a long way to go. &lt;br /&gt;&lt;br /&gt;Wading through the source code for the system I come across things that can only be described as code stenches.  Yes I'm aware of the term code smell, and that's where I'm coming from.  They really do bother me that much.  Pages are often entities all their own with some even doing data access directly.  To make matters worse there are many places that business logic and requirements are implicitly implemented without proper comments or mention of it in the XML documentation, which is also sparse.  Data access is very heavily tied to the UI in that many of the DataGrids are bound to a DataSet which is the direct result of a database call.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;So where to go from here?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We have started refactoring our pages to MVP (Passive View) with IoC on existing forms to increase testability/reusability and disconnect the UI from the data and business layers.  Don't yell at me, I know the goal of IoC is &lt;a href="http://jeffreypalermo.com/blog/inversion-of-control-is-not-about-testability/"&gt;not testability&lt;/a&gt; but it was a solid means to an end.  This will likely continue to be the bulk of refactoring throughout this iteration but we have already added a DomainModel project where all solid domain objects should eventually end up.  The appropriate services then need to be refactored to be encapsulated within these domain objects.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18079639-6717049365195804822?l=mlb5000behrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mlb5000behrend.blogspot.com/feeds/6717049365195804822/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18079639&amp;postID=6717049365195804822' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/6717049365195804822'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/6717049365195804822'/><link rel='alternate' type='text/html' href='http://mlb5000behrend.blogspot.com/2008/09/adventure-in-refactoring-part-1.html' title='An Adventure in Refactoring Part 1'/><author><name>Matthew Baker</name><uri>http://www.blogger.com/profile/09130722872162097459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_uqEMM3AOKNY/TO141z47zYI/AAAAAAAAACU/03UsFYn4Rxo/S220/41768_9328753_3338_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18079639.post-946297472666579092</id><published>2008-07-14T09:56:00.015-04:00</published><updated>2010-01-23T13:03:42.600-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><category scheme='http://www.blogger.com/atom/ns#' term='IoC'/><category scheme='http://www.blogger.com/atom/ns#' term='dependency injection'/><category scheme='http://www.blogger.com/atom/ns#' term='mocking'/><title type='text'>Reducing Code Duplication in RhinoMocks Tests</title><content type='html'>UPDATE:  This post was later &lt;a href="http://mlb5000behrend.blogspot.com/2009/08/revisited-reducing-code-duplication-in.html"&gt;revisited&lt;/a&gt;, but it's still worth reading for an example of what mocking shouldn't be :).&lt;br /&gt;&lt;br /&gt;I was recently placed on my first project at my new job (I'll post about that later) and they're having me integrate a bunch of great things into their process.  These include automated unit testing, continuous integration and refactoring to patterns.  Anyway, I've been writing some of my unit tests using isolation with RhinoMocks and came up with a way to achieve full path coverage without duplicating my Expects between test cases.&lt;br /&gt;&lt;br /&gt;Below is a fairly standard MVP example.  A presenter method is invoked and makes decisions based on information obtained from the view.  Say you are testing the following method using isolation and assume the dependencies on view and model are injected via the presenter's constructor:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;public class Presenter&lt;br /&gt;{&lt;br /&gt;        IView view;&lt;br /&gt;        IModel model;&lt;br /&gt;&lt;br /&gt;        //...constructors, properties&lt;br /&gt;&lt;br /&gt;        public void Foo()&lt;br /&gt;        {&lt;br /&gt;                if (view.val1)&lt;br /&gt;                {&lt;br /&gt;                        //...&lt;br /&gt;                        model.F1();&lt;br /&gt;                        //...&lt;br /&gt;                        if (view.val2)&lt;br /&gt;                        {&lt;br /&gt;                                //...&lt;br /&gt;                                model.F2();&lt;br /&gt;                                //...&lt;br /&gt;                        }&lt;br /&gt;                        else&lt;br /&gt;                        {&lt;br /&gt;                                //...&lt;br /&gt;                                model.F3();&lt;br /&gt;                                //...&lt;br /&gt;                        }&lt;br /&gt;                }&lt;br /&gt;                else&lt;br /&gt;                {&lt;br /&gt;                        //...&lt;br /&gt;                        model.F4();&lt;br /&gt;                        //...&lt;br /&gt;                }&lt;br /&gt;        }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Now obviously there are 3 possible paths through this method:&lt;br /&gt;&lt;br /&gt;val1 = true &amp;amp; val2 = true&lt;br /&gt;val1 = true &amp;amp; val2 = false&lt;br /&gt;val1 = false &amp;amp; val2 = don't care&lt;br /&gt;&lt;br /&gt;Now, my approach to this sort of problem in the past had been to duplicate a lot of test code only to change a single case return:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;[Test]&lt;br /&gt;public void CanFooVal1TrueVal2True()&lt;br /&gt;{&lt;br /&gt;        Expect.Call(view.val1).Return(&lt;b&gt;true&lt;/b&gt;);&lt;br /&gt;        //...some expects&lt;br /&gt;        model.F1();&lt;br /&gt;        LastCall.IgnoreArguments();&lt;br /&gt;        //...some more expects&lt;br /&gt;        Expect.Call(view.val2).Return(&lt;b&gt;true&lt;/b&gt;);&lt;br /&gt;        //...some expects&lt;br /&gt;        model.F2();&lt;br /&gt;        LastCall.IgnoreArguments();&lt;br /&gt;        //...some more expects&lt;br /&gt;&lt;br /&gt;        mockery.ReplayAll();&lt;br /&gt;&lt;br /&gt;        presenter.Foo();&lt;br /&gt;        //Assertions&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;[Test]&lt;br /&gt;public void CanFooVal1TrueVal2False()&lt;br /&gt;{&lt;br /&gt;        Expect.Call(view.val1).Return(&lt;b&gt;true&lt;/b&gt;);&lt;br /&gt;        //...some expects&lt;br /&gt;        model.F1();&lt;br /&gt;        LastCall.IgnoreArguments();&lt;br /&gt;        //...some expects&lt;br /&gt;        Expect.Call(view.val2).Return(&lt;b&gt;false&lt;/b&gt;);&lt;br /&gt;        //...some expects&lt;br /&gt;        model.F3();&lt;br /&gt;        LastCall.IgnoreArguments();&lt;br /&gt;&lt;br /&gt;        mockery.ReplayAll();&lt;br /&gt;&lt;br /&gt;        presenter.Foo();&lt;br /&gt;        //Assertions&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;[Test]&lt;br /&gt;public void CanFooVal1False()&lt;br /&gt;{&lt;br /&gt;        Expect.Call(view.val1).Return(&lt;b&gt;false&lt;/b&gt;);&lt;br /&gt;        //...some expects&lt;br /&gt;        model.F4();&lt;br /&gt;        LastCall.IgnoreArguments();&lt;br /&gt;&lt;br /&gt;        mockery.ReplayAll();&lt;br /&gt;&lt;br /&gt;        presenter.Foo();&lt;br /&gt;        //Assertions&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;The approach I've come up with to solve this problem is to have each test case call a single method which uses its parameter list to take a path through the method being tested (granted this is one of the simplest mocking cases):&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;br /&gt;[Test]&lt;br /&gt;public void CanFooVal1TrueVal2True()&lt;br /&gt;{&lt;br /&gt;        FooPaths(true, true);&lt;br /&gt;&lt;br /&gt;        mockery.ReplayAll();&lt;br /&gt;&lt;br /&gt;        presenter.Foo();&lt;br /&gt;        //Assertions&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;[Test]&lt;br /&gt;public void CanFooVal1TrueVal2False()&lt;br /&gt;{&lt;br /&gt;        FooPaths(true, false);&lt;br /&gt;&lt;br /&gt;        mockery.ReplayAll();&lt;br /&gt;&lt;br /&gt;        presenter.Foo();&lt;br /&gt;        //Assertions&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;[Test]&lt;br /&gt;public void CanFooVal1False()&lt;br /&gt;{&lt;br /&gt;        FooPaths(false, true); //keep in mind val2 doesn't matter in this case&lt;br /&gt;&lt;br /&gt;        mockery.ReplayAll();&lt;br /&gt;&lt;br /&gt;        presenter.Foo();&lt;br /&gt;        //Assertions&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;private void FooPaths(bool val1, bool val2)&lt;br /&gt;{&lt;br /&gt;        Expect.Call(view.val1).Return(val1);&lt;br /&gt;        if (val1)&lt;br /&gt;        {&lt;br /&gt;                //...&lt;br /&gt;                model.F1();&lt;br /&gt;                LastCall.IgnoreArguments();&lt;br /&gt;                Expect.Call(view.val2).Return(val2);&lt;br /&gt;                if (val2)&lt;br /&gt;                {&lt;br /&gt;                        //...&lt;br /&gt;                        model.F2();&lt;br /&gt;                        LastCall.IgnoreArguments();&lt;br /&gt;                }&lt;br /&gt;                else&lt;br /&gt;                {&lt;br /&gt;                        //...&lt;br /&gt;                        model.F3();&lt;br /&gt;                        LastCall.IgnoreArguments();&lt;br /&gt;                }&lt;br /&gt;        }&lt;br /&gt;        else&lt;br /&gt;        {&lt;br /&gt;                //...&lt;br /&gt;                model.F4();&lt;br /&gt;                LastCall.IgnoreArguments();&lt;br /&gt;        }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;This makes it so that you only need to change Expects and other information relative to the code you are testing in once place (FooPaths) when the code you are testing changes.&lt;br /&gt;&lt;br /&gt;Does anyone else out there have any other solutions to this problem?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18079639-946297472666579092?l=mlb5000behrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mlb5000behrend.blogspot.com/feeds/946297472666579092/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18079639&amp;postID=946297472666579092' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/946297472666579092'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/946297472666579092'/><link rel='alternate' type='text/html' href='http://mlb5000behrend.blogspot.com/2008/07/reducing-code-duplication-in-rhinomocks.html' title='Reducing Code Duplication in RhinoMocks Tests'/><author><name>Matthew Baker</name><uri>http://www.blogger.com/profile/09130722872162097459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_uqEMM3AOKNY/TO141z47zYI/AAAAAAAAACU/03UsFYn4Rxo/S220/41768_9328753_3338_n.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-18079639.post-4227429640623068301</id><published>2007-09-26T16:32:00.001-04:00</published><updated>2009-12-30T16:57:00.789-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='visual studio'/><category scheme='http://www.blogger.com/atom/ns#' term='jobs'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'></title><content type='html'>Following my meeting with a few companies at the Penn State career fair this past week I realized that it's about time to start experimenting with Visual Studio 2008 Beta 2.  So I downloaded Visual Studio Team System 2008 Beta 2 and got to work.  Here's what's new in VS 2008 Team System Beta 2, according to Microsoft:&lt;br /&gt;&lt;br /&gt;Windows Vista support&lt;br /&gt;- Provides Windows Vista security compliance.  (aka, no more work-arounds for UAC)&lt;br /&gt;- IIS still requires admin rights.&lt;br /&gt;&lt;br /&gt;Allocation Stacks&lt;br /&gt;- Collects allocation data (from the perf session property page).&lt;br /&gt;- Available in the Allocation view performance report.&lt;br /&gt;&lt;br /&gt;Line-level sampling data&lt;br /&gt;- On by default.&lt;br /&gt;- Checks out the new IP and Line view performance reports (and line information in the Module view).&lt;br /&gt;&lt;br /&gt;Runtime control&lt;br /&gt;- Starts up automatically on profiler launch.&lt;br /&gt;- Enables and disables collection from the UI.&lt;br /&gt;- Starts with collection disabled.&lt;br /&gt;- Adds custom marks without editing code.&lt;br /&gt;&lt;br /&gt;Filtered analysis&lt;br /&gt;- Filters on timestamp, process, thread, and marks.&lt;br /&gt;- Works just like the work item tracking query system.&lt;br /&gt;- /filterfile (saves the filter from the UI if you need the format).&lt;br /&gt;&lt;br /&gt;Diff&lt;br /&gt;- Represents a flat diff of a single column with the ability to set a threshold for what shows up.&lt;br /&gt;- Selects two reports in the Performance Explorer and chooses diff from the right-click shortcut menu.&lt;br /&gt;- Chooses new diff report from the tools menu.&lt;br /&gt;- /diff on the command line.&lt;br /&gt;&lt;br /&gt;Improved chip counter support&lt;br /&gt;- Provides new friendlier names.&lt;br /&gt;- Configurable xml files.&lt;br /&gt;&lt;br /&gt;PDH (Windows) counter support&lt;br /&gt;- Filters on marks based on what the PDH data tells the user.&lt;br /&gt;- Checks out the windows counters page of the perf session properties.&lt;br /&gt;- /wincounter flag.&lt;br /&gt;&lt;br /&gt;Compressed report files&lt;br /&gt;- Created from full reports.&lt;br /&gt;- Generates small compressed files that open up very quickly.&lt;br /&gt;- Right-click the report in the UI and choose Save Analyzed.&lt;br /&gt;- /summaryfile on the command line.&lt;br /&gt;&lt;br /&gt;Hot Path&lt;br /&gt;- Calltree and allocation view—shows the user the lowest performing path.&lt;br /&gt;- Right-click on a node or use the buttons on the new toolbar.&lt;br /&gt;&lt;br /&gt;Copy to HTML&lt;br /&gt;- Copy from the view and paste into email.&lt;br /&gt;- cntrl-c.&lt;br /&gt;&lt;br /&gt;Load/Web test integration&lt;br /&gt;- Creates a load or web test.&lt;br /&gt;- Right-click and create a perf session from the test.&lt;br /&gt;&lt;br /&gt;Indigo support&lt;br /&gt;- Profiling tools now supports Indigo.&lt;br /&gt;&lt;br /&gt;If you've taken a look at the "&lt;a href="http://blogs.msdn.com/fxcop/"&gt;The Visual Studio Code Analysis Team Blog&lt;/a&gt;" recently you'll see that their team has integrated FXCop very well into Visual Studio with a slew of new features for ease of use/access.  The most visible thing to me was done after Beta 2 was released, however, with the addition of the Analyze menu item giving you quick access to the features of FXCop.&lt;br /&gt;&lt;br /&gt;Another addition in 2008 is the Test menu.  It looks like Microsoft is (finally) trying to make it so that you never need to leave Visual Studio to get your work done.  For example, in the past when I've run FXCop on my solutions, I found the UI provided by FXCop to be more usable than the Visual Studio integration provided.  The same went for testing.  I have been using the &lt;a href="http://www.nunit.org/"&gt;NUnit&lt;/a&gt; testing framework along side &lt;a href="http://www.jetbrains.com/resharper/"&gt;ReSharper&lt;/a&gt;  since I entered the field professionally and it is extremely simple to run my Test Fixtures: Right Click the Solution -&gt; Run Unit Tests and wait.  Another feature that will be very helpful is the ability to run coverage right inside Visual Studio, as opposed to running TestDriven.NET's Visual Studio integration.  If you're like me and attempting to make a transition from the NUnit testing framework to Microsoft's here are a few attribute correllations that may help:&lt;br /&gt;&lt;table style="width: 216px; height: 240px;" border="1" cellspacing="0"&gt;&lt;tbody&gt;&lt;br /&gt;&lt;tr&gt;&lt;td style="" solid="" 1px="" dddddd=""&gt;&lt;b&gt;NUnit&lt;/b&gt;&lt;/td&gt;&lt;td style="" solid="" 1px="" dddddd=""&gt;&lt;b&gt;Microsoft&lt;/b&gt;&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;TestFixture&lt;/td&gt;&lt;td&gt;TestClass&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;Test&lt;/td&gt;&lt;td&gt;TestMethod&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;SetUp&lt;/td&gt;&lt;td&gt;TestInitialize()&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;TearDown&lt;/td&gt;&lt;td&gt;TestCleanup()&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;TestFixtureSetUp&lt;/td&gt;&lt;td&gt;ClassInitialize()&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;tr&gt;&lt;td&gt;TextFixtureTearDown&lt;/td&gt;&lt;td&gt;ClassCleanup()&lt;/td&gt;&lt;/tr&gt;&lt;br /&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;Visual Studio Test Classes appear to work the same way as the ones you would create using NUnit, it's just the attributes you use are different.  I copied an NUnit test verbatim (aside from the Assert class method names) and ran it using the Visual Studio test runner and it worked fine.&lt;br /&gt;&lt;br /&gt;To mention ReSharper again, if you want to try out Visual Studio 2008 Beta 2 but can't live without ReSharper, you can download their &lt;a href="http://www.jetbrains.net/confluence/display/ReSharper/Nightly+Builds"&gt;nightly build&lt;/a&gt;.  According to &lt;a href="http://blog.benhall.me.uk/2007/08/resharper-and-visual-studio-2008-beta-2.html"&gt;Ben Hall&lt;/a&gt;'s blog anything later than v.3.0.2 should be compatible with Visual Studio 2008 Beta 2, but don't take my word for it as I'm yet to test it extensively on my own.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/18079639-4227429640623068301?l=mlb5000behrend.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://mlb5000behrend.blogspot.com/feeds/4227429640623068301/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=18079639&amp;postID=4227429640623068301' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/4227429640623068301'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/18079639/posts/default/4227429640623068301'/><link rel='alternate' type='text/html' href='http://mlb5000behrend.blogspot.com/2007/09/following-my-meeting-with-few-companies.html' title=''/><author><name>Matthew Baker</name><uri>http://www.blogger.com/profile/09130722872162097459</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://2.bp.blogspot.com/_uqEMM3AOKNY/TO141z47zYI/AAAAAAAAACU/03UsFYn4Rxo/S220/41768_9328753_3338_n.jpg'/></author><thr:total>0</thr:total></entry></feed>
