<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
	
	<channel>
		<title>Allan's Ramblings</title>
		<link>http://www.allannienhuis.com/index.php</link>
		<description>thoughts on technology and more</description>
		<language>en</language>
		<managingEditor>allan@allanandshelley.ca</managingEditor>
                <copyright>Copyright 2010</copyright>
		<generator>Pivot Pivot - 1.40.5: 'Dreadwind'</generator>
		<pubDate>Tue, 31 Aug 2010 08:15:57 -0700</pubDate>
		<ttl>60</ttl>
		
		
		
		
		<item>
			<title>Learning another language</title>
			<link>http://www.allannienhuis.com/archive/2009/10/07/Learning_another_language</link>
			<comments>http://www.allannienhuis.com/archive/2009/10/07/Learning_another_language#comm</comments>
                        <description><![CDATA[ <p>
I've been meaning to learn another programming language as a way of 'sharpening my tools', so to speak.&nbsp; For years I've had my eye on LISP, but wasn't sure it would be worth my time, given the predominance of the MS .net stack, Java, javascript, and some of the new scripting languages - ruby, python, etc.&nbsp; But I stumbled across a recommendation to watch a series of videos on LISP from MIT professors <span style="font-size: 90%">Hal Abelson and Gerald Jay Sussman.&nbsp; They are freely posted here:</span> <a rel="external" href="http://www.archive.org/details/mit_ocw_sicp">http://www.archive.org/details/mit_ocw_sicp</a>&nbsp; Well I tried the first lecture, and while I chuckled at the dress and hairstyles of the early 80's, I was quickly hooked on the content.&nbsp; I quickly realized that this wasn't just a course on LISP, but rather a great course on the really great concepts of computer programming.&nbsp; I'm on the 3rd lecture so far, and having a blast.&nbsp; This might be old-hat for some CS grads, but I'd still really recommend checking these out if you want to geek out on some advanced ideas.</p> ]]></description>
			<guid isPermaLink="false">41@http://allannienhuis.com/pivot/</guid>
			<category>Technology</category>
			<pubDate>Wed, 07 Oct 2009 19:45:00 -0700</pubDate>
		</item>
		
		
		
		<item>
			<title>Cisco VPN for Win7 x64</title>
			<link>http://www.allannienhuis.com/archive/2009/08/09/Cisco_VPN_for_Win7_x64</link>
			<comments>http://www.allannienhuis.com/archive/2009/08/09/Cisco_VPN_for_Win7_x64#comm</comments>
                        <description><![CDATA[ <p>The Cisco VPN client won't run on 64bit versions of windows, and Cisco has no plans to ship a 64 bit client anytime soon.&nbsp; In order to get VPN working on my shiny new Windows 7 x64 install, I tried to get the Cygwin/linux vpnc client working.&nbsp; I ran into a number of problems, so this post explains how it can be done and hopefully will help you avoid the same problems I had.&nbsp; I spent a lot of time researching information on the 'net, and wound up tweaking steps a bit and hacking scripts myself, but much of this is based on work by <a rel="external" href="http://blog.lizhao.com/2008/02/22/multiple-vpn-connections-at-the-same-time">Li Zhao</a> and <a rel="external" href="http://www.theologyweb.com/campus/showthread.php?p=2148649">Salty</a>.<br /></p><p><strong>NOTE: update 22 Mar 2010 -&nbsp;</strong><span class="Apple-style-span" style="font-family: Verdana, Arial, Helvetica, sans-serif; line-height: 15px; font-size: 11px; color: #424440"><strong>The Shrew.net client supports Win7 now, and seems to work flawlessly. It&rsquo;s a much better option if you don&rsquo;t already have a need for Cygwin.</strong><span class="Apple-style-span" style="color: #000000; font-family: Tahoma, Arial, sans-serif; line-height: 18px; font-size: 13px"><strong>&nbsp;</strong></span></span></p><p><br />To get Cisco VPN working on an x64 Windows 7, you need:<br /></p><ul>	<li>Cygwin - a wonderful set of tools to emulate a linux environment on windows</li>	<li>OpenVPN - to provide a virtual TAP network adapter</li>	<li>VPNC - the VPN Client</li></ul>Here's how to do it:<br />I turned off UAC for the purposes of getting all of this installed.&nbsp; I ran into a number of permissions issues and false starts when I left it turned on.&nbsp; This reduces the number of things that can go wrong in the install process, particularly with Cygwin.&nbsp; Feel free to turn UAC back on after the install process if you're so inclined.&nbsp; <br /><br /><strong>Install Cygwin:</strong><br /><ul>	<li>Download cygwin <a rel="external" href="http://www.cygwin.com/setup.exe">http://www.cygwin.com/setup.exe</a> installer and save to your hard drive (don't just run it directly)</li>	<li>Right-click on the setup file, and 'Run as administrator'. This may not actually be neccesary but it makes me feel good.</li>	<li>Accept defaults except for local packages directory - I changed that to c:\cygwin\packages.&nbsp; Saving stuff to my desktop is annoying.</li>	<li>Choose a mirror to download packages from.&nbsp; Choose something physically close to you. </li>	<li>Choose the following additional packages to include:&nbsp; (choose them by clicking on the word 'skip' in the 'New' column) 	<ul>		<li>Devel &gt; gcc-g++: C++ Compiler</li>		<li>Devel &gt; make: The GNU version of the 'make' utility</li>		<li>Libs &gt; libgcrypt: A general purpose crypto library based on the code from GnuPG</li>		<li>Libs &gt; libgcrypt-devel: A general purpose crypto library based on the code from GnuPG (development)</li>		<li>Libs &gt; libgpg-error: A library that defines common error values for GnuPG</li>		<li>Perl &gt; perl: Larry Wall's Practical Extraction and Reporting Language</li>	</ul>	</li>	<li>The rest of the cygwin install process is pretty obvious; just a couple more mouse clicks.</li></ul><strong>Install OpenVPN:</strong><br /><ul>	<li>Download the latest OPENVPN release candidate from <a rel="external" href="http://openvpn.net/index.php/open-source/downloads.html">http://openvpn.net/index.php/open-source/downloads.html</a></li>	<li>	<div align="left">	The version I downloaded was: <a rel="external" href="http://openvpn.net/release/openvpn-2.1_rc19-install.exe">http://openvpn.net/release/openvpn-2.1_rc19-install.exe</a> 	</div>	</li>	<li>Save it to your hard drive somewhere you can find it. </li>	<li>Make sure to run the installer as an administrator and in windows vista compatibility mode:&nbsp; (this IS neccesary!!) 	<ul>		<li>Open up windows explorer to that location.</li>		<li>Right click on the file you saved, and select 'properties' 		<ul>			<li>Select the 'compatibility' tab</li>			<li>In the Compatibility mode section, check the box 'Run this program in compatibility mode for:', choose Windows Vista (service pack 2)</li>			<li>In the Privilege Level section, check the box 'Run this program as an administrator'</li>			<li>OK/Apply the settings.</li>		</ul>		</li>	</ul>	</li>	<li>Now run the installer.&nbsp; Agree to the license agreement.&nbsp; </li>	<li>Uncheck all of the options EXCEPT for: 'TAP Virtual Ethernet Adapter', and 'add shortcuts to Start Menu' (in case you want to add another vpn connection)</li>	<li>Install to default location.</li>	<li>The installer should have created a TAP adapter in Control PanelNetwork and InternetNetwork Connections.&nbsp; It's probably called Local Area Connection 2.&nbsp; You NEED to rename it to something without a space in the name and something you'll remember.&nbsp; I called mine 'CiscoVPN'.</li></ul><br /><strong>Build and install VPNC:</strong><br /><ul>	<li>Download the latest release of vpnc from : <a rel="external" href="http://www.unix-ag.uni-kl.de/%7Emassar/vpnc/">http://www.unix-ag.uni-kl.de/~massar/vpnc/</a> I got <a rel="external" href="http://www.unix-ag.uni-kl.de/%7Emassar/vpnc/vpnc-0.5.3.tar.gz">http://www.unix-ag.uni-kl.de/~massar/vpnc/vpnc-0.5.3.tar.gz</a></li>	<li>Save the file to a convenient temporary location, such as c:\cygwin\tmp </li>	<li>Right click on the Cygwin Bash Shell shortcut (should be on your desktop and/or start menu) and select 'Run as administrator' to open up a cygwin bash command prompt.&nbsp; IT IS CRITICAL THAT YOU RUN THIS AS ADMINISTRATOR OR YOU WILL FAIL AT CERTAIN POINTS IN THIS PROCESS SILENTLY!!! </li>	<li>Now extract the contents of the file and change to the extracted folder:</li></ul><blockquote>	$ cd /tmp<br />	$ tar xvfz vpnc&lt;tab&gt; <br />	$ cd vpnc&lt;tab&gt; </blockquote><ul>	<li>Now, compile it with make:</li></ul><blockquote>	$ make<br />	$ make PREFIX=/usr install<br />	$ mkdir /var/run/vpnc </blockquote><ul>	<li>For or some reason my own Cygwin install did not put /usr/sbin into the 'path' environment variable.&nbsp; Not sure why that is.&nbsp; You could add c:\cygwin\usrs\bin into your system path via advanced system properties in Windows, but here's how I fixed it:&nbsp; I edited my .bashrc file (found in your 'home' directory: /home/&lt;username&gt;/.bashrc ), and added these two lines:</li></ul><blockquote>	export PATH=${PATH}:/usr/local/bin<br />	export PATH=${PATH}:/usr/sbin/&nbsp; </blockquote><ul>	<li>You'll want to logout out of the bash shell and login again to have that take effect.&nbsp; REMEMBER TO 'RUN AS ADMINISTATOR'</li>	<li>You can check to make sure you can 'find' vpnc with this command:</li></ul><blockquote>	$ which vpnc<br />	/usr/sbin/vpnc<br /></blockquote><strong>Repair the VPN Routing configuration script:</strong><br /><ul>	<li>This is the bit that's broken in Win 7, or perhaps all x64 bit OS.&nbsp; The script in question is: /etc/vpnc/vpnc-script-win.js.&nbsp; I've posted my updated script here: <a rel="external" href="/images/vpnc-script-win.js" title="" class="download"><img src="http://www.allannienhuis.com/pivot/pics/icon_file.gif" width="16" height="16" alt="" class="icon" style="border:0;" /> </a> Note that I added a bunch of debugging information to the script.&nbsp; You can make it much quieter by removing or commenting out&nbsp;the two echo commands inside the run function definition on lines 17 and 19.</li>	<li>The script supplied with vpnc&nbsp;relies on the execution of the &quot;route print&quot; command to extract the default gateway on this computer.&nbsp; For some reason the results of that command do not format the default gateway information in Win 7 x64 in the expected manner (perhaps other versions as well - I've seen references to this problem with Vista x64).</li>	<li>To fix the script, you need to replace the function getDefaultGateway with this one I hacked together:</li></ul><blockquote>	<p>	function getDefaultGateway()<br />	{<br />	&nbsp;&nbsp;&nbsp; var output =&nbsp;&nbsp; run( &quot;route print 0.0.0.0&quot;&nbsp; ) ;<br />	&nbsp;&nbsp;&nbsp; var pos = output.indexOf(&quot;0.0.0.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0.0.0.0&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &quot;) + 30;<br />	&nbsp;&nbsp;&nbsp; var gw = output.substring(pos,pos+15); // max length of ip address<br />	&nbsp;&nbsp;&nbsp; gw = gw.substring(0,gw.indexOf(&quot; &quot;)); // trim at first space...<br />	&nbsp;&nbsp;&nbsp; echo(&quot;Default Gateway: [&quot; + gw + &quot;]&quot;);<br />	&nbsp;&nbsp;&nbsp; return gw;&nbsp;&nbsp;&nbsp; <br />	} 	</p></blockquote><ul>	<li>I suck at regular expressions so I didn't try to use them for this.&nbsp; If you're better with regular expressions than I am feel free to post a comment with an improved function.&nbsp;</li>	<li>I also found it neccessary to add a smal pause to the script before adding the internal routes. Without the pause, the 'route add' commands were not adding correct routes in every case.&nbsp;</li></ul><blockquote>	<p>	echo(&quot;Pausing for 4 seconds to allow the adapter to register itself correctly and therefore correct routing inferences made. You may need to supply a longer delay.&quot;);<br />	&nbsp;WScript.Sleep(4000);&nbsp; 	</p></blockquote><ul>	<li>I put that sleep command just before line: if (env(&quot;CISCO_SPLIT_INC&quot;)) {&nbsp;</li>	<li>I also noticed that&nbsp;after disconnecting (ctrl-c), there were still stray routes in the route table.&nbsp; I'm not sure that it matters because the route to the main vpn gateway is properly removed, but I went ahead and added some code to remove all of the routes added by the script when disconnecting:</li></ul><blockquote>	<p>	run(&quot;route delete &quot; + env(&quot;VPNGATEWAY&quot;) + &quot; mask 255.255.255.255&quot;);<br />	&nbsp;<br />	&nbsp;//remove internal network routes<br />	&nbsp;if (env(&quot;CISCO_SPLIT_INC&quot;)) {<br />	&nbsp;&nbsp;for (var i = 0 ; i &lt; parseInt(env(&quot;CISCO_SPLIT_INC&quot;)); i++) {<br />	&nbsp;&nbsp;&nbsp;var network = env(&quot;CISCO_SPLIT_INC_&quot; + i + &quot;_ADDR&quot;);<br />	&nbsp;&nbsp;&nbsp;run(&quot;route delete &quot; + network );<br />	&nbsp;&nbsp;} 	</p></blockquote><ul>	<li>Alternatively, I've posted an updated file here:<a rel="external" href="/images/vpnc-script-win.js" title="" class="download"><img src="http://www.allannienhuis.com/pivot/pics/icon_file.gif" width="16" height="16" alt="" class="icon" style="border:0;" /> </a>Just copy that to your /etc/vpnc folder.</li></ul><strong>Create your VPNC Configuration file:</strong><br /><ul>	<li>You need to convert your old Cisco .pcf file into a config file for vpnc in order to get the shared secret included in that file carried over correctly, and to make sure you have the ip address of the vpn gateway, etc.&nbsp; So, first copy your existing cisco .pcf file into somewhere convenient.&nbsp; /tmp is pretty convenient. Then run the pcf2vpnc utility:</li></ul><blockquote>	$ cd /tmp<br />	$ pcf2vpnc &lt;old Cisco filename&gt;.pcf /etc/vpnc/&lt;profilename&gt;.conf<br /></blockquote><ul>	<li>&lt;profilename&gt; is whatever unique name you want it to be.&nbsp; Note that we're saving the new configuration file to /etc/vpnc.&nbsp; You could always copy the created file to that location later.</li>	<li>Now, edit the file it created with your favorite unix friendly editor.&nbsp; Windows Notepad is no good.&nbsp; Go download <a rel="external" href="http://notepad-plus.sourceforge.net/uk/site.htm">Notepad++</a> right now; I'll wait.&nbsp; Got it? OK. Open the file /etc/vpnc/&lt;profilename&gt;.conf</li>	<li>You'll need to add a few items to the file:</li></ul><blockquote>	Interface name &lt;NameOfTheInterfaceYouPickedEarlier&gt; # mine is: CiscoVPN<br />	Interface mode tap<br />	Pidfile /var/run/vpnc/&lt;uniqueName&gt;.pid # need a unique one per profile, so may as well use &lt;profilename&gt;.pid<br />	Local Port 0&nbsp; #auto selects a port<br />	NAT Traversal Mode force-natt<br />	No Detach <br /></blockquote><ul>	<li>You really shouldn't do it, but you can also enter your password in this config file if you don't mind that password being there in plain text. The syntax for that is:</li></ul><blockquote>	Xauth password &lt;yourpassword&gt;&nbsp; # You've got a secure computer, right? Really? Are you sure? <br /></blockquote><ul>	<li>If you have any trouble, you can add a debug flag to your config file:</li></ul><blockquote>	Debug 1&nbsp;&nbsp;&nbsp;&nbsp; # valid values: 1-3, 99.&nbsp; 99 = everything, including authorization information (passwords), so be careful<br /></blockquote><br /><strong>Putting it all together:</strong><br /><ul>	<li>Actually there's not much to put together, you just need to use your shiny new vpnc command:</li></ul><blockquote>	$ vpnc &lt;profileNameWithoutExtension&gt;<br /></blockquote><ul>	<li>You could drop that command into an executable file to save a few keystrokes.&nbsp; I'll leave figuring out how to launch the cygwin bash shell and executing that command from a windows batch file (and so an icon on your desktop) up to you.&nbsp;&nbsp;</li></ul><p><br />I hope this works for you, but I can't guarantee anything!&nbsp; Feel free to post comments with your experiences. </p><p><strong>Update 10 Aug 09:</strong> </p><p>I have had issues with routing within the network if the vpn concentrator provides me with a new IP address.&nbsp; I'm not sure exactly why that happened or what to do in order to fix the routing - I'm not a network routing guru.&nbsp; I did figure out how to work around this issue though.&nbsp; In Control Panel\Network and Internet\Network Connections I went to the TCP/IPv4 settings and switched to dhcp ('obtain an IP address automatically, Obtain DNS server address automatically).&nbsp; These settings are overwritten when connecting to the vpn again, but for some reason making that change clears out something so that when connecting via vpnc the routing works again.&nbsp; For today anyways. :) </p><p>Cheers,&nbsp; </p><p>Allan </p><div class="zemanta-pixie"><img class="zemanta-pixie-img" src="http://img.zemanta.com/pixy.gif?x-id=fa6ea795-2bcc-8111-b046-c49bea868fbb" border="0" /> </div><div class="zemanta-pixie"><strong>Update 11 Aug 09:</strong> </div><div class="zemanta-pixie">I forgot to mention that in my research, this VPN client: http://www.shrew.net/software was mentioned by a number of folks as a valid free alternative.&nbsp; It actually looks pretty good, but I didn't try it, as I wanted to get the vpnc option figured out.&nbsp; I always install cygwin on my windows boxes so I didn't mind going down this route.&nbsp; If anyone has experience with the shrewsoft client on x64 bit windows, please comment here. </div> ]]></description>
			<guid isPermaLink="false">40@http://allannienhuis.com/pivot/</guid>
			<category>Technology</category>
			<pubDate>Sun, 09 Aug 2009 00:42:00 -0700</pubDate>
		</item>
		
		
		
		<item>
			<title>Speeding up the build – ditch the SSD and go for the RAM drive : Jeffrey Palermo (.com)</title>
			<link>http://www.allannienhuis.com/archive/2009/07/01/Speeding_up_the_build_–_ditc</link>
			<comments>http://www.allannienhuis.com/archive/2009/07/01/Speeding_up_the_build_–_ditc#comm</comments>
                        <description><![CDATA[ <a rel="external" href="http://jeffreypalermo.com/blog/speeding-up-the-build-ndash-ditch-the-ssd-and-go-for-the-ram-drive/">Speeding up the build – ditch the SSD and go for the RAM drive : Jeffrey Palermo (.com)</a><br /><br />Thought I'd pass along props to Jeffrey Palermo for doing a great job on his post about using RAM drives to improve developer workstation performance - specifically running builds &amp; unit tests.&nbsp; He's done a lot of experimenting and has the data to back up his choices.&nbsp; Definitely something to consider doing these days with RAM so cheap.<br /><blockquote></blockquote> ]]></description>
			<guid isPermaLink="false">39@http://allannienhuis.com/pivot/</guid>
			<category>default</category>
			<pubDate>Wed, 01 Jul 2009 06:41:00 -0700</pubDate>
		</item>
		
		
		
		<item>
			<title>Kaban Development Oversimplified - putting limits on parts of your development cycle</title>
			<link>http://www.allannienhuis.com/archive/2009/05/27/Kaban_Development_Oversimplifi</link>
			<comments>http://www.allannienhuis.com/archive/2009/05/27/Kaban_Development_Oversimplifi#comm</comments>
                        <description><![CDATA[ <!-- [DocumentBodyStart:9b8f4ed3-153f-4f5e-bd3c-0cb0bfe72a03] --><div class="jive-rendered-content"><div class="jive-rendered-content"><p><span>Jeff Patton</span> <a rel="external" class="jive-link-external-small" href="http://www.agileproductdesign.com/blog/2009/kanban_over_simplified.html">has a great blog</a> <span>about Agile product development practices - mostly from the product/design perspective, but he's got some good project management information in there too.&nbsp; He doesn't post very often, but his posts are real winners. </span><br /><a rel="external" class="jive-link-external-small" href="http://www.agileproductdesign.com/blog/2009/kanban_over_simplified.html"><br />His latest article</a> <span>is about Kanban Development - something that has been gaining traction and awareness in the Agile development community for the last year or two.&nbsp; I won't expound much on it here, as Jeff does a much better job of it than I would - read his post!</span></p><p style="padding: 0px; min-height: 8pt; height: 8pt;">&nbsp;</p><p><span>Kanban development comes from Toyota's famously efficient and high quality product development &amp; manufacturing teams - Kanban means literally visual card (or board), and is about the use of simple visual devices to control the</span> <em><strong>flow</strong></em> <span>of work through any system. </span></p><p style="padding: 0px; min-height: 8pt; height: 8pt;">&nbsp;</p><p><span>A common problem in software development is having too many unfinished work items on a person or team's plate at any one time.&nbsp; This is usually a symptom of people not completely finishing the items before moving on to the next one, because they've run into some type of roadblock with their current item (need a question answered, waiting for the next build, or whatever). </span></p><p style="padding: 0px; min-height: 8pt; height: 8pt;">&nbsp;</p><p><span>The problem with this is that it increases the amount of context switching people have to - do by orders of magnitude in some cases.&nbsp;&nbsp;&nbsp; The costs of context switching for people working in highly intellectual jobs like ours is very often grossly underestimated, because we're so used to multi-tasking and often our team culture often promotes it - people with a lot on their plate are looked up to as busy and productive, when they are really just spinning their wheels with lots of activity but little real progress.</span></p><p style="padding: 0px; min-height: 8pt; height: 8pt;">&nbsp;</p><p><span>A related problem is that this increases the 'cycle time' - the average amount of calendar time it takes for items to be completed, which increases the risk that items will become stale.&nbsp; For example it is much more efficient for a developer to fix bugs on an item that they coded today or yesterday than even a few days later. </span></p><p style="padding: 0px; min-height: 8pt; height: 8pt;">&nbsp;</p><p><span>The use of Kanban concepts can help with these problems by putting simple rules or governors on your software development workflow to simply not allow too many work items in any one stage or spot.&nbsp; For instance: you could have a rule to not allow more than x units of work in the Implementation (coding) state.&nbsp; If a business analyst is finished with another requirement/story/use case, they're not allowed to send it to the development queue.&nbsp; And if the size of work sitting in the design queue is already maxed out, they're not allowed to pick up another story and start working on that.&nbsp; What should they do then?&nbsp; Perhaps help the testers test some of the items in their queue.&nbsp; Perhaps go talk with customers about the latest release, or do some usability/user experience testing.&nbsp; Anything but drop more work on the developers.&nbsp; The same would go for developers - if the test queue is 'full', they can't drop more coded features onto the test team.&nbsp; They should go help the testers with their work items, help set up the performance testing lab, help troubleshoot the latest escalation from support.&nbsp; They could even take a bit of time for professional development by doing some reading or experimenting. </span></p><p style="padding: 0px; min-height: 8pt; height: 8pt;">&nbsp;</p><p><span>Having people help with addressing the current bottlenecks for the team keeps the work flowing through the system at a more reliable rate, and reduces the amount of context switching going on because there simply won't be so many work items in play at any one time.&nbsp; It also reduces the cycle time time for items in the system, which means that the work is fresher in people's mind so that things like bugfixing and any rework from feedback are done much more efficiently.</span></p><p style="padding: 0px; min-height: 8pt; height: 8pt;">&nbsp;</p><p><span>The more subtle benefit that this brings to the team is to bring the 'whole team together'.&nbsp; It's no longer "someone else's problem" if they're overburdened.&nbsp; It encourages teamwork and collaboration, and puts the focus on 'finished' to the end of the system (ready for production), rather than just finishing <em>my</em> tasks.</span></p><p style="padding: 0px; min-height: 8pt; height: 8pt;">&nbsp;</p><p><span>These rules could be put into place by simple declaration of policy (another email from the manager), or implementing some sort of rules in your task tracking system, but the use of very visual mechanisms like a story board can be very helpful in not only enforcing the rules, but making sense of them for the team - they can 'see' that the test team is overburdened, so the decision to go and help them out becomes a natural decision that doesn't require top-down direction.&nbsp; Jeff's article above has some good examples of how story boards can be used for this.&nbsp; For distributed teams, that story board may need to become a dashboard on your team's wiki, or you could experiment with tools like</span> <a rel="external" class="jive-link-external-small" href="http://www.cardmeeting.com">cardmeeting.com</a><span>.</span></p><p style="padding: 0px; min-height: 8pt; height: 8pt;">&nbsp;</p><p><span>There are a number of variations on this theme that can also be useful - minimum size in certain queues, and maximum sizes for any one person.&nbsp; Remember when experimenting with things like this to always do a retrospective with your team at the end of the iteration to get feedback and make decisions about improvements.</span></p><p style="padding: 0px; min-height: 8pt; height: 8pt;">&nbsp;</p><p><span>I know this is a pretty light treatment on the subject, but hopefully this has introduced the concept well enough that you're encouraged to do a bit more research on your own and dream about how this might help your team work together more efficiently.</span></p><p style="padding: 0px; min-height: 8pt; height: 8pt;">&nbsp;</p><p><span>Cheers,</span></p><p style="padding: 0px; min-height: 8pt; height: 8pt;">&nbsp;</p><p><span>Allan</span></p></div><!-- [DocumentBodyEnd:27c4c4e3-e346-45de-9730-e1b6d15aa678] --></div><!-- [DocumentBodyEnd:9b8f4ed3-153f-4f5e-bd3c-0cb0bfe72a03] --> ]]></description>
			<guid isPermaLink="false">38@http://allannienhuis.com/pivot/</guid>
			<category>default</category>
			<pubDate>Wed, 27 May 2009 09:45:00 -0700</pubDate>
		</item>
		
		
		
		<item>
			<title>Quality &amp; Broken Windows</title>
			<link>http://www.allannienhuis.com/archive/2009/05/26/Quality__Broken_Windows</link>
			<comments>http://www.allannienhuis.com/archive/2009/05/26/Quality__Broken_Windows#comm</comments>
                        <description><![CDATA[ <!-- [DocumentBodyStart:e4987c22-e0e8-4334-9e5f-450166141246] -->
<div class="jive-rendered-content">
<p>
The authors of the <a rel="external" href="http://www.pragprog.com/titles/tpp/the-pragmatic-programmer">Pragmatic Programmer</a> (great book btw, highly recommended) have a lot of insights into the craft of software development, but in my opinion one of the most powerful ideas is that &quot;living with broken windows&quot; drives quality downward in a depressing spiral of entropy.&nbsp; Well, they put it a lot more eloquently than that, but the idea is that when you're working in a codebase that's littered with problems, bugs, sloppiness, etc, you and your team are much more likely to do sloppy work.&nbsp; Your standards are lowered by the sheer weight of the code around you, in spite of your best intentions and even explicit attempts to do high-quality work.&nbsp; This is a great argument for continued refactoring of existing code, even if that code is more or less functional.&nbsp; It can affect the quality of new code just by its presence in the same codebase.&nbsp; It's like a poison, or at least a bad smelling swamp gas...
</p>
<p>
I won't attempt to elaborate much more on the concept - <a rel="external" href="http://www.pragprog.com/the-pragmatic-programmer/extracts/software-entropy">this article</a> explains it much better than I'm likely to.&nbsp; Go ahead and use up some of your daily or weekly geek reading time on that article - it's time well spent.
</p>
<p>
What's <strong>your</strong> experience like?&nbsp; Have trouble keeping high standards when working on crappy legacy code that someone-who's-no-longer-working-here-for-a-good-reason wrote?&nbsp; Wish you could rewrite that whole module or function from scratch but just don't think you have the time?&nbsp; Can't convince your Dev or Product manager to let you have the time to refactor that painful and buggy sub-system?&nbsp; Or, have you been able to clean up parts of your codebase with positive results? Was it worth it? Do you think it really makes much of a difference?&nbsp; Or, can you manage to keep your work up to all the awesome standards that you have in spite of the muck that you're wading around in?
</p>
<p>
What do <strong>YOU</strong> think? 
</p>
<p>
P.S. Don't take this as suggesting that all of the legacy code is crap - it's not.&nbsp; There's a lot of really great code out there, I know.&nbsp; And you don't need to look only at 'legacy' code to find sloppiness either.&nbsp; These are big generalizations, but I think they're useful ones that apply to much more than just code.
</p>
</div>
<!-- [DocumentBodyEnd:e4987c22-e0e8-4334-9e5f-450166141246] --> ]]></description>
			<guid isPermaLink="false">37@http://allannienhuis.com/pivot/</guid>
			<category>Technology</category>
			<pubDate>Tue, 26 May 2009 08:38:00 -0700</pubDate>
		</item>
		
		
		
		<item>
			<title>ELMAH - an Amazing asp.net error logging monitoring tool</title>
			<link>http://www.allannienhuis.com/archive/2009/04/24/ELMAH_-_an_Amazing_aspnet_erro</link>
			<comments>http://www.allannienhuis.com/archive/2009/04/24/ELMAH_-_an_Amazing_aspnet_erro#comm</comments>
                        <description><![CDATA[ <p>
I saw this referenced on Jeff Atwood's blog a little while ago and meant to pass it along to a few folks, and now I see that Scott Hanselman has just blogged about it as well.  <a rel="external" href="http://www.hanselman.com/blog/ELMAHErrorLoggingModulesAndHandlersForASPNETAndMVCToo.aspx">Scott's article</a> is probably the best place to start. for more detailed information (I guess other than the project's <a rel="external" href="http://code.google.com/p/elmah/">site</a>)</p><p>
Here's the blurb from <a rel="external" href="http://code.google.com/p/elmah/">ELMAH'S site</a>: &nbsp; 
</p>
<blockquote style="border-style: none; margin: 0px 0px 0px 40px; padding: 0px">
	&nbsp;<span class="Apple-style-span" style="font-family: arial; line-height: normal">ELMAH
	(Error Logging Modules and Handlers) is an application-wide error
	logging facility that is completely pluggable. It can be dynamically
	added to a running&nbsp;<a href="http://www.asp.net/" rel="nofollow external">ASP.NET</a>&nbsp;web application, or even all ASP.NET web applications on a machine, without any need for re-compilation or re-deployment.</span><br />
	<span class="Apple-style-span" style="font-family: arial; line-height: normal">Once
	ELMAH has been dropped into a running web application and configured
	appropriately, you get the following facilites without changing a
	single line of your code</span>
</blockquote>
<span class="Apple-style-span" style="font-family: arial; line-height: normal">
<ul style="max-width: 65em; padding-left: 40px">
	<li>
	<ul style="max-width: 65em; padding-left: 40px">
		<li>Logging of nearly all unhandled exceptions.</li>
		<li>A web page to remotely view the entire log of recoded exceptions.</li>
		<li>A web page to remotely view the full details of any one logged exception.</li>
		<li>In many cases, you can review the original&nbsp;<a href="http://en.wikipedia.org/wiki/Yellow_Screen_of_Death#ASP.NET" rel="nofollow external">yellow screen of death</a>&nbsp;that ASP.NET generated for a given exception, even with&nbsp;customErrors&nbsp;mode turned off.</li>
		<li>An e-mail notification of each error at the time it occurs.</li>
		<li>An RSS feed of the last 15 errors from the log.</li>
		<li>A number of backing storage implementations for the log, including in-memory,&nbsp;<a href="http://www.microsoft.com/sql/" rel="nofollow external">Microsoft SQL Server</a>&nbsp;and several&nbsp;<a href="http://groups.google.com/group/elmah/files" rel="nofollow external">contributed by the community</a>.</li>
	</ul>
	</li>
</ul>
</span>
<p>
I
don't know about you, but this is very exciting for me - exactly the
type of thing that I've been encouraging folks to somehow get onto
their development schedules. Things like this help drive quality to the
next level by not only giving you tools to diagnose problems better,
they increase the <strong>visibility</strong> of problems by orders of magnitude. No
longer are errors hidden away in some error log on the server which
isn't easily accessed by the average dev. RSS feeds of the latest error
reports to drop on your iGoogle homepage! That's the bomb!&nbsp; 
</p>
<p>
As with
anything like this, be careful what you ask for, because you could
easily be innundated with error reports to the point where you may have
a hard time absorbing the information. But its a SUPER motivator to fix
those seemingly benign issues that wind up generating the bulk of your
exceptions...&nbsp; 
</p>
<p>
I'd love to hear about anyone's experience with this or
similar tools, or if it inspires you to brew up something similar for
your other (non .net) projects.</p> ]]></description>
			<guid isPermaLink="false">36@http://allannienhuis.com/pivot/</guid>
			<category>Technology</category>
			<pubDate>Fri, 24 Apr 2009 14:35:00 -0700</pubDate>
		</item>
		
		
		
		<item>
			<title>Making sense of design patterns, best practices, etc</title>
			<link>http://www.allannienhuis.com/archive/2009/02/13/Making_sense_of_design_pattern</link>
			<comments>http://www.allannienhuis.com/archive/2009/02/13/Making_sense_of_design_pattern#comm</comments>
                        <description><![CDATA[ <p>
I read a couple of posts the other day from Jeff Attwod (<a rel="external" href="http://www.codinghorror.com/blog/archives/001225.html">The Ferengi Programmer</a>)&nbsp;and Rob Connery (<a rel="external" href="http://blog.wekeroad.com/blog/patterns-purists-and-sinkholes/">Patterns, Purists, and Sinkholes</a>) that were a little more thought provoking than average.&nbsp; They're both talking about how to make sense of all of the 'best practice' advice thats out there, how to know when you're allowed to break the rules, and the various troubles that you can get into on both sides of that coin.&nbsp; Certainly you can quickly get lost when using the design pattern hammer for every problem and often you just have to 'get things done, NOW!'.&nbsp; But obviously those best practices and principles (like&nbsp;Bob Martin's&nbsp; <a rel="external" href="http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod">SOLID principles</a>), have a ton of value and really can't be ignored by any professional developer.&nbsp; So how do you know when to break the rules?</p><p>
I really liked the analogy given by a commenter (James) on Rob's article, drawing on his experience as an electrician - specifically as an electrician's apprentice (I can relate - that's my background).&nbsp; The point that I&nbsp;took home&nbsp;was - rules can only get you so far, but it's the rules and guidlines that the 'newbies' learn in their first few years, combined with the experiences lived through in those years that give people the knowledge and widsom to deal with things that the rules don't cover or when it's 'safe' to compromise rule X in order to achieve the goal at hand.
</p>
<p>
So, think twice when faced with the common choice between doing it right or doing it quick.&nbsp; Are you really qualified to decide when to cut corners?&nbsp; 
</p>
<p>
I'm not ashamed to admit that I love to watch Mike Holmes' <a rel="external" href="http://www.holmesonhomes.com/makeitright/index.php">'Holmes on Homes'</a> show on the Home and Garden network.&nbsp; His motto is: <strong><em>&quot;If you're going to do it - do it right the first time&quot;.</em></strong>&nbsp; His show is all about how much effort and waste and heartache happens when contractors cut corners (too much).&nbsp; His genuine passion for doing things right really resonates with me.
</p>
<p>
I stumbled across another quote the other day that seems to fit in this context.&nbsp; John Wooden is a famous college basketball coach of the 60's and 70's, and in his time was well known for a few sage sayings.&nbsp; <strong><em>&quot;Be quick, but don't hurry&quot;</em></strong> really captures the great balance we struggle with in software development - the need to deliver value (working software) quickly, but with sufficient quality that we won't regret later.&nbsp; &quot;Doing it right doesn't&quot; doesn't have to mean &quot;Doing it slow&quot;, all the time.&nbsp; It certainly shouldn't be an excuse for spinning your wheels or not making good progress on your projects.
</p>
<p>
As a manager of software developers, I would WAY rather deal with the problem of &quot;it's taking too long&quot; rather than &quot;the quality sucks and our customers are coming after us with pitchforks and flaming torches!&quot;.&nbsp; I'm sure&nbsp;everyone would agree that rushing, cutting corners, and dealing with the resulting pain will take longer to get to the end of the job than taking that bit of extra time to do it 'the right way'.&nbsp; But how do you deal with the crushing realities of&nbsp;hard deadlines and customer commitments (made by you or others)?&nbsp; What if you just don't have the time to do it the way you want to?&nbsp; 
</p>
<p>
The challenge of course is trying to figure out where the line is - how far down the path of 'doing it right' do we need to go in this case?&nbsp; Do I really need to do those unit tests?&nbsp; How much of the code is worth getting reviewed?&nbsp; How much should be done by pairs of devs? All of it? really?&nbsp; Do we need an interface in this case? Is a dependency injection framework&nbsp;overkill for this? Will it take the new folks too long to understand the system if I do it that way? How much regression testing should we do? Do we need usabilty testing?
</p>
<p>
I don't have answers for those questions because obviously 'it depends'. I can say that I very much default to the answer that you should really really try to 'do it right the first time', and only make decisions to cut those corners in the light of the experience and wisdom of the real journeymen on your team.&nbsp; No rule can be a replacement for the life lessons learned by those with the battle-scars, but those rules are a darned good starting place for all of the conversations.
</p>
<p>
In conclusion, I'd like to leave you with another set of rules. :) :)&nbsp; These ones are by&nbsp;Eric S Raymond, and can be found here: <a rel="external" href="http://catb.org/~esr/writings/taoup/html/ch01s06.html">http://catb.org/~esr/writings/taoup/html/ch01s06.html</a>&nbsp;&nbsp;They are the distilled wisdom of many of the developers who wrote the Unix operating system -&nbsp;some of the real&nbsp;'elders' and journeymen of our industry.&nbsp;
</p>
<ol>
	<li>
	<p>
	Rule of Modularity: Write simple parts connected by clean interfaces.
	</p>
	</li>
	<li>
	<p>
	Rule of Clarity: Clarity is better than cleverness.
	</p>
	</li>
	<li>
	<p>
	Rule of Composition: Design programs to be connected to other programs.
	</p>
	</li>
	<li>
	<p>
	Rule of Separation: Separate policy from mechanism; separate interfaces from engines.
	</p>
	</li>
	<li>
	<p>
	Rule of Simplicity: Design for simplicity; add complexity only where you must.
	</p>
	</li>
	<li>
	<p>
	Rule of Parsimony: Write a big program only when it is clear by demonstration that nothing else will do.
	</p>
	</li>
	<li>
	<p>
	Rule of Transparency: Design for visibility to make inspection and debugging easier.
	</p>
	</li>
	<li>
	<p>
	Rule of Robustness: Robustness is the child of transparency and simplicity.
	</p>
	</li>
	<li>
	<p>
	Rule of Representation: Fold knowledge into data so program logic can be stupid and robust.
	</p>
	</li>
	<li>
	<p>
	Rule of Least Surprise: In interface design, always do the least surprising thing.
	</p>
	</li>
	<li>
	<p>
	Rule of Silence: When a program has nothing surprising to say, it should say nothing.
	</p>
	</li>
	<li>
	<p>
	Rule of Repair: When you must fail, fail noisily and as soon as possible.
	</p>
	</li>
	<li>
	<p>
	Rule of Economy: Programmer time is expensive; conserve it in preference to machine time.
	</p>
	</li>
	<li>
	<p>
	Rule of Generation: Avoid hand-hacking; write programs to write programs when you can.
	</p>
	</li>
	<li>
	<p>
	Rule of Optimization: Prototype before polishing. Get it working before you optimize it.
	</p>
	</li>
	<li>
	<p>
	Rule of Diversity: Distrust all claims for &ldquo;one true way&rdquo;.
	</p>
	</li>
	<li>
	<p>
	Rule of Extensibility: Design for the future, because it will be here sooner than you think.
	</p>
	</li>
</ol>
<p>
&nbsp;Cheers, 
</p>
<p>
Allan</p> ]]></description>
			<guid isPermaLink="false">34@http://allannienhuis.com/pivot/</guid>
			<category>Technology</category>
			<pubDate>Fri, 13 Feb 2009 10:48:00 -0700</pubDate>
		</item>
		
		
		
		<item>
			<title>MbUnit Combinatorial Tests</title>
			<link>http://www.allannienhuis.com/archive/2008/11/03/MbUnit_Combinatorial_Tests</link>
			<comments>http://www.allannienhuis.com/archive/2008/11/03/MbUnit_Combinatorial_Tests#comm</comments>
                        <description><![CDATA[ <p>
<a rel="external" href="http://www.mbunit.com/" title="MbUnit">MbUnit</a> rocks. Perhaps other unit test tools for .net rock as well, but right now I'm really happy with MbUnit and how easy it is to work with. Plus it has some killer features.&nbsp; I'm really impressed with the combinatorial test. &nbsp;I have no idea whether other xUnit frameworks have this feature, but in MbUnit it's really easy to impliment, and really powerful.&nbsp; Everyone doing unit testing should understand the possibilites of the combinatorial test, to improve the real-world coverage of thier test suites, regardless of the platform and toolsets you're working with.</p><!-- code formatted by http://manoli.net/csharpformat/ --><span class="lnum">
<p>
<strong><u>The Problem:&nbsp;real-world test coverage</u></strong>&nbsp; 
</p>
<p>
A common metric for automated testing is something called 'code coverage', which basically counts the number of lines of code that your tests excercise to tell you how much of your system you have under test.&nbsp; The problem with this (and any metric that relies on LOC metrics) is that it doesn't take into consideration the various VALUES that pass through your code, particularly data entered by users, and environmental factors (like current date/time).&nbsp; While an exceptional value might only cause your code to pass through one additional line of code (perhaps your error handler), there could be many opportunites for your code to experience that exceptional value. Even more troubling, it is often a specific combination of two or more values that cause problems and undesired consequences. 
</p>
<p>
Most of the time,&nbsp;testers&nbsp;and developers&nbsp;will try to deal with this situation by running the same type of test with various inputs.&nbsp; Sometimes this can be done with the combinatorial test's 'little brother' called the RowTest.&nbsp; With a row test, the same test is run multiple times with values that the tester/developer will specify in a number of rows.&nbsp; Kind of like grabbing your inputs from an excel spreadsheet, but keeping your test values right in the test source code.&nbsp; While this is very useful, it still relies on someone to provide all of the combinations.&nbsp; Not only is this time consuming, it is likely that some combinations will be missed.&nbsp; This is where the combinatorial test comes in. 
</p>
<p>
<strong><u>The Solution: Combinatorial Tests</u></strong> 
</p>
<p>
With combinatorial tests, the testing framework determines all of the combinations from various sets of inputs.&nbsp; This isn't a particularly difficult thing for the framework to calculate - it's simply the cross-product of the sets of inputs.&nbsp; This is what computers are good at, so why should us mere humans try to do something our computers are so good at :).&nbsp; MbUnit provides a fairly simple way of supplying those sets of inputs and marking up your tests to use those inputs.&nbsp; MbUnit takes care of the rest.&nbsp; This saves a TREMENDOUS amout of time, and improves your real-world test coverage.&nbsp; 
</p>
<p>
MbUnit supplies a few simple&nbsp;attributes to identify the sets of values and the tests which will consume them.&nbsp; They are: 'Factory', 'CombinatorialTest', and 'UsingFactories'.&nbsp; I won't get into the various flavors or specific features of each of these attributes - you can get that information from MbUnit documentation, or Google.&nbsp; 
</p>
<p>
The &quot;Factory&quot; attribute marks methods which define iEnumerable sets of values.&nbsp; They could be simple native data types, but they can also be sets of complex objects.&nbsp; This can be particularly useful if you want to test sets of concrete types that impliment the same interface, or test subclassed instances of a base type.&nbsp; In the code example below, I'm only using simple string and decimal types, but the pattern is the same. 
</p>
<p class="alt">
The &quot;CombinatorialTest&quot; attribute simply tells MbUnit to generate multiple tests from this single method, using&nbsp;the cross-product of the Factories specified. 
</p>
<p class="alt">
The &quot;UsingFactories&quot; attribute is applied to parameters of the combinatorial test, indicating that this parameter's values will be supplied by the specified factory method. 
</p>
<p class="alt">
<strong><u>The Sample</u></strong> 
</p>
<p class="alt">
In the code sample below, I will only show you&nbsp;a very basic implimentation.&nbsp;&nbsp;This example tests a fake 'payment authorization' system, which simplisticly takes credit card types and values to authorize. The sample only enforces one business rule:&nbsp;amounts &lt;= 0 are not authorized.&nbsp;&nbsp;The sample could be extended to cover additional business rules which actually rely on combinations of both sets of inputs (perhaps Amex really does allow&nbsp;$0 authorizations?), but I didn't want to&nbsp;make the sample&nbsp;any more complex; I'll leave that excercise for you. :)&nbsp; I thought this sample would evoke more real-world ideas for you&nbsp;than the very generic 'x,y,z' type samples I've been able to find.&nbsp; 
</p>
<p class="alt">
I've also shown a way to categorize your sets of inputs into groups which help organize your tests such that they all actually pass.&nbsp; In this case, I've grouped valid and invalid data seperately, allowing me to have two tests with different assertions.&nbsp; I&nbsp;used VB.net for my sample as most of the samples online I've been able to find are done with C#, so I thought this might add some marginal incremental value to the existing blog posts on this topic. 
</p>
</span>
<div class="csharpcode">
<pre class="alt">
<span class="lnum"> 1:  </span><span class="kwrd">Imports</span> MbUnit.Framework
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">   2:  </span>&nbsp;
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">   3:  </span>&lt;TestFixture()&gt; _
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">   4:  </span><span class="kwrd">Public</span> <span class="kwrd">Class</span> SampleCombinatorialTests
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">   5:  </span>&nbsp;
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">   6:  </span>    &lt;CombinatorialTest()&gt; _
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">   7:  </span>    <span class="kwrd">Public</span> <span class="kwrd">Sub</span> CanAuthorizeValidAmounts( _
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">   8:  </span>        &lt;UsingFactories(<span class="str">&quot;CCType&quot;</span>)&gt; <span class="kwrd">ByVal</span> CCType <span class="kwrd">As</span> <span class="kwrd">String</span>, _
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">   9:  </span>        &lt;UsingFactories(<span class="str">&quot;ValidAmount&quot;</span>)&gt; <span class="kwrd">ByVal</span> amount <span class="kwrd">As</span> <span class="kwrd">Decimal</span>)
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">  10:  </span>&nbsp;
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">  11:  </span>        <span class="kwrd">Dim</span> result = Payment.Authorize(CCType, amount)
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">  12:  </span>        Assert.AreEqual(<span class="str">&quot;success&quot;</span>, result)
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">  13:  </span>&nbsp;
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">  14:  </span>    <span class="kwrd">End</span> <span class="kwrd">Sub</span>
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">  15:  </span>&nbsp;
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">  16:  </span>    &lt;CombinatorialTest()&gt; _
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">  17:  </span>    <span class="kwrd">Public</span> <span class="kwrd">Sub</span> CannotAuthorizeInvalidAmounts( _
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">  18:  </span>        &lt;UsingFactories(<span class="str">&quot;CCType&quot;</span>)&gt; <span class="kwrd">ByVal</span> CCType <span class="kwrd">As</span> <span class="kwrd">String</span>, _
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">  19:  </span>        &lt;UsingFactories(<span class="str">&quot;InvalidAmount&quot;</span>)&gt; <span class="kwrd">ByVal</span> amount <span class="kwrd">As</span> <span class="kwrd">Decimal</span>)
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">  20:  </span>&nbsp;
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">  21:  </span>        <span class="kwrd">Dim</span> result = Payment.Authorize(CCType, amount)
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">  22:  </span>        Assert.AreEqual(<span class="str">&quot;fail&quot;</span>, result)
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">  23:  </span>    <span class="kwrd">End</span> <span class="kwrd">Sub</span>
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">  24:  </span>&nbsp;
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">  25:  </span>    &lt;Factory()&gt; _
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">  26:  </span>    <span class="kwrd">Public</span> <span class="kwrd">Function</span> CCType() <span class="kwrd">As</span> List(Of <span class="kwrd">String</span>)
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">  27:  </span>        <span class="kwrd">Dim</span> list = <span class="kwrd">New</span> List(Of <span class="kwrd">String</span>)
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">  28:  </span>        list.Add(<span class="str">&quot;Visa&quot;</span>)
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">  29:  </span>        list.Add(<span class="str">&quot;MasterCard&quot;</span>)
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">  30:  </span>        list.Add(<span class="str">&quot;American Express&quot;</span>)
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">  31:  </span>        list.Add(<span class="str">&quot;DiscoverCard&quot;</span>)
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">  32:  </span>        <span class="kwrd">Return</span> list
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">  33:  </span>    <span class="kwrd">End</span> <span class="kwrd">Function</span>
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">  34:  </span>&nbsp;
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">  35:  </span>    &lt;Factory()&gt; _
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">  36:  </span>    <span class="kwrd">Public</span> <span class="kwrd">Function</span> ValidAmount() <span class="kwrd">As</span> List(Of <span class="kwrd">Decimal</span>)
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">  37:  </span>        <span class="kwrd">Dim</span> list = <span class="kwrd">New</span> List(Of <span class="kwrd">Decimal</span>)
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">  38:  </span>        list.Add(100.0)
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">  39:  </span>        list.Add(<span class="kwrd">Decimal</span>.MaxValue)
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">  40:  </span>        list.Add(0.01)
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">  41:  </span>        <span class="kwrd">Return</span> list
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">  42:  </span>    <span class="kwrd">End</span> <span class="kwrd">Function</span>
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">  43:  </span>&nbsp;
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">  44:  </span>    &lt;Factory()&gt; _
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">  45:  </span>    <span class="kwrd">Public</span> <span class="kwrd">Function</span> InvalidAmount() <span class="kwrd">As</span> List(Of <span class="kwrd">Decimal</span>)
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">  46:  </span>        <span class="kwrd">Dim</span> list = <span class="kwrd">New</span> List(Of <span class="kwrd">Decimal</span>)
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">  47:  </span>        list.Add(0.0)
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">  48:  </span>        list.Add(<span class="kwrd">Decimal</span>.MinValue)
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">  49:  </span>        list.Add(-0.01)
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">  50:  </span>        <span class="kwrd">Return</span> list
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">  51:  </span>    <span class="kwrd">End</span> <span class="kwrd">Function</span>
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">  52:  </span>&nbsp;
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">  53:  </span>&nbsp;
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">  54:  </span><span class="kwrd">End</span> <span class="kwrd">Class</span>
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">  55:  </span>&nbsp;
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">  56:  </span><span class="kwrd">Public</span> <span class="kwrd">Class</span> Payment
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">  57:  </span>    <span class="kwrd">Public</span> <span class="kwrd">Shared</span> <span class="kwrd">Function</span> Authorize(<span class="kwrd">ByVal</span> CCType <span class="kwrd">As</span> <span class="kwrd">String</span>, <span class="kwrd">ByVal</span> amount <span class="kwrd">As</span> <span class="kwrd">Decimal</span>) <span class="kwrd">As</span> <span class="kwrd">String</span>
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">  58:  </span>        Debug.Print(CCType &amp; <span class="str">&quot;, &quot;</span> &amp; amount)
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">  59:  </span>        <span class="kwrd">If</span> amount &lt;= 0 <span class="kwrd">Then</span> <span class="kwrd">Return</span> <span class="str">&quot;fail&quot;</span>
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">  60:  </span>        <span class="kwrd">Return</span> <span class="str">&quot;success&quot;</span>
</pre>
</div>
<div class="csharpcode">
<pre class="alt">
<span class="lnum">  61:  </span>    <span class="kwrd">End</span> <span class="kwrd">Function</span>
</pre>
</div>
<div class="csharpcode">
<pre>
<span class="lnum">  62:  </span><span class="kwrd">End</span> <span class="kwrd">Class</span>
</pre>
</div>
<p>
<strong><u>The Results</u></strong>&nbsp; 
</p>
<p>
And here's the resulting MbUnit test suite from these few lines of code. 
</p>
<p style="text-align:center;"><img src="http://www.allannienhuis.com/images/combinatorialtests.jpg" style="border:0px solid" title="" alt="" class="pivot-image" /></p>

<p>
<strong><u>Summary</u></strong> 
</p>
<p>
I hope this post has helped you to see just how simple it is to use MbUnit to harness the power of Combinatorial testing to&nbsp;improve real-world test scenario coverage in your applications.</p> ]]></description>
			<guid isPermaLink="false">33@http://allannienhuis.com/pivot/</guid>
			<category>Technology</category>
			<pubDate>Mon, 03 Nov 2008 08:33:00 -0700</pubDate>
		</item>
		
		
		
		<item>
			<title>very cool presentation on mono</title>
			<link>http://www.allannienhuis.com/archive/2008/11/01/very_cool_presentation_on_mono</link>
			<comments>http://www.allannienhuis.com/archive/2008/11/01/very_cool_presentation_on_mono#comm</comments>
                        <description><![CDATA[ <div>
<a rel="external" href="http://channel9.msdn.com/pdc2008/PC54/">http://channel9.msdn.com/pdc2008/PC54/</a>&nbsp; 
</div>
<div>
Its long, but really very cool.&nbsp; This guy is the lead for the mono project, which is an open source implimentation of .net.&nbsp; Microsoft actually gave him a slot at their biggest developer conference of the year.&nbsp; 
</div>
<div>
One of the really cool bits is something he shows in the middle of the presentation where he talks about the issues that game developers have with the speed of scripting AI in their apps (typically lua).&nbsp; They can now imbed mono into their apps, and get the features of a fast-performing strongly typed language (c#), but still be relatively 'safe' (memory managment, etc).&nbsp; He showed a very cool demo of a game construction kit/tool called Unity (i think) which is written in mono.&nbsp; 
</div>
<div>
Anyways, I thought it was interesting, and if you want to immerse yourself in some pretty technical geeky stuff for a while, it's worth watching. 
</div> ]]></description>
			<guid isPermaLink="false">32@http://allannienhuis.com/pivot/</guid>
			<category>Technology</category>
			<pubDate>Sat, 01 Nov 2008 14:12:00 -0700</pubDate>
		</item>
		
		
		
		<item>
			<title>cool windows utility</title>
			<link>http://www.allannienhuis.com/archive/2008/10/21/cool_windows_utility</link>
			<comments>http://www.allannienhuis.com/archive/2008/10/21/cool_windows_utility#comm</comments>
                        <description><![CDATA[ <p>
<a rel="external" href="http://www.gtopala.com/">http://www.gtopala.com/</a>
</p>
<p>
SIW - System information for Windows.&nbsp; From their website:
</p>
<blockquote>
	<p>
	&nbsp; SIW is an advanced System Information for Windows&nbsp; tool that gathers detailed information about your system properties and settings and displays it in an extremely comprehensible manner.
	</p>
</blockquote>
<p>
I used it today to get ram specs on a server rather than shutting the server down and physically inspecting it.&nbsp; Very cool tool:
</p>
<p>
<span style="font-size: 11pt; font-family: 'Calibri','sans-serif'"><img src="http://www.allannienhuis.com/images/siw_copy1.jpg" style="float:left;margin-right:10px;margin-bottom:5px;border:0px solid" title="" alt="" class="pivot-image" /></span></p> ]]></description>
			<guid isPermaLink="false">31@http://allannienhuis.com/pivot/</guid>
			<category>default</category>
			<pubDate>Tue, 21 Oct 2008 12:57:00 -0700</pubDate>
		</item>
		
		
		
		<item>
			<title>About Me</title>
			<link>http://www.allannienhuis.com/archive/2008/03/23/About_Me</link>
			<comments>http://www.allannienhuis.com/archive/2008/03/23/About_Me#comm</comments>
                        <description><![CDATA[ <p>
Hi, I'm Allan Nienhuis.&nbsp; At work I help software development managers keep their teams productive and happy at the <a rel="external" href="http://www.activenetwork.com">Active Network</a> (my official title is 'Director,&nbsp;Product Development').&nbsp; I also help <a rel="external" href="http://www.theactivenetwork.com.cn/">my team</a> in&nbsp;<a rel="external" href="http://en.wikipedia.org/wiki/Xi'an">Xian, China</a> grow at an incredible pace.&nbsp; 
</p>
<p>
I'm&nbsp;still amazed that my&nbsp;wife Shelley actually married me&nbsp;(26th anniversary this year!).&nbsp; Both of our children (daughter Danielle,&nbsp;son Noel) have&nbsp;moved out of the house kind of recently so we're experiencing the 'empty nest' thing first hand.&nbsp; We're now living on the beatiful waterfront of Pender Harbour, which is a bit north of Vancouver, BC in an area called 'The Sunshine Coast', although we lived in Abbotsford, BC for over 20 years.&nbsp; You can find some pictures of our place <a rel="external" href="http://www.allannienhuis.com/albums/farringtoncove/">here</a>. Our Christian faith is imporant to us, and for many years we've supported and encouraged others to support several hands-on ministries - <a rel="external" href="http://www.onemileclinic.org">www.onemileclinic.org</a>, <a rel="external" href="http://www.partnersforhaiti.org">www.partnersforhaiti.org</a>, and the work of Norm and Jen Weir serving people in remote communities in BC.&nbsp; 
</p>
<p>
I suppose my first post on why I bothered putting up this blog in the first place will probably get kicked off the front page after a while, so I'll put a link to it <a rel="external" href="/archive/2008/03/29/Welcome">here</a>.</p> ]]></description>
			<guid isPermaLink="false">12@http://allannienhuis.com/pivot/</guid>
			<category>about</category>
			<pubDate>Sun, 23 Mar 2008 14:36:00 -0700</pubDate>
		</item>
		
		
		
	</channel>
</rss>
