<?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-4988670965309258707</id><updated>2011-07-08T01:46:44.782+02:00</updated><category term='silly'/><category term='craftmanship'/><category term='users'/><category term='theory'/><category term='habit'/><category term='UnitTests'/><category term='MoSCoW'/><category term='bug'/><category term='bugs'/><category term='cheese'/><category term='conspiracy'/><category term='mock'/><category term='RED'/><category term='done'/><category term='F#'/><category term='pizza'/><category term='C#'/><category term='IDisposable'/><category term='TypeMock'/><category term='agile'/><category term='build'/><category term='planning'/><category term='BDD'/><category term='crap'/><category term='VS2010'/><category term='quality'/><category term='fix'/><category term='version control'/><category term='code'/><category term='testing'/><category term='business value'/><category term='story points'/><category term='comments'/><category term='stupid'/><category term='good intentions'/><category term='clean'/><category term='estimation'/><title type='text'>Torbjörn's Random Ramblings</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>29</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-5947520316021158415</id><published>2010-07-14T15:20:00.003+02:00</published><updated>2010-07-14T16:00:16.989+02:00</updated><title type='text'>Introducing Cone</title><content type='html'>&lt;a href='http://NUnit.org'&gt;NUnit&lt;/a&gt; is one of the most widely used and mature .Net Unit testing frameworks out there. Anyone doing TDD on .Net has heard of and probably used it. I've been tempted to use other excellent alternatives like &lt;a href='http://www.mbunit.com/'&gt;MbUnit&lt;/a&gt; and someone once forced me to use &lt;a href='http://en.wikipedia.org/wiki/Visual_Studio_Unit_Testing_Framework'&gt;Visual Studio Unit Testing Framework&lt;/a&gt;, the only good thing about that one is that the name tells you a lot about the experience. It's long, it's integrated, it's going the opposite direction of everyone else.
&lt;p&gt;But for one reason or another I always come back to by old byddy NUnit. It's probably the familiarity and that the features that once did draw me to MbUnit like parameterized/data-driven tests are now available with NUnit. 
&lt;/p&gt;&lt;p&gt;
All that being said, there's some stuff that always kinda irked me with NUnit, and most of the apply to the others to.
&lt;ol&gt;
  &lt;li&gt;Test cases are named after their fixture, not after the thing they're verifying.&lt;/li&gt;
  &lt;li&gt;Nesting fixtures to provide context and logical grouping don't really work.&lt;/li&gt;
  &lt;li&gt;Test names tend to duplicate part of the code since assertion messages tells me the values, but not how they were obtained&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;1) Test case names&lt;/h2&gt;
The majority of unit-tests written are either targetting a single class, or targetting that class in some context. Fixture names tend to be akin to "FooTests" or "FooWhenBarTests" and are dutifully rendered as such often including a namespace with "Tests" in it. Quite typically it looks like this when looking at a single test case&lt;br&gt;
&lt;pre&gt;Acme.Tests.BowlingTests.Score_should_return_0_for_gutter_game&lt;/pre&gt;&lt;br&gt;
Now that's just plain silly! Because what happens is that for every single such case we go and mentally remap the class under test to "Acme.Bowling", so why not show that instead? Maybe providing some extra context on the side?
&lt;h2&gt;2) Nested Fixtures&lt;/h2&gt;
If you've ever tried to nest fixtures in NUnit to create a logical grouping for tests then you're familiar with testnames like &lt;pre&gt;"Acme.Tests.FooTests+BarTests.oh_my_god"&lt;/pre&gt; oh, these also end up not being nested but as sibling to all your other tests. 
&lt;h2&gt;3) Test Name duplicate assertions, because assertions only gives you the values&lt;/h2&gt;
If you lean to classicist state based testing this happens quite a lot, in order to give enough context to make a failing test immediately obvious you either have to write a custom assert message or add something to your test name, depending on your asserts/test either works, both feels like a hack.  
&lt;/p&gt;&lt;p&gt;Since I'm having a vacation and renovating. I spent a few hours watching the paint dry and hacking a NUnit addin to solve those issues. The result, henceforth called Cone, solves those issues for the majority of cases. The picture below should give you a feel for how it looks and feel. 
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_HeRwgf8wL4c/TD26F3V_AlI/AAAAAAAAADw/_QxousTFfaE/s1600/Cone.Bowling.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 245px;" src="http://2.bp.blogspot.com/_HeRwgf8wL4c/TD26F3V_AlI/AAAAAAAAADw/_QxousTFfaE/s400/Cone.Bowling.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5493751730380145234" /&gt;&lt;/a&gt;

Things worth noting:
&lt;ul&gt;
  &lt;li&gt;Fixture names are derived from the Described type, not from the fixture name&lt;/li&gt;
  &lt;li&gt;Underscores are translated to whitespace to aid scanability&lt;/li&gt;
  &lt;li&gt;The actual failing expression "bowling.Score" is shown in the Assertion message&lt;/li&gt;
&lt;/ul&gt;
My initial experience have been very pleasant, but that could just be me being enamored with my own idea. That's where you come in. Please tell me what you think about the idea, is it worth persuing further and packing up properly and release it?
If so, is there any obvious use cases that you couldn't live without?
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-5947520316021158415?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/5947520316021158415/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2010/07/introducing-cone.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/5947520316021158415'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/5947520316021158415'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2010/07/introducing-cone.html' title='Introducing Cone'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_HeRwgf8wL4c/TD26F3V_AlI/AAAAAAAAADw/_QxousTFfaE/s72-c/Cone.Bowling.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-2583322578240829222</id><published>2010-05-05T08:43:00.002+02:00</published><updated>2010-05-05T08:46:46.746+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='good intentions'/><category scheme='http://www.blogger.com/atom/ns#' term='build'/><category scheme='http://www.blogger.com/atom/ns#' term='stupid'/><title type='text'>The Fallacy of the Ever-Green Build</title><content type='html'>The fallacy of the ever green build is built on top of good intentions and hyperbole.
Let's start with getting some of the preliminaries clear, these behaviors are strictly "not ok"
&lt;ul&gt;
  &lt;li&gt;Checking in code that is known to be broken.
  &lt;/li&gt;&lt;li&gt;Not taking responsibility for fixing the build once broken, by yourself or by asking for help.
  &lt;/li&gt;&lt;li&gt;Not helping a team-mate stuck on how to fix the build.
&lt;/li&gt;&lt;/ul&gt;
Given that these clearly defective behaviors aren't present, and under the assumption that you
have a normally stable build process and a decent enough build machine,
the fastest machine affordable is a good advice.

Then given the commandment "thou shalt never break the build" or "when you break the build God kills a kitten",
most don't respond with enlightenment, they figure out "good" ways to not break the build:
&lt;ul&gt;
  &lt;li&gt;Writing fewer tests, tests not present never breaks the build
    &lt;ul&gt;&lt;li&gt;prime example is not verifying behavior of common components or leaving them underspecified.&lt;/li&gt;&lt;/ul&gt;
  &lt;/li&gt;&lt;li&gt;Delaying checkins far longer than necessary "to make sure", waste full since it squanders time that could have been used for better things
  &lt;/li&gt;&lt;li&gt;Not working, no work = no code = no broken build.
&lt;/li&gt;&lt;/ul&gt;
If you're using the fastest machine in the building to display a green light, you're not making good use of that investment.
On the other hand, if you use it to find valuable but seldom occurring problems in a way that is less costly than the alternative
then it's a good investment. That basically entails loosing up a bit on the "run every test we got! never break the build" in favor of
"run the fast, high coverage tests most likely to yield sufficient certainty the soundness of your commit". 

There's learning to be had from every build failure, 
the only thing you learn from "green" is that you're probably hiding problems.

Now I'm talking about a small controlled amount of high information build failures, 
missing files and not bothering to spend a couple of minutes to run the tests for the area just changed don't qualify.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-2583322578240829222?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/2583322578240829222/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2010/05/fallacy-of-ever-green-build.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/2583322578240829222'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/2583322578240829222'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2010/05/fallacy-of-ever-green-build.html' title='The Fallacy of the Ever-Green Build'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-5112526140766482641</id><published>2010-01-08T19:31:00.003+01:00</published><updated>2010-01-08T19:34:42.936+01:00</updated><title type='text'>Did I just μBDD in NUnit?</title><content type='html'>&lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Have a look at this picture, what do you see?&lt;/p&gt;  &lt;p&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; margin-left: 0px; border-top: 0px; margin-right: 0px; border-right: 0px" title="uBDD-NUnit" border="0" alt="uBDD-NUnit" src="http://lh6.ggpht.com/_HeRwgf8wL4c/S0d59chhUyI/AAAAAAAAADU/PHg_GiNPBlI/uBDD-NUnit%5B11%5D.png?imgmax=800" width="644" height="360" /&gt;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Yup, that’s the old familiar “no frills we mean business and are professional about our testing” looking NUnit GUI. But have a look at the test names, they look like some dynamic-typing loving hippie wrote them! What are they doing in my NUnit!? &lt;/p&gt;  &lt;p&gt;The answer is, they’re lending a BDD-like Given/When/Then flavor to our old workhorse, in a way that’s fully compatible and complementary to the standard NUnit model. Does it require magic and fairy-dust? Nope not really, just some creative use of the TestCaseDataSource attribute, the test fixture looks like this:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://lh3.ggpht.com/_HeRwgf8wL4c/S0d594e4BXI/AAAAAAAAADY/Nim2w4Qs4cA/s1600-h/uBDD-Fixture%5B9%5D.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: inline; margin-left: 0px; border-top: 0px; margin-right: 0px; border-right: 0px" title="uBDD-Fixture" border="0" alt="uBDD-Fixture" src="http://lh5.ggpht.com/_HeRwgf8wL4c/S0d5-YeQHFI/AAAAAAAAADc/PNJIlHYPFME/uBDD-Fixture_thumb%5B7%5D.png?imgmax=800" width="532" height="484" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;GWT doesn’t always make sense, but when it do it can lead to some really communicative tests. &lt;/p&gt;  &lt;p&gt;If you want the small (~40 lines) source for the Scenario class just leave a comment.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-5112526140766482641?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/5112526140766482641/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2010/01/did-i-just-bdd-in-nunit.html#comment-form' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/5112526140766482641'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/5112526140766482641'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2010/01/did-i-just-bdd-in-nunit.html' title='Did I just μBDD in NUnit?'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh6.ggpht.com/_HeRwgf8wL4c/S0d59chhUyI/AAAAAAAAADU/PHg_GiNPBlI/s72-c/uBDD-NUnit%5B11%5D.png?imgmax=800' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-2804857934994406580</id><published>2009-11-17T22:24:00.004+01:00</published><updated>2009-11-17T22:28:17.558+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='conspiracy'/><category scheme='http://www.blogger.com/atom/ns#' term='silly'/><title type='text'>Visual Resharper</title><content type='html'>I've been using Visual Studio 2010 Beta 2 at home for a while and truly it really rocks. 
But something has been nagging me, there just seems to be so much stuff borrowed from everyones favourite plugin, Resharper. 
And I belive I've found the reason. 
If you take a screenshot of the new logo and reverse the red and blue channels something quite familar appears.
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_HeRwgf8wL4c/SwMVKQJj2rI/AAAAAAAAABg/VqoMeEdOluE/s1600/VisualResharper.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 54px;" src="http://2.bp.blogspot.com/_HeRwgf8wL4c/SwMVKQJj2rI/AAAAAAAAABg/VqoMeEdOluE/s320/VisualResharper.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5405187243652668082" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-2804857934994406580?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/2804857934994406580/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/11/visual-resharper.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/2804857934994406580'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/2804857934994406580'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/11/visual-resharper.html' title='Visual Resharper'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_HeRwgf8wL4c/SwMVKQJj2rI/AAAAAAAAABg/VqoMeEdOluE/s72-c/VisualResharper.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-1806441235245922922</id><published>2009-11-04T13:25:00.002+01:00</published><updated>2009-11-04T13:27:34.801+01:00</updated><title type='text'>How to reset registry and file permissions.</title><content type='html'>If you somehow manage to get into trouble with registry or file permissions and feel that the only sane way out would be to reset them. Here's the magic incantation to put into the black box:
&lt;pre&gt;secedit /configure /cfg %windir%\repair\secsetup.inf /db secsetup.sdb /verbose&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-1806441235245922922?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/1806441235245922922/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/11/how-to-reset-registry-and-file.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/1806441235245922922'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/1806441235245922922'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/11/how-to-reset-registry-and-file.html' title='How to reset registry and file permissions.'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-3680577650908058917</id><published>2009-07-10T09:23:00.004+02:00</published><updated>2009-07-10T11:12:40.454+02:00</updated><title type='text'>Using NUnit with VS2010 Beta and .NET Framework 4.0</title><content type='html'>I've been test driving Visual Studio 2010 Beta recently and it comes with, and defaults to, .NET Framework 4.0, exciting stuff all around until you realize that if you target the 4.0 Framework you end up with this when trying to run your tests.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_HeRwgf8wL4c/SlcCK_m_5gI/AAAAAAAAABQ/LvL7QwhZve4/s1600-h/NUnit-pre-patch.PNG"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 233px;" src="http://4.bp.blogspot.com/_HeRwgf8wL4c/SlcCK_m_5gI/AAAAAAAAABQ/LvL7QwhZve4/s320/NUnit-pre-patch.PNG" border="0" alt=""id="BLOGGER_PHOTO_ID_5356752669677446658" /&gt;&lt;/a&gt;

Let's call this, less than helpful. Some googling turns up one solution, rebuild NUnit from source. Now while that is a viable solution you should never just go for the first solution that enters your mind. After some pondering I came to think of the metadata storage signature defintion present in all .NET Assemblies and how it actually does contain the desired framework version. 
&lt;p&gt;
Using your hexeditor of choice (I like &lt;a href='http://www.chmaas.handshake.de/delphi/freeware/xvi32/xvi32.htm'&gt;XVI32&lt;/a&gt;) simply open "nunit.exe" and search for "v2" it should turn up something like the screenshot below:
&lt;/p&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_HeRwgf8wL4c/SlcCQ_Ek9uI/AAAAAAAAABY/8MfBeIgyN6k/s1600-h/HexEdit-Nunit.png"&gt;&lt;img style="margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_HeRwgf8wL4c/SlcCQ_Ek9uI/AAAAAAAAABY/8MfBeIgyN6k/s320/HexEdit-Nunit.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5356752772612290274" /&gt;&lt;/a&gt;
Notice the "BSJB" just preceding the version string, that's the metadata signature basically telling us we're in the right place. Now change "v2.0.50727" into "v4.0.20506" save and start NUnit. It will now run under the 4.0 framework instead, happily running your tests. 
&lt;p&gt;
Oh, if you think that't both rebuilding from source, and hacking metadata is maybe not really "the right solution (tm)" you could &lt;a href='http://www.cookcomputing.com/blog/archives/000597.html'&gt;just configure it instead.&lt;/a&gt;
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-3680577650908058917?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/3680577650908058917/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/07/using-nunit-with-vs2010-beta-and-net.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/3680577650908058917'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/3680577650908058917'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/07/using-nunit-with-vs2010-beta-and-net.html' title='Using NUnit with VS2010 Beta and .NET Framework 4.0'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_HeRwgf8wL4c/SlcCK_m_5gI/AAAAAAAAABQ/LvL7QwhZve4/s72-c/NUnit-pre-patch.PNG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-6548448701847041390</id><published>2009-07-05T19:22:00.002+02:00</published><updated>2009-07-05T19:42:47.654+02:00</updated><title type='text'>Thinking in context.</title><content type='html'>&lt;p&gt;
There has been som general hubbub about establishing WIP limits in the Kanban community latly, some have gone so far as to claim that it is wasteful. Or more exactly that they are wasteful since if you're mindfull you can see the same bottlenecks without them. And theoretically I think that is true. But this is one of thoose times theory just won't help. 
&lt;/p&gt;&lt;p&gt;
In my, not so humble, oppinion establishing WIP limits helps us the same way a budgets do. It help us set clear priorites and makes us think about our general goals. It also works as a clear leading indicator for when things are getting out of hand. One could make the claim that having a budget is waste, and if you're really disciplined I guess that is a viable option. But for me, it's not that I strictly need it, it's just way simpler than the alternatives. 
&lt;/p&gt;&lt;p&gt;
Twitter via &lt;a href='http://twitter.com/hiranabe'&gt;@hiranabe&lt;/a&gt; provided this gem: &lt;q&gt;Kuroiwa-san(ex-Toyota mgr) concluded speech by emphasizing "Thinking for yourself in your context" is the heart of Lean&lt;/q&gt;
&lt;/p&gt;&lt;p&gt;
This is another very tangible postive effect of imposing limits, they help us establish context. The heart of lean and agile processes is thinking in context, anything that helps us faster establish context and be present have a great positive impact on the speed of communication. Thereby helping us improve, reflect, adjust and evaluate. That in turn helps us deliver more value faster, and sustain those improvements over time. 
&lt;/p&gt;&lt;p&gt;
Thinking is not the key, thinking about the right stuff is. Establishing context is vital for that.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-6548448701847041390?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/6548448701847041390/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/07/thinking-in-context.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/6548448701847041390'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/6548448701847041390'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/07/thinking-in-context.html' title='Thinking in context.'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-3169162453851319879</id><published>2009-06-30T08:35:00.002+02:00</published><updated>2009-06-30T08:48:51.293+02:00</updated><title type='text'>Ownership, Responsibility and Sharing.</title><content type='html'>Im a big fan of collective code ownership. This is my attempt to clear up one common point of confusion. Responsibility does not imply ownership. Making everyone responsible for the whole codebase most often fails miserably for the same reasons very few can keep any sufficently large system wholy in their heads. If everyone is responsible, most often nobody or a select few is. My current thinking about this is that people should be responsible for a slice of functionality or a module depending on your circumstances. But they're responsible, they don't own it. Anyone can, and should be encouraged to, change the code. The responsible guardian for that part should monitor changes, clarify conceptual missunderstandings, know his part of the system on a sufficent depth to be able to detect at a structural and conceptual level when duplication is creeping in to other parts of the system. Having responsibility does not mean soly working on that part, it means shepherding it and making sure that peers adhers to agreed conventions.
&lt;p&gt;
I've seen tremendous benefits from this, it lets people get really good at one part of the system, giving them both pride and the ability to at a much deeper level draw parallels to other parts during pairing sessions and work on other parts. It avoids the "everyone knows almost nothing about everything"-problem thereby reducing waste due to relearning and rediscovery. It sets expectations and builds team spirit, if we know that someone will be checking our work we tend to take greater care. And noone want to let a team-mate down. Theese effects augument conventional practices like pair programming in a very positive way.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-3169162453851319879?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/3169162453851319879/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/06/ownership-responsibility-and-sharing.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/3169162453851319879'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/3169162453851319879'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/06/ownership-responsibility-and-sharing.html' title='Ownership, Responsibility and Sharing.'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-2685808601212667895</id><published>2009-06-25T21:08:00.001+02:00</published><updated>2009-06-25T21:09:42.009+02:00</updated><title type='text'>Anti-If Campaing I've Joined!</title><content type='html'>&lt;a href="http://www.antiifcampaign.com"&gt;
   &lt;img height="60" width="120" 
   src="http://www.antiifcampaign.com/_export/anti-if-campaign-ive-joined.gif" 
   alt="I have joined Anti-IF Campaign" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-2685808601212667895?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/2685808601212667895/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/06/anti-if-campaing-ive-joined.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/2685808601212667895'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/2685808601212667895'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/06/anti-if-campaing-ive-joined.html' title='Anti-If Campaing I&apos;ve Joined!'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-7920387017408353915</id><published>2009-05-27T09:14:00.004+02:00</published><updated>2009-05-27T09:25:27.132+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bugs'/><category scheme='http://www.blogger.com/atom/ns#' term='F#'/><category scheme='http://www.blogger.com/atom/ns#' term='VS2010'/><title type='text'>Microsoft - You're doing it right!</title><content type='html'>&lt;p&gt;I'm generally not known for being a big Microsoft fanboy. But I have to say that my recent experinces have left me happy. I've been using the F# CTP since it came out and currently running the Visual Studio 2010 beta. Both are great products but that's not what this post is about.&lt;/p&gt;&lt;p&gt;
This post is about how pleased I am with their handling of submitted bugs. The F# team is extremly friendly, quick to respond and equally good at providing updates and responding in a timely manner. Maybe not shocking given that it seems to be a small dedicated team. What mandates this post is that the VS2010 beta team also exhibits theese qualities. Submitting a bug is easy and painfree and they seem to be handled in a very good manner providing timely updates as it flows through the process.&lt;/p&gt;
So all thumbs up for the awsome F# and VSEditor teams!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-7920387017408353915?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/7920387017408353915/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/05/microsoft-youre-doing-it-right.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/7920387017408353915'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/7920387017408353915'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/05/microsoft-youre-doing-it-right.html' title='Microsoft - You&apos;re doing it right!'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-7880939787640430585</id><published>2009-04-24T13:10:00.004+02:00</published><updated>2009-04-24T13:14:38.987+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='F#'/><title type='text'>Fake - The future of .NET build tools?</title><content type='html'>Tired of XML based build systems? &lt;br&gt;
Thought so. That's why I spent a few minutes hacking togheter the basis for my own build system. I call it Fake. And looks like this:&lt;br&gt;
&lt;div class='f-sharp'&gt;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;clean&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;task&amp;nbsp;&lt;span class='tx'&gt;"Clean"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;&lt;span class='kw'&gt;fun&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console&lt;span class='op'&gt;.&lt;/span&gt;WriteLine&lt;span class='op'&gt;(&lt;/span&gt;&lt;span class='tx'&gt;"Cleaning."&lt;/span&gt;&lt;span class='op'&gt;))&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class='op'&gt;[&amp;lt;&lt;/span&gt;Default&lt;span class='op'&gt;&gt;]&lt;/span&gt;&lt;br&gt;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;build&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;task&amp;nbsp;&lt;span class='tx'&gt;"Build&amp;nbsp;the&amp;nbsp;lot"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;clean&amp;nbsp;&lt;span class='op'&gt;=&gt;&lt;/span&gt;&amp;nbsp;&lt;span class='kw'&gt;fun&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console&lt;span class='op'&gt;.&lt;/span&gt;WriteLine&lt;span class='op'&gt;(&lt;/span&gt;&lt;span class='tx'&gt;"Building.."&lt;/span&gt;&lt;span class='op'&gt;))&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;loadTestData&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;task&amp;nbsp;&lt;span class='tx'&gt;"Load&amp;nbsp;some&amp;nbsp;test&amp;nbsp;data"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;&lt;span class='kw'&gt;fun&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console&lt;span class='op'&gt;.&lt;/span&gt;WriteLine&lt;span class='op'&gt;(&lt;/span&gt;&lt;span class='tx'&gt;"Loading&amp;nbsp;test&amp;nbsp;data..."&lt;/span&gt;&lt;span class='op'&gt;))&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;test&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;task&amp;nbsp;&lt;span class='tx'&gt;"Test&amp;nbsp;it"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;([&lt;/span&gt;build&lt;span class='op'&gt;;&lt;/span&gt;&amp;nbsp;loadTestData&lt;span class='op'&gt;]&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&gt;&lt;/span&gt;&amp;nbsp;&lt;span class='kw'&gt;fun&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Console&lt;span class='op'&gt;.&lt;/span&gt;WriteLine&lt;span class='op'&gt;(&lt;/span&gt;&lt;span class='tx'&gt;"Running&amp;nbsp;Tests...."&lt;/span&gt;&lt;span class='op'&gt;))&lt;/span&gt;&lt;/div&gt;

Then simply&lt;pre&gt;x:\..\&amp;gt;fake test
Cleaning.
Building..
Loading test data...
Running Tests....
x:\..\&amp;gt;&lt;/pre&gt;

Is this idea worthwhile? Tell me in the comments.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-7880939787640430585?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/7880939787640430585/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/04/fake-future-of-net-build-tools.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/7880939787640430585'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/7880939787640430585'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/04/fake-future-of-net-build-tools.html' title='Fake - The future of .NET build tools?'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-4347911924941071932</id><published>2009-04-21T08:56:00.005+02:00</published><updated>2009-04-30T08:22:46.068+02:00</updated><title type='text'>Team Foundation vs Subversion and Bazaar - Round 1: Update my workspace.</title><content type='html'>I usually work with Subversion or Bazaar but currently I'm on a project using Team Foundation Server. Today I got the silly idea of updating my workspace using the command line interface. 
Assuming that you are standing in the directory you want to update this task can be accomplished as follows:&lt;table style="border:1px solid black"&gt;
&lt;tr&gt;&lt;td style="border-right:1px solid black"&gt;Subversion&lt;/td&gt;&lt;td&gt;Team Foundation&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td style="border-right:1px solid black"&gt;svn up&lt;/td&gt;&lt;td&gt;tf get .\* /version:T /recursive&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;

Now one of theese is sane, the other is complelty insane. I won't tell you wich is wich.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-4347911924941071932?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/4347911924941071932/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/04/team-foundation-vs-subversion-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/4347911924941071932'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/4347911924941071932'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/04/team-foundation-vs-subversion-and.html' title='Team Foundation vs Subversion and Bazaar - Round 1: Update my workspace.'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-8077401036613926916</id><published>2009-04-08T22:26:00.007+02:00</published><updated>2009-04-08T22:45:36.762+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='RED'/><title type='text'>RED - Re Evolutionary Development</title><content type='html'>Something is happening in devloperland, if you put your ear to the tubes of the blogosphere you can hear a faint message. The Software Craftmanship movement is gathering momentum with a simple message, and one of the high priests of XP has abdicated.
&lt;p&gt;
There's a new focus comming and it cuts right through all excuses, the message is simple.&lt;br&gt;
&lt;strong&gt;YOU&lt;/strong&gt; are responsible.
&lt;/p&gt;&lt;p&gt;
No one else is going to give you the mandate to work in a fashion you know you really ought to, no one else is going to educate your peers for you, and no one else is going to fix your broken process. Yes I know it's horrible. The business demands the impossible and your cow orkers are all a bunch of imbicils. That's exactly why it's your problem. You're the only sane, educated, competent, levelheaded person around, it's your responsibility to do something about the madness. 
&lt;/p&gt;&lt;p&gt;
We need to stop trying to blame everyone else for our problems, we need to stop discussing what's wrong with "other people" and actually start taking action. Every single day, strive to improve, learn and share! 
&lt;/p&gt;
I'll dub this "Re Evolutionary Development" or RED for short and as all good philosophies it needs a set of principles the first one simply is:

&lt;h2&gt;RED Principle #1&lt;/h2&gt;
Each day ask yourself. 
&lt;ul&gt;
&lt;li&gt;What did I learn?&lt;/li&gt;
&lt;li&gt;What did I share?&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-8077401036613926916?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/8077401036613926916/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/04/red-re-evolutionary-development.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/8077401036613926916'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/8077401036613926916'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/04/red-re-evolutionary-development.html' title='RED - Re Evolutionary Development'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-3226746906826922148</id><published>2009-03-09T08:28:00.007+01:00</published><updated>2009-03-09T09:46:37.427+01:00</updated><title type='text'>The Care and Feeding of your Build - Stability.</title><content type='html'>Having an automated, fast, repeatable build provides the heartbeat of the project. Sadly it's often neglected and viewed as tedious to set up, boring to maintain and the only time it actually does get any attention is when it doens't work. Good build systems exhibit a few key charecteristics, today Im going to talk about one of the finer points, stability.

&lt;h2&gt;What is stability?&lt;/h2&gt;
The stability of a build can be stated as:&lt;strong&gt;Unless something changed, do nothing.&lt;/strong&gt;&lt;br/&gt;
Or as &lt;a href='http://www.onjava.com/pub/a/onjava/2003/12/17/ant_bestpractices.html'&gt;Ant best practices&lt;/a&gt; item "14. Perform the Clean Build Test" puts it:
&lt;p&gt;&lt;q&gt;Assuming your buildfile has clean and compile targets, perform the following test. First, type ant clean. Second, type ant compile. Third, type ant compile again. The third step should do absolutely nothing. If files compile a second time, something is wrong with your buildfile.&lt;/q&gt;

&lt;h2&gt;Why stability?&lt;/h2&gt;
Stability is important since it has a direct effect on the length of your build/test cycle. Any inefficency introduced grows both with the project and with the number of team members. This means that unless you keep your build stable every compile will cost you a small amount of time, for every team member, over time this adds up to substantial amount. 
&lt;h2&gt;Easy ways to fail.&lt;/h2&gt;
There's a few ways that almost every build system I've worked with failed the stability test the most common offenders I've found are.
&lt;h3&gt;Unconditional Post Build xcopy&lt;/h3&gt;
It's often convinent and sometimes neccessary to copy output files to some other directory. Often this is done to create smaller solutions/projectfiles for the IDE and more stable projects are simply built and copied to a folder with precompiled binaries and referenced from there. This is a good strategy. The problem arise when the copy is unconditional since this often forces a rebuild of all dependent projects even though the shared library did not change! If you're using Visual Studio, unless you got a really really good reason always use "When the build updates the project output" option for "Run the post-build event:". If you're using Ant/NAnt/Rake/&lt;Your Favourite Build Tool&gt; and have a target that does compile+copy always check before copying. 
&lt;h3&gt;Unguarded build targets&lt;/h3&gt;
Common offenders in this category is test/coverage targets, creation of installation packages and "zip tasks", care should always be taken to ensure that something actually did change before redoing theese procedures. Often this can be accomplished by comparing timestamps for the source and destination files. If no tangible output is generated by default it can make sense to introduce a marker file and touche it on completion of the task. 
&lt;h2&gt;Summary&lt;/h2&gt;
Keep your build fast by avoiding redundant work, take care to never do work unless something actually did change.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-3226746906826922148?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/3226746906826922148/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/03/care-and-feeding-of-your-build.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/3226746906826922148'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/3226746906826922148'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/03/care-and-feeding-of-your-build.html' title='The Care and Feeding of your Build - Stability.'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-7220909751702129051</id><published>2009-03-07T10:40:00.002+01:00</published><updated>2009-03-07T10:44:50.369+01:00</updated><title type='text'>Manifesto for Software Craftmanship</title><content type='html'>Ever felt that there's something missing from the &lt;a href='http://www.agilemanifesto.org/'&gt;Agile Manifesto&lt;/a&gt;? Feeling left out in all the management fluff? Ever wondered, but where's the focus on &lt;em&gt;my&lt;/em&gt; craft? I sure have.
&lt;p&gt;
There's a old, new, movement on the raise, a movement for software craftmanship. Sign the &lt;a href='http://manifesto.softwarecraftsmanship.org/'&gt;Manifesto for Software Craftmanship&lt;/a&gt; and help us raise the bar. 
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-7220909751702129051?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/7220909751702129051/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/03/manifesto-for-software-craftmanship.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/7220909751702129051'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/7220909751702129051'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/03/manifesto-for-software-craftmanship.html' title='Manifesto for Software Craftmanship'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-4861507803931588702</id><published>2009-02-21T18:59:00.004+01:00</published><updated>2009-02-21T19:38:20.800+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='story points'/><category scheme='http://www.blogger.com/atom/ns#' term='planning'/><category scheme='http://www.blogger.com/atom/ns#' term='estimation'/><category scheme='http://www.blogger.com/atom/ns#' term='pizza'/><title type='text'>Pizza Points - story estimation made round!</title><content type='html'>There's two commonly used methods for agile estimation Story Points and Ideal Programming Somethings, commonly days or hours. Both methods have their merits with some bias towards Story Points (SP) from Mike Cohn and various other well known names although Ideal Programming Somethings seems to be more commonly used by the teams I've spoken to. 
&lt;p&gt;
There seems to be quite a bit of confusion regarding how they relate and how both terms relate to hours. To remedy some of this I want to propose a new system, Pizza Points, that is driven by an easy to explain intuitive and rich metaphor. 
&lt;/p&gt;&lt;p&gt;
Lets look at the similarities between work and pizza as used in the following discussion. 
&lt;/p&gt;&lt;p&gt;
&lt;ul&gt;
&lt;li&gt;Pizza is round, work tends to be circular.&lt;/li&gt;
&lt;li&gt;Pizza can be filling and deeply satisfying, as can work.&lt;/li&gt;
&lt;li&gt;Pizza comes in different sizes, as does stories and tasks.&lt;/li&gt;
&lt;li&gt;Pizza can have lots of varying and interesting fillings, work can be filled with many intresting things.&lt;/li&gt;
&lt;li&gt;As we mature we can eat more pizza and as we learn a domain and tools we can tackle bigger tasks.&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;&lt;p&gt;
Depending on the peculiarities of your favourite pizza parlour the size and form may vary, maybe you have children, normal and family, maybe the range is small, medium, large, and extra-large often it's round and sometimes you get oddly square bites. There's no guarantee that a small pizza is the same size between to different places and there's likewise no sense in assuming that a pizza point is equally sized between two teams. That said, if you stick to one place, keep your team intact, any given size will overtime be quite consistent. 
&lt;/p&gt;&lt;p&gt;
So how do we get started using Pizza Points? 
&lt;/p&gt;&lt;p&gt;
We have to start by establishing some sort of baseline size, no diffrent from the initial sizing of story points. Find a fairly small, easily graspable story discuss the criterias for done and label it "children", "small" or why not, one. 
Continue estimation by thinking about the relative *size* not filling, give them descriptive names, standard, family, 2, 3, 5, 8, 13, 20, 40, 100, xxx-large. 
&lt;/p&gt;&lt;p&gt;
It's as easy as that. The thing to remember is that size is actually a constant but the filling might greatly influence how much we can eat. I like pizza and can eat quite a lot given toppings like different cheeses, ham, pineapple for example. Give me anchovies and you'll have me struggling an evening to come close to finishing even a child size bite. The size haven't changed, my aptitude and motivation did.
&lt;/p&gt;&lt;p&gt;
If you're the one placing orders and want to get as much pizza eaten as possible during any period of time it can be wise to ask your team for their taste preferences. But real life sometimes dictates that we put anchovies on their plate, that's a big responsibility. 
&lt;/p&gt;&lt;p&gt;
To summarize, think size not filling, match fillings to team, expect size to vary depending on team. Also expect mature, adult, teams to eat more than children.
&lt;/p&gt;
And don't forget to order planning pizza as a reminder during long estimation sessions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-4861507803931588702?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/4861507803931588702/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/02/pizza-points-story-estimation-made.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/4861507803931588702'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/4861507803931588702'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/02/pizza-points-story-estimation-made.html' title='Pizza Points - story estimation made round!'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-6799108898390948304</id><published>2009-02-09T13:40:00.004+01:00</published><updated>2009-02-09T13:44:31.019+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='mock'/><category scheme='http://www.blogger.com/atom/ns#' term='BDD'/><category scheme='http://www.blogger.com/atom/ns#' term='TypeMock'/><title type='text'>The story about TypeMock.</title><content type='html'>To mock or not. That's the question. Here's how I think some BDDers and Mockists labled their Kool-Aid before drinking it.
&lt;p&gt;
&lt;strong&gt;Given&lt;/strong&gt; &lt;a href='http://www.typemock.com/'&gt;TypeMock&lt;/a&gt;&lt;br/&gt;
&lt;strong&gt;When&lt;/strong&gt; I want to test&lt;br/&gt;
&lt;strong&gt;Then&lt;/strong&gt; everything looks like a mock object.&lt;br/&gt;
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-6799108898390948304?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/6799108898390948304/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/02/story-about-typemock.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/6799108898390948304'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/6799108898390948304'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/02/story-about-typemock.html' title='The story about TypeMock.'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-8099577276114210187</id><published>2009-02-03T12:54:00.005+01:00</published><updated>2009-02-03T13:20:50.273+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='F#'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><title type='text'>Pencil.Unit and Micro Lightweight Unit Testing</title><content type='html'>Joe Armstrong of Erlang fame has the following to say on how he write unit tests
&lt;a href="http://armstrongonsoftware.blogspot.com/2009/01/micro-lightweight-unit-testing.html"&gt;Micro Lightweight Unit Testing&lt;/a&gt;
&lt;br/&gt;
Here's a condenced retrace of his steps using F# and Pencil.Unit
&lt;br/&gt;
&lt;strong&gt;Step 1) Write Micro Unit Test&lt;/strong&gt;
&lt;div class='f-sharp'&gt;Theory&amp;nbsp;&lt;span class='tx'&gt;"Fib&amp;nbsp;should&amp;nbsp;work&amp;nbsp;for&amp;nbsp;known&amp;nbsp;values&amp;nbsp;from&amp;nbsp;Wikipedia"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;[(&lt;/span&gt;0&lt;span class='op'&gt;,&lt;/span&gt;0&lt;span class='op'&gt;);&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;1&lt;span class='op'&gt;,&lt;/span&gt;&amp;nbsp;1&lt;span class='op'&gt;);&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;2&lt;span class='op'&gt;,&lt;/span&gt;&amp;nbsp;1&lt;span class='op'&gt;);&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;3&lt;span class='op'&gt;,&lt;/span&gt;&amp;nbsp;2&lt;span class='op'&gt;);&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;20&lt;span class='op'&gt;,&lt;/span&gt;&amp;nbsp;6765&lt;span class='op'&gt;)]&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;&lt;span class='kw'&gt;fun&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;n&lt;span class='op'&gt;,&lt;/span&gt;&amp;nbsp;e&lt;span class='op'&gt;)&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;Fib&amp;nbsp;n&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;Should&amp;nbsp;Equal&amp;nbsp;e&lt;span class='op'&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;strong&gt;Step 2) Implement Fib&lt;/strong&gt;
&lt;div class='f-sharp'&gt;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;&lt;span class='kw'&gt;rec&lt;/span&gt;&amp;nbsp;Fib&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;&lt;span class='kw'&gt;function&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;0&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;0&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;1&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;1&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;_&lt;/span&gt;&amp;nbsp;&lt;span class='kw'&gt;as&lt;/span&gt;&amp;nbsp;n&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;Fib&lt;span class='op'&gt;(&lt;/span&gt;n&amp;nbsp;&lt;span class='op'&gt;-&lt;/span&gt;&amp;nbsp;1&lt;span class='op'&gt;)&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;+&lt;/span&gt;&amp;nbsp;Fib&lt;span class='op'&gt;(&lt;/span&gt;n&amp;nbsp;&lt;span class='op'&gt;-&lt;/span&gt;&amp;nbsp;2&lt;span class='op'&gt;)&lt;/span&gt;&lt;/div&gt;
&lt;strong&gt;Step 3) Theorize about FastFib&lt;/strong&gt;
&lt;div class='f-sharp'&gt;Theory&amp;nbsp;&lt;span class='tx'&gt;"FastFib&amp;nbsp;should&amp;nbsp;give&amp;nbsp;same&amp;nbsp;result&amp;nbsp;as&amp;nbsp;Fib"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;[&lt;/span&gt;0&lt;span class='op'&gt;;&lt;/span&gt;&amp;nbsp;1&lt;span class='op'&gt;;&lt;/span&gt;&amp;nbsp;2&lt;span class='op'&gt;;&lt;/span&gt;&amp;nbsp;3&lt;span class='op'&gt;;&lt;/span&gt;&amp;nbsp;25&lt;span class='op'&gt;]&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;&lt;span class='kw'&gt;fun&lt;/span&gt;&amp;nbsp;n&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;FastFib&amp;nbsp;n&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;Should&amp;nbsp;Equal&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;Fib&amp;nbsp;n&lt;span class='op'&gt;))&lt;/span&gt;&lt;/div&gt;
&lt;strong&gt;Step 4)Implement FastFib&lt;/strong&gt;
&lt;div class='f-sharp'&gt;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;FastFib&amp;nbsp;n&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;&lt;span class='kw'&gt;rec&lt;/span&gt;&amp;nbsp;loop&amp;nbsp;n&amp;nbsp;a&amp;nbsp;b&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;match&lt;/span&gt;&amp;nbsp;n&amp;nbsp;&lt;span class='kw'&gt;with&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;0&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;a&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;_&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;loop&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;n&amp;nbsp;&lt;span class='op'&gt;-&lt;/span&gt;&amp;nbsp;1&lt;span class='op'&gt;)&lt;/span&gt;&amp;nbsp;b&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;a&amp;nbsp;&lt;span class='op'&gt;+&lt;/span&gt;&amp;nbsp;b&lt;span class='op'&gt;)&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;loop&amp;nbsp;n&amp;nbsp;0&amp;nbsp;1&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-8099577276114210187?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/8099577276114210187/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/02/pencilunit-and-micro-lightweight-unit.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/8099577276114210187'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/8099577276114210187'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/02/pencilunit-and-micro-lightweight-unit.html' title='Pencil.Unit and Micro Lightweight Unit Testing'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-5012101127242298046</id><published>2009-02-02T21:01:00.004+01:00</published><updated>2009-02-03T12:39:46.794+01:00</updated><title type='text'>Taking Pencil.Unit for a spin, F# syntax highlighting.</title><content type='html'>Decided to take the current iteration of the testing code posted earlier for a spin by trying to actually build something usefull with it. Since Im yet to find a decent syntax highlighter that supports F# and doesn't generate utterly disgusting HTML I decided to try to test and hack my way to one that at least suits my quite humble needs. The result was this:
&lt;div class='f-sharp'&gt;&lt;span class='c'&gt;(*&amp;nbsp;Building&amp;nbsp;a&amp;nbsp;(very&amp;nbsp;simple)&amp;nbsp;syntax&amp;nbsp;higligher&amp;nbsp;with&amp;nbsp;Pencil.Unit&amp;nbsp;*)&lt;/span&gt;&lt;br&gt;&lt;span class='pp'&gt;#light&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class='kw'&gt;open&lt;/span&gt;&amp;nbsp;System&lt;br&gt;&lt;span class='kw'&gt;open&lt;/span&gt;&amp;nbsp;System&lt;span class='op'&gt;.&lt;/span&gt;Text&lt;br&gt;&lt;span class='kw'&gt;open&lt;/span&gt;&amp;nbsp;System&lt;span class='op'&gt;.&lt;/span&gt;IO&lt;br&gt;&lt;span class='kw'&gt;open&lt;/span&gt;&amp;nbsp;Pencil&lt;span class='op'&gt;.&lt;/span&gt;Unit&lt;br&gt;&lt;br&gt;&lt;span class='kw'&gt;type&lt;/span&gt;&amp;nbsp;Token&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;Comment&amp;nbsp;&lt;span class='kw'&gt;of&lt;/span&gt;&amp;nbsp;string&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;Keyword&amp;nbsp;&lt;span class='kw'&gt;of&lt;/span&gt;&amp;nbsp;string&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;Preprocessor&amp;nbsp;&lt;span class='kw'&gt;of&lt;/span&gt;&amp;nbsp;string&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;String&amp;nbsp;&lt;span class='kw'&gt;of&lt;/span&gt;&amp;nbsp;string&amp;nbsp;array&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;Text&amp;nbsp;&lt;span class='kw'&gt;of&lt;/span&gt;&amp;nbsp;string&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;WhiteSpace&amp;nbsp;&lt;span class='kw'&gt;of&lt;/span&gt;&amp;nbsp;string&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;NewLine&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;Operator&amp;nbsp;&lt;span class='kw'&gt;of&lt;/span&gt;&amp;nbsp;string&lt;br&gt;&lt;br&gt;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;Classify&amp;nbsp;x&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;match&lt;/span&gt;&amp;nbsp;x&amp;nbsp;&lt;span class='kw'&gt;with&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"abstract"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"and"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"as"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"assert"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"base"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"begin"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"class"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"default"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"delegate"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"do"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"done"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"downcast"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"downto"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"elif"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"else"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"end"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"exception"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"extern"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"false"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"finally"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"for"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"fun"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"function"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"if"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"in"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"inherit"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"inline"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"interface"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"internal"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"lazy"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"let"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"match"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"member"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"module"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"mutable"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"namespace"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"new"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"null"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"of"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"open"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"or"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"override"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"private"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"public"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"rec"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"return"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"static"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"struct"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"then"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"to"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"true"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"try"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"type"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"upcast"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"use"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"val"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"void"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"when"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"while"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"with"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"yield"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;Keyword&amp;nbsp;x&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;_&lt;/span&gt;&amp;nbsp;&lt;span class='kw'&gt;when&lt;/span&gt;&amp;nbsp;x&lt;span class='op'&gt;.[&lt;/span&gt;0&lt;span class='op'&gt;]&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;'#'&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;Preprocessor&amp;nbsp;x&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;_&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;Text&amp;nbsp;x&lt;br&gt;&lt;br&gt;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;IsKeyword&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;&lt;span class='kw'&gt;function&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;Keyword&amp;nbsp;&lt;span class='op'&gt;_&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;&lt;span class='kw'&gt;true&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;_&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;&lt;span class='kw'&gt;false&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;IsPreprocessor&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;&lt;span class='kw'&gt;function&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;Preprocessor&amp;nbsp;&lt;span class='op'&gt;_&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;&lt;span class='kw'&gt;true&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;_&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;&lt;span class='kw'&gt;false&lt;/span&gt;&lt;br&gt;&lt;br&gt;Theory&amp;nbsp;&lt;span class='tx'&gt;"Classify&amp;nbsp;should&amp;nbsp;support&amp;nbsp;all&amp;nbsp;F#&amp;nbsp;keywords"&lt;/span&gt;&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;&lt;span class='tx'&gt;"abstract&amp;nbsp;and&amp;nbsp;as&amp;nbsp;assert&amp;nbsp;base&amp;nbsp;begin&amp;nbsp;class&amp;nbsp;default&amp;nbsp;delegate&amp;nbsp;do&amp;nbsp;done&lt;/span&gt;&lt;br&gt;&lt;span class='tx'&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;downcast&amp;nbsp;downto&amp;nbsp;elif&amp;nbsp;else&amp;nbsp;end&amp;nbsp;exception&amp;nbsp;extern&amp;nbsp;false&amp;nbsp;finally&amp;nbsp;for&lt;/span&gt;&lt;br&gt;&lt;span class='tx'&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fun&amp;nbsp;function&amp;nbsp;if&amp;nbsp;in&amp;nbsp;inherit&amp;nbsp;inline&amp;nbsp;interface&amp;nbsp;internal&amp;nbsp;lazy&amp;nbsp;let&lt;/span&gt;&lt;br&gt;&lt;span class='tx'&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;match&amp;nbsp;member&amp;nbsp;module&amp;nbsp;mutable&amp;nbsp;namespace&amp;nbsp;new&amp;nbsp;null&amp;nbsp;of&amp;nbsp;open&amp;nbsp;or&lt;/span&gt;&lt;br&gt;&lt;span class='tx'&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;override&amp;nbsp;private&amp;nbsp;public&amp;nbsp;rec&amp;nbsp;return&amp;nbsp;static&amp;nbsp;struct&amp;nbsp;then&amp;nbsp;to&lt;/span&gt;&lt;br&gt;&lt;span class='tx'&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;true&amp;nbsp;try&amp;nbsp;type&amp;nbsp;upcast&amp;nbsp;use&amp;nbsp;val&amp;nbsp;void&amp;nbsp;when&amp;nbsp;while&amp;nbsp;with&amp;nbsp;yield"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;.&lt;/span&gt;Split&lt;span class='op'&gt;([|&lt;/span&gt;'&amp;nbsp;'&lt;span class='op'&gt;;&lt;/span&gt;'\t'&lt;span class='op'&gt;;&lt;/span&gt;'\r'&lt;span class='op'&gt;;&lt;/span&gt;'\n'&lt;span class='op'&gt;|],&lt;/span&gt;&amp;nbsp;StringSplitOptions&lt;span class='op'&gt;.&lt;/span&gt;RemoveEmptyEntries&lt;span class='op'&gt;))&lt;/span&gt;&lt;br&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;&lt;span class='kw'&gt;fun&lt;/span&gt;&amp;nbsp;x&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;Classify&amp;nbsp;x&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;IsKeyword&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;Should&amp;nbsp;Equal&amp;nbsp;&lt;span class='kw'&gt;true&lt;/span&gt;&lt;span class='op'&gt;)&lt;/span&gt;&lt;br&gt;&lt;br&gt;Fact&amp;nbsp;&lt;span class='tx'&gt;"Classify&amp;nbsp;should&amp;nbsp;treat&amp;nbsp;leading&amp;nbsp;#&amp;nbsp;as&amp;nbsp;Preprocessor"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;Classify&amp;nbsp;&lt;span class='tx'&gt;"#light"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;IsPreprocessor&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;Should&amp;nbsp;Equal&amp;nbsp;&lt;span class='kw'&gt;true&lt;/span&gt;&lt;span class='op'&gt;)&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;Tokenize&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;s&lt;span class='op'&gt;:&lt;/span&gt;string&lt;span class='op'&gt;)&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;start&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;ref&amp;nbsp;0&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;p&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;ref&amp;nbsp;0&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;next&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;p&amp;nbsp;&lt;span class='op'&gt;:=&lt;/span&gt;&amp;nbsp;!p&amp;nbsp;&lt;span class='op'&gt;+&lt;/span&gt;&amp;nbsp;1&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;and&lt;/span&gt;&amp;nbsp;hasMore&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;!p&amp;nbsp;&lt;span class='op'&gt;&amp;lt;&lt;/span&gt;&amp;nbsp;s&lt;span class='op'&gt;.&lt;/span&gt;Length&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;and&lt;/span&gt;&amp;nbsp;sub&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;s&lt;span class='op'&gt;.&lt;/span&gt;Substring&lt;span class='op'&gt;(&lt;/span&gt;!start&lt;span class='op'&gt;,&lt;/span&gt;&amp;nbsp;!p&amp;nbsp;&lt;span class='op'&gt;-&lt;/span&gt;&amp;nbsp;!start&lt;span class='op'&gt;)&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;and&lt;/span&gt;&amp;nbsp;current&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;s&lt;span class='op'&gt;.[&lt;/span&gt;!p&lt;span class='op'&gt;]&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;and&lt;/span&gt;&amp;nbsp;prev&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;s&lt;span class='op'&gt;.[&lt;/span&gt;!p&amp;nbsp;&lt;span class='op'&gt;-&lt;/span&gt;&amp;nbsp;1&lt;span class='op'&gt;]&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;peek&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;&lt;span class='kw'&gt;if&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;!p&amp;nbsp;&lt;span class='op'&gt;+&lt;/span&gt;&amp;nbsp;1&lt;span class='op'&gt;)&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;&amp;lt;&lt;/span&gt;&amp;nbsp;s&lt;span class='op'&gt;.&lt;/span&gt;Length&amp;nbsp;&lt;span class='kw'&gt;then&lt;/span&gt;&lt;br&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;s&lt;span class='op'&gt;.[&lt;/span&gt;!p&amp;nbsp;&lt;span class='op'&gt;+&lt;/span&gt;&amp;nbsp;1&lt;span class='op'&gt;]&lt;/span&gt;&lt;br&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;&amp;nbsp;&lt;span class='kw'&gt;else&lt;/span&gt;&lt;br&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;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;char&lt;span class='op'&gt;)&lt;/span&gt;0&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;and&lt;/span&gt;&amp;nbsp;isWhite&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;match&lt;/span&gt;&amp;nbsp;current&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='kw'&gt;with&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;'&amp;nbsp;'&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;'\t'&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;&lt;span class='kw'&gt;true&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;_&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;&lt;span class='kw'&gt;false&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;and&lt;/span&gt;&amp;nbsp;isOperator&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"_(){}&amp;lt;&gt;,.=|-+:;[]"&lt;/span&gt;&lt;span class='op'&gt;.&lt;/span&gt;Contains&lt;span class='op'&gt;(&lt;/span&gt;string&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;current&lt;span class='op'&gt;()))&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;and&lt;/span&gt;&amp;nbsp;isNewLine&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;current&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;'\r'&amp;nbsp;&lt;span class='op'&gt;||&lt;/span&gt;&amp;nbsp;current&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;'\n'&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;notNewline&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;not&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;isNewLine&lt;span class='op'&gt;())&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;and&lt;/span&gt;&amp;nbsp;notBlockEnd&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;not&lt;span class='op'&gt;(&lt;/span&gt;current&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;'&lt;span class='op'&gt;)&lt;/span&gt;'&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;prev&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;'*'&lt;span class='op'&gt;)&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;inWord&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;not&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;isWhite&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;||&lt;/span&gt;&amp;nbsp;isNewLine&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;||&lt;/span&gt;&amp;nbsp;isOperator&lt;span class='op'&gt;())&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;read&amp;nbsp;p&amp;nbsp;eatLast&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;while&lt;/span&gt;&amp;nbsp;hasMore&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&amp;amp;&amp;amp;&amp;nbsp;p&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='kw'&gt;do&lt;/span&gt;&lt;br&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;next&lt;span class='op'&gt;()&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;if&lt;/span&gt;&amp;nbsp;eatLast&amp;nbsp;&lt;span class='kw'&gt;then&lt;/span&gt;&lt;br&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;next&lt;span class='op'&gt;()&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sub&lt;span class='op'&gt;()&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;readWhite&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;WhiteSpace&lt;span class='op'&gt;(&lt;/span&gt;read&amp;nbsp;isWhite&amp;nbsp;&lt;span class='kw'&gt;false&lt;/span&gt;&lt;span class='op'&gt;)&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;and&lt;/span&gt;&amp;nbsp;readNewLine&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;next&lt;span class='op'&gt;()&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;if&lt;/span&gt;&amp;nbsp;isNewLine&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='kw'&gt;then&lt;/span&gt;&lt;br&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;next&lt;span class='op'&gt;()&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;NewLine&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;and&lt;/span&gt;&amp;nbsp;readWord&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;Classify&lt;span class='op'&gt;(&lt;/span&gt;read&amp;nbsp;inWord&amp;nbsp;&lt;span class='kw'&gt;false&lt;/span&gt;&lt;span class='op'&gt;)&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;and&lt;/span&gt;&amp;nbsp;readOperator&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;Operator&lt;span class='op'&gt;(&lt;/span&gt;read&amp;nbsp;isOperator&amp;nbsp;&lt;span class='kw'&gt;false&lt;/span&gt;&lt;span class='op'&gt;)&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;and&lt;/span&gt;&amp;nbsp;readString&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;isEscaped&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;prev&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;'\\'&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;inString&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;isEscaped&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;||&lt;/span&gt;&amp;nbsp;current&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;&amp;lt;&gt;&lt;/span&gt;&amp;nbsp;'\"'&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;next&lt;span class='op'&gt;()&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;s&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;read&amp;nbsp;inString&amp;nbsp;&lt;span class='kw'&gt;true&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String&lt;span class='op'&gt;(&lt;/span&gt;s&lt;span class='op'&gt;.&lt;/span&gt;Split&lt;span class='op'&gt;([|&lt;/span&gt;'\r'&lt;span class='op'&gt;;&lt;/span&gt;'\n'&lt;span class='op'&gt;|],&lt;/span&gt;&amp;nbsp;StringSplitOptions&lt;span class='op'&gt;.&lt;/span&gt;RemoveEmptyEntries&lt;span class='op'&gt;))&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;seq&amp;nbsp;&lt;span class='op'&gt;{&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;while&lt;/span&gt;&amp;nbsp;hasMore&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='kw'&gt;do&lt;/span&gt;&lt;br&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;start&amp;nbsp;&lt;span class='op'&gt;:=&lt;/span&gt;&amp;nbsp;!p&lt;br&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;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;token&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&lt;br&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;&lt;span class='kw'&gt;match&lt;/span&gt;&amp;nbsp;current&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='kw'&gt;with&lt;/span&gt;&lt;br&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;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;'\"'&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;readString&lt;span class='op'&gt;()&lt;/span&gt;&lt;br&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;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;'/'&amp;nbsp;&lt;span class='kw'&gt;when&lt;/span&gt;&amp;nbsp;peek&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;'/'&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;Comment&lt;span class='op'&gt;(&lt;/span&gt;read&amp;nbsp;notNewline&amp;nbsp;&lt;span class='kw'&gt;false&lt;/span&gt;&lt;span class='op'&gt;)&lt;/span&gt;&lt;br&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;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;'&lt;span class='op'&gt;(&lt;/span&gt;'&amp;nbsp;&lt;span class='kw'&gt;when&lt;/span&gt;&amp;nbsp;peek&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;'*'&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;Comment&lt;span class='op'&gt;(&lt;/span&gt;read&amp;nbsp;notBlockEnd&amp;nbsp;&lt;span class='kw'&gt;true&lt;/span&gt;&lt;span class='op'&gt;)&lt;/span&gt;&lt;br&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;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;_&lt;/span&gt;&amp;nbsp;&lt;span class='kw'&gt;when&lt;/span&gt;&amp;nbsp;isWhite&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;readWhite&lt;span class='op'&gt;()&lt;/span&gt;&lt;br&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;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;_&lt;/span&gt;&amp;nbsp;&lt;span class='kw'&gt;when&lt;/span&gt;&amp;nbsp;isOperator&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;readOperator&lt;span class='op'&gt;()&lt;/span&gt;&lt;br&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;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;_&lt;/span&gt;&amp;nbsp;&lt;span class='kw'&gt;when&lt;/span&gt;&amp;nbsp;isNewLine&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;readNewLine&lt;span class='op'&gt;()&lt;/span&gt;&lt;br&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;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;_&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;readWord&lt;span class='op'&gt;()&lt;/span&gt;&lt;br&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;&lt;span class='kw'&gt;yield&lt;/span&gt;&amp;nbsp;token&lt;span class='op'&gt;}&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;ToString&amp;nbsp;x&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;encode&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;&lt;span class='kw'&gt;function&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;Comment&amp;nbsp;&lt;span class='op'&gt;_&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"c"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;Keyword&amp;nbsp;&lt;span class='op'&gt;_&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"k"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;Preprocessor&amp;nbsp;&lt;span class='op'&gt;_&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"p"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;String&amp;nbsp;&lt;span class='op'&gt;_&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"s"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;Text&amp;nbsp;&lt;span class='op'&gt;_&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"t"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;WhiteSpace&amp;nbsp;&lt;span class='op'&gt;_&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"w"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;NewLine&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"n"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;Operator&amp;nbsp;&lt;span class='op'&gt;_&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"o"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;x&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;Seq&lt;span class='op'&gt;.&lt;/span&gt;fold&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;&lt;span class='kw'&gt;fun&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;r&lt;span class='op'&gt;:&lt;/span&gt;StringBuilder&lt;span class='op'&gt;)&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;encode&amp;nbsp;&lt;span class='op'&gt;&gt;&gt;&lt;/span&gt;&amp;nbsp;r&lt;span class='op'&gt;.&lt;/span&gt;Append&lt;span class='op'&gt;)&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;StringBuilder&lt;span class='op'&gt;())&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;string&lt;br&gt;&lt;br&gt;Fact&amp;nbsp;&lt;span class='tx'&gt;"Tokenize&amp;nbsp;should&amp;nbsp;categorize"&lt;/span&gt;&lt;span class='op'&gt;(&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Tokenize&amp;nbsp;&lt;span class='tx'&gt;"#light&amp;nbsp;let&amp;nbsp;foo"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;ToString&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;Should&amp;nbsp;Equal&amp;nbsp;&lt;span class='tx'&gt;"pwkwt"&lt;/span&gt;&lt;span class='op'&gt;)&lt;/span&gt;&lt;br&gt;&lt;br&gt;Fact&amp;nbsp;&lt;span class='tx'&gt;"Tokenize&amp;nbsp;should&amp;nbsp;handle&amp;nbsp;string"&lt;/span&gt;&lt;span class='op'&gt;(&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Tokenize&amp;nbsp;&lt;span class='tx'&gt;"\"Hello&amp;nbsp;World\""&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;ToString&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;Should&amp;nbsp;Equal&amp;nbsp;&lt;span class='tx'&gt;"s"&lt;/span&gt;&lt;span class='op'&gt;)&lt;/span&gt;&lt;br&gt;&lt;br&gt;Fact&amp;nbsp;&lt;span class='tx'&gt;"Tokenize&amp;nbsp;should&amp;nbsp;split&amp;nbsp;string&amp;nbsp;into&amp;nbsp;lines"&lt;/span&gt;&lt;span class='op'&gt;(&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;lines&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;&lt;span class='kw'&gt;function&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;String&amp;nbsp;x&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;x&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;_&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;[||]&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Tokenize&amp;nbsp;&lt;span class='tx'&gt;"\"Hello\r\nWorld\""&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;Seq&lt;span class='op'&gt;.&lt;/span&gt;hd&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;lines&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;Seq&lt;span class='op'&gt;.&lt;/span&gt;length&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;Should&amp;nbsp;Equal&amp;nbsp;2&lt;span class='op'&gt;)&lt;/span&gt;&lt;br&gt;&lt;br&gt;Theory&amp;nbsp;&lt;span class='tx'&gt;"Tokenize&amp;nbsp;should&amp;nbsp;separate&amp;nbsp;start&amp;nbsp;on&amp;nbsp;operators"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;&lt;span class='tx'&gt;"_&amp;nbsp;(&amp;nbsp;)&amp;nbsp;{&amp;nbsp;}&amp;nbsp;&amp;lt;&amp;nbsp;&gt;&amp;nbsp;[&amp;nbsp;]&amp;nbsp;,&amp;nbsp;=&amp;nbsp;|&amp;nbsp;-&amp;nbsp;+&amp;nbsp;:&amp;nbsp;;&amp;nbsp;."&lt;/span&gt;&lt;span class='op'&gt;.&lt;/span&gt;Split&lt;span class='op'&gt;([|&lt;/span&gt;'&amp;nbsp;'&lt;span class='op'&gt;|]))&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;&lt;span class='kw'&gt;fun&lt;/span&gt;&amp;nbsp;x&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;Tokenize&amp;nbsp;x&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;ToString&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;Should&amp;nbsp;Equal&amp;nbsp;&lt;span class='tx'&gt;"o"&lt;/span&gt;&lt;span class='op'&gt;)&lt;/span&gt;&lt;br&gt;&lt;br&gt;Fact&amp;nbsp;&lt;span class='tx'&gt;"Tokenize&amp;nbsp;should&amp;nbsp;end&amp;nbsp;on&amp;nbsp;separators"&lt;/span&gt;&lt;span class='op'&gt;(&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Tokenize&amp;nbsp;&lt;span class='tx'&gt;"foo)"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;ToString&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;Should&amp;nbsp;Equal&amp;nbsp;&lt;span class='tx'&gt;"to"&lt;/span&gt;&lt;span class='op'&gt;)&lt;/span&gt;&lt;br&gt;&lt;br&gt;Fact&amp;nbsp;&lt;span class='tx'&gt;"Tokenize&amp;nbsp;should&amp;nbsp;handle&amp;nbsp;escaped&amp;nbsp;char&amp;nbsp;in&amp;nbsp;string"&lt;/span&gt;&lt;span class='op'&gt;(&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Tokenize&amp;nbsp;&lt;span class='tx'&gt;"\"\\\"\""&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;&amp;nbsp;ToString&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;Should&amp;nbsp;Equal&amp;nbsp;&lt;span class='tx'&gt;"s"&lt;/span&gt;&lt;span class='op'&gt;)&lt;/span&gt;&lt;br&gt;&lt;br&gt;Fact&amp;nbsp;&lt;span class='tx'&gt;"Tokenize&amp;nbsp;should&amp;nbsp;handle&amp;nbsp;//line&amp;nbsp;comment"&lt;/span&gt;&lt;span class='op'&gt;(&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Tokenize&amp;nbsp;&lt;span class='tx'&gt;"//line&amp;nbsp;comment"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;ToString&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;Should&amp;nbsp;Equal&amp;nbsp;&lt;span class='tx'&gt;"c"&lt;/span&gt;&lt;span class='op'&gt;)&lt;/span&gt;&lt;br&gt;&lt;br&gt;Fact&amp;nbsp;&lt;span class='tx'&gt;"Tokenize&amp;nbsp;should&amp;nbsp;handle&amp;nbsp;(*&amp;nbsp;block&amp;nbsp;comments&amp;nbsp;*)"&lt;/span&gt;&lt;span class='op'&gt;(&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Tokenize&amp;nbsp;&lt;span class='tx'&gt;"(*&amp;nbsp;block&amp;nbsp;comment&amp;nbsp;)*)&amp;nbsp;"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;ToString&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;Should&amp;nbsp;Equal&amp;nbsp;&lt;span class='tx'&gt;"cw"&lt;/span&gt;&lt;span class='op'&gt;)&lt;/span&gt;&lt;br&gt;&lt;br&gt;Fact&amp;nbsp;&lt;span class='tx'&gt;"Tokenize&amp;nbsp;should&amp;nbsp;handle&amp;nbsp;newline"&lt;/span&gt;&lt;span class='op'&gt;(&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Tokenize&amp;nbsp;&lt;span class='tx'&gt;"\r\n"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;ToString&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;Should&amp;nbsp;Equal&amp;nbsp;&lt;span class='tx'&gt;"n"&lt;/span&gt;&lt;span class='op'&gt;)&lt;/span&gt;&lt;br&gt;&lt;br&gt;Fact&amp;nbsp;&lt;span class='tx'&gt;"Tokenize&amp;nbsp;should&amp;nbsp;separate&amp;nbsp;whitespace&amp;nbsp;and&amp;nbsp;newline"&lt;/span&gt;&lt;span class='op'&gt;(&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Tokenize&amp;nbsp;&lt;span class='tx'&gt;"&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;\r\n"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;ToString&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;Should&amp;nbsp;Equal&amp;nbsp;&lt;span class='tx'&gt;"wn"&lt;/span&gt;&lt;span class='op'&gt;)&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;Sanitize&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;s&lt;span class='op'&gt;:&lt;/span&gt;string&lt;span class='op'&gt;)&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;s&lt;span class='op'&gt;.&lt;/span&gt;Replace&lt;span class='op'&gt;(&lt;/span&gt;&lt;span class='tx'&gt;"&amp;amp;"&lt;/span&gt;&lt;span class='op'&gt;,&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"&amp;amp;amp;"&lt;/span&gt;&lt;span class='op'&gt;).&lt;/span&gt;Replace&lt;span class='op'&gt;(&lt;/span&gt;&lt;span class='tx'&gt;"&amp;lt;"&lt;/span&gt;&lt;span class='op'&gt;,&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"&amp;amp;lt;"&lt;/span&gt;&lt;span class='op'&gt;).&lt;/span&gt;Replace&lt;span class='op'&gt;(&lt;/span&gt;&lt;span class='tx'&gt;"&amp;nbsp;"&lt;/span&gt;&lt;span class='op'&gt;,&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"&amp;amp;nbsp;"&lt;/span&gt;&lt;span class='op'&gt;)&lt;/span&gt;&lt;br&gt;&lt;br&gt;Fact&amp;nbsp;&lt;span class='tx'&gt;"Sanitize&amp;nbsp;should&amp;nbsp;replace&amp;nbsp;&amp;lt;&amp;nbsp;with&amp;nbsp;&amp;amp;lt;"&lt;/span&gt;&lt;span class='op'&gt;(&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Sanitize&amp;nbsp;&lt;span class='tx'&gt;"&amp;lt;"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;Should&amp;nbsp;Equal&amp;nbsp;&lt;span class='tx'&gt;"&amp;amp;lt;"&lt;/span&gt;&lt;span class='op'&gt;)&lt;/span&gt;&lt;br&gt;&lt;br&gt;Fact&amp;nbsp;&lt;span class='tx'&gt;"Sanitize&amp;nbsp;should&amp;nbsp;repalce&amp;nbsp;&amp;amp;&amp;nbsp;with&amp;nbsp;&amp;amp;amp;"&lt;/span&gt;&lt;span class='op'&gt;(&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Sanitize&amp;nbsp;&lt;span class='tx'&gt;"&amp;amp;"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;Should&amp;nbsp;Equal&amp;nbsp;&lt;span class='tx'&gt;"&amp;amp;amp;"&lt;/span&gt;&lt;span class='op'&gt;)&lt;/span&gt;&lt;br&gt;&lt;br&gt;Fact&amp;nbsp;&lt;span class='tx'&gt;"Sanitize&amp;nbsp;should&amp;nbsp;repalce&amp;nbsp;'&amp;nbsp;'&amp;nbsp;with&amp;nbsp;&amp;amp;nbsp;"&lt;/span&gt;&lt;span class='op'&gt;(&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Sanitize&amp;nbsp;&lt;span class='tx'&gt;"&amp;nbsp;"&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;Should&amp;nbsp;Equal&amp;nbsp;&lt;span class='tx'&gt;"&amp;amp;nbsp;"&lt;/span&gt;&lt;span class='op'&gt;)&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class='kw'&gt;type&lt;/span&gt;&amp;nbsp;IHtmlWriter&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;abstract&lt;/span&gt;&amp;nbsp;Literal&amp;nbsp;&lt;span class='op'&gt;:&lt;/span&gt;&amp;nbsp;string&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;unit&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;abstract&lt;/span&gt;&amp;nbsp;Span&amp;nbsp;&lt;span class='op'&gt;:&lt;/span&gt;&amp;nbsp;string&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;string&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;unit&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;abstract&lt;/span&gt;&amp;nbsp;NewLine&amp;nbsp;&lt;span class='op'&gt;:&lt;/span&gt;&amp;nbsp;unit&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;unit&lt;br&gt;&lt;br&gt;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;HtmlEncode&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;w&lt;span class='op'&gt;:&lt;/span&gt;IHtmlWriter&lt;span class='op'&gt;)&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;span&amp;nbsp;style&amp;nbsp;s&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;w&lt;span class='op'&gt;.&lt;/span&gt;Span&amp;nbsp;style&amp;nbsp;s&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;function&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;Comment&amp;nbsp;x&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;span&amp;nbsp;&lt;span class='tx'&gt;"c"&lt;/span&gt;&amp;nbsp;x&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;Keyword&amp;nbsp;x&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;span&amp;nbsp;&lt;span class='tx'&gt;"kw"&lt;/span&gt;&amp;nbsp;x&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;Preprocessor&amp;nbsp;x&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;span&amp;nbsp;&lt;span class='tx'&gt;"pp"&lt;/span&gt;&amp;nbsp;x&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;String&amp;nbsp;x&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;span&amp;nbsp;&lt;span class='tx'&gt;"tx"&lt;/span&gt;&amp;nbsp;x&lt;span class='op'&gt;.[&lt;/span&gt;0&lt;span class='op'&gt;]&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;for&lt;/span&gt;&amp;nbsp;i&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;1&amp;nbsp;&lt;span class='kw'&gt;to&lt;/span&gt;&amp;nbsp;x&lt;span class='op'&gt;.&lt;/span&gt;Length&amp;nbsp;&lt;span class='op'&gt;-&lt;/span&gt;&amp;nbsp;1&amp;nbsp;&lt;span class='kw'&gt;do&lt;/span&gt;&lt;br&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;w&lt;span class='op'&gt;.&lt;/span&gt;NewLine&lt;span class='op'&gt;()&lt;/span&gt;&lt;br&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;span&amp;nbsp;&lt;span class='tx'&gt;"tx"&lt;/span&gt;&amp;nbsp;x&lt;span class='op'&gt;.[&lt;/span&gt;i&lt;span class='op'&gt;]&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;Operator&amp;nbsp;x&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;span&amp;nbsp;&lt;span class='tx'&gt;"op"&lt;/span&gt;&amp;nbsp;x&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;Text&amp;nbsp;x&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;WhiteSpace&amp;nbsp;x&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;w&lt;span class='op'&gt;.&lt;/span&gt;Literal&amp;nbsp;x&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;|&lt;/span&gt;&amp;nbsp;NewLine&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;w&lt;span class='op'&gt;.&lt;/span&gt;NewLine&lt;span class='op'&gt;()&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;AsHtml&amp;nbsp;s&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;r&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;StringBuilder&lt;span class='op'&gt;(&lt;/span&gt;&lt;span class='tx'&gt;"&amp;lt;div&amp;nbsp;class='f-sharp'&gt;"&lt;/span&gt;&lt;span class='op'&gt;)&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;encode&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;HtmlEncode&amp;nbsp;&lt;span class='op'&gt;{&lt;/span&gt;&lt;span class='kw'&gt;new&lt;/span&gt;&amp;nbsp;IHtmlWriter&amp;nbsp;&lt;span class='kw'&gt;with&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;member&lt;/span&gt;&amp;nbsp;this&lt;span class='op'&gt;.&lt;/span&gt;Literal&amp;nbsp;s&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;r&lt;span class='op'&gt;.&lt;/span&gt;Append&lt;span class='op'&gt;(&lt;/span&gt;Sanitize&amp;nbsp;s&lt;span class='op'&gt;)&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;ignore&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;member&lt;/span&gt;&amp;nbsp;this&lt;span class='op'&gt;.&lt;/span&gt;Span&amp;nbsp;c&amp;nbsp;s&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;r&lt;span class='op'&gt;.&lt;/span&gt;AppendFormat&lt;span class='op'&gt;(&lt;/span&gt;&lt;span class='tx'&gt;"&amp;lt;span&amp;nbsp;class='{0}'&gt;{1}&amp;lt;/span&gt;"&lt;/span&gt;&lt;span class='op'&gt;,&lt;/span&gt;&amp;nbsp;c&lt;span class='op'&gt;,&lt;/span&gt;&amp;nbsp;Sanitize&amp;nbsp;s&lt;span class='op'&gt;)&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;ignore&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;member&lt;/span&gt;&amp;nbsp;this&lt;span class='op'&gt;.&lt;/span&gt;NewLine&lt;span class='op'&gt;()&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;r&lt;span class='op'&gt;.&lt;/span&gt;Append&lt;span class='op'&gt;(&lt;/span&gt;&lt;span class='tx'&gt;"&amp;lt;br&gt;"&lt;/span&gt;&lt;span class='op'&gt;)&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;ignore&lt;span class='op'&gt;}&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;Tokenize&amp;nbsp;s&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;Seq&lt;span class='op'&gt;.&lt;/span&gt;iter&amp;nbsp;encode&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;string&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;r&lt;span class='op'&gt;.&lt;/span&gt;Append&lt;span class='op'&gt;(&lt;/span&gt;&lt;span class='tx'&gt;"&amp;lt;/div&gt;"&lt;/span&gt;&lt;span class='op'&gt;))&lt;/span&gt;&lt;br&gt;&lt;br&gt;Fact&amp;nbsp;&lt;span class='tx'&gt;"AsHtml&amp;nbsp;sample"&lt;/span&gt;&lt;span class='op'&gt;(&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;sample&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;"#light\r\nlet&amp;nbsp;numbers&amp;nbsp;=&amp;nbsp;[1..10]"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='kw'&gt;let&lt;/span&gt;&amp;nbsp;expected&amp;nbsp;&lt;span class='op'&gt;=&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;String&lt;span class='op'&gt;.&lt;/span&gt;Concat&amp;nbsp;&lt;span class='op'&gt;[|&lt;/span&gt;&lt;span class='tx'&gt;"&amp;lt;div&amp;nbsp;class='f-sharp'&gt;&amp;lt;span&amp;nbsp;class='pp'&gt;#light&amp;lt;/span&gt;&amp;lt;br&gt;"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;;&lt;/span&gt;&lt;span class='tx'&gt;"&amp;lt;span&amp;nbsp;class='kw'&gt;let&amp;lt;/span&gt;&amp;amp;nbsp;numbers&amp;amp;nbsp;&amp;lt;span&amp;nbsp;class='op'&gt;=&amp;lt;/span&gt;&amp;amp;nbsp;"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;;&lt;/span&gt;&lt;span class='tx'&gt;"&amp;lt;span&amp;nbsp;class='op'&gt;[&amp;lt;/span&gt;1&amp;lt;span&amp;nbsp;class='op'&gt;..&amp;lt;/span&gt;"&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;span class='op'&gt;;&lt;/span&gt;&lt;span class='tx'&gt;"10&amp;lt;span&amp;nbsp;class='op'&gt;]&amp;lt;/span&gt;&amp;lt;/div&gt;"&lt;/span&gt;&lt;span class='op'&gt;|]&lt;/span&gt;&lt;br&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;sample&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;AsHtml&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;Should&amp;nbsp;Equal&amp;nbsp;expected&lt;span class='op'&gt;)&lt;/span&gt;&lt;br&gt;&lt;br&gt;&lt;span class='c'&gt;//Render&amp;nbsp;myself.&lt;/span&gt;&lt;br&gt;File&lt;span class='op'&gt;.&lt;/span&gt;ReadAllText&lt;span class='op'&gt;(__&lt;/span&gt;SOURCE&lt;span class='op'&gt;_&lt;/span&gt;FILE&lt;span class='op'&gt;__)&lt;/span&gt;&lt;br&gt;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;AsHtml&amp;nbsp;&lt;span class='op'&gt;|&gt;&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;(&lt;/span&gt;&lt;span class='kw'&gt;fun&lt;/span&gt;&amp;nbsp;x&amp;nbsp;&lt;span class='op'&gt;-&gt;&lt;/span&gt;&amp;nbsp;File&lt;span class='op'&gt;.&lt;/span&gt;WriteAllText&lt;span class='op'&gt;(__&lt;/span&gt;SOURCE&lt;span class='op'&gt;_&lt;/span&gt;FILE&lt;span class='op'&gt;__&lt;/span&gt;&amp;nbsp;&lt;span class='op'&gt;+&lt;/span&gt;&amp;nbsp;&lt;span class='tx'&gt;".html"&lt;/span&gt;&lt;span class='op'&gt;,&lt;/span&gt;&amp;nbsp;x&lt;span class='op'&gt;))&lt;/span&gt;&lt;/div&gt;
As outputed from itself. I really like how "Fact" and "Theory" turned out and it seems to suite my current needs just fine.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-5012101127242298046?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/5012101127242298046/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/02/taking-pencilunit-for-spin-f-syntax_8740.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/5012101127242298046'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/5012101127242298046'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/02/taking-pencilunit-for-spin-f-syntax_8740.html' title='Taking Pencil.Unit for a spin, F# syntax highlighting.'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-6535017871934335944</id><published>2009-01-30T13:22:00.002+01:00</published><updated>2009-01-30T13:25:35.548+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cheese'/><category scheme='http://www.blogger.com/atom/ns#' term='silly'/><category scheme='http://www.blogger.com/atom/ns#' term='F#'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='pizza'/><title type='text'>Fact about Pizza.</title><content type='html'>I find this test as amusing as it's silly:
&lt;PRE&gt;&lt;FONT COLOR="#ff8000"&gt;#light&lt;/FONT&gt;

&lt;FONT COLOR="#6464b4"&gt;open &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;Pencil.Unit&lt;/FONT&gt;

&lt;FONT COLOR="#000000"&gt;Fact &lt;/FONT&gt;&lt;FONT COLOR="#981040"&gt;&amp;quot;Pizza should have cheese.&amp;quot;&lt;/FONT&gt;
    &lt;FONT COLOR="#ff8000"&gt;(&lt;/FONT&gt;&lt;FONT COLOR="#981040"&gt;&amp;quot;Pizza&amp;quot; &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;|&amp;gt; &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;Should &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;(&lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;Contain &lt;/FONT&gt;&lt;FONT COLOR="#981040"&gt;&amp;quot;Cheese&amp;quot;&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;))&lt;/FONT&gt;&lt;/PRE&gt;

And the output:
&lt;pre&gt;Pizza should have cheese. Failed with "Pizza" doesn't contain "Cheese".&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-6535017871934335944?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/6535017871934335944/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/01/fact-about-pizza.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/6535017871934335944'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/6535017871934335944'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/01/fact-about-pizza.html' title='Fact about Pizza.'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-6410032394641045534</id><published>2009-01-30T07:32:00.002+01:00</published><updated>2009-01-30T07:45:24.096+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='clean'/><category scheme='http://www.blogger.com/atom/ns#' term='craftmanship'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><category scheme='http://www.blogger.com/atom/ns#' term='crap'/><title type='text'>Craftmanship over Crap</title><content type='html'>Uncle Bob makes a compelling case for adding one more value to the &lt;a href="http://agilemanifesto.org/"&gt;Agile Manifesto&lt;/a&gt;, initially and for effect it was "Craftmanship over Crap" he later changed it to the less dramatic "Craftmanship over Execution" and asked others if they could find an even better phrasing and many good points were raised, for the full story look &lt;a href="http://blog.objectmentor.com/articles/2008/08/14/quintessence-the-fifth-element-for-the-agile-manifesto"&gt;here&lt;/a&gt;.

I've been mulling over this a bit, looking at the proposals and in the meantime hoping that my &lt;a href="http://butunclebob.com/ArticleS.UncleBob.GreenWristBand"&gt;green wristband&lt;/a&gt; will guide me, but then it struck me. The original formulation is from a clean code perspective absolutley perfect, with one minor detail. It's not Crap the word, it's CRAP the acronym, and that's a honest misstake. Let's look a bit closer CRAP is &lt;span style="font-weight:bold;"&gt;Coupled Redundant Arbitrary Duplication&lt;/span&gt; and in essence that's exectly the anti-thesis of clean code.

The marvelous thing about it is that even the acronym in itself exhibits a distinctly CRAP quality. 

Coupled because it doesn't make sense without the other parts. 
Redundant because it duplicates what crap is. 
Arbitrary since it could be something else. 
Duplication is redundant.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-6410032394641045534?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/6410032394641045534/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/01/craftmanship-over-crap.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/6410032394641045534'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/6410032394641045534'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/01/craftmanship-over-crap.html' title='Craftmanship over Crap'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-8259562250434287128</id><published>2009-01-27T16:03:00.004+01:00</published><updated>2009-01-27T16:31:52.326+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='UnitTests'/><category scheme='http://www.blogger.com/atom/ns#' term='F#'/><title type='text'>Minimal Unit Tests in F#</title><content type='html'>It's easy to get caught up in always building bigger, cooler more complex thingmajigs. Sometimes we forget our roots, take Unit Testing for exmaple, there's numerous frameworks and doodahs to facilitate that, but how slim and still provide value could it be. Over a cup of hot cacao I decided to find out. 
Here's the result:

&lt;PRE&gt;&lt;FONT COLOR="#ff8000"&gt;#light&lt;/FONT&gt;

&lt;FONT COLOR="#6464b4"&gt;namespace &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;Pencil.Unit&lt;/FONT&gt;

&lt;FONT COLOR="#6464b4"&gt;open &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;System&lt;/FONT&gt;
&lt;FONT COLOR="#6464b4"&gt;open &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;System.Diagnostics&lt;/FONT&gt;
&lt;FONT COLOR="#6464b4"&gt;open &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;System.Collections.Generic&lt;/FONT&gt;

&lt;FONT COLOR="#6464b4"&gt;type &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;IMatcher &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;=&lt;/FONT&gt;
    &lt;FONT COLOR="#6464b4"&gt;abstract &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;Match&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;&amp;lt;&lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;'a&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;&amp;gt; : &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;'a &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;-&amp;gt; &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;'a &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;-&amp;gt; &lt;/FONT&gt;&lt;FONT COLOR="#7ba402"&gt;bool&lt;/FONT&gt;
    &lt;FONT COLOR="#6464b4"&gt;abstract &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;Format&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;&amp;lt;&lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;'a&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;&amp;gt; : &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;'a &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;-&amp;gt; &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;'a &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;-&amp;gt; &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;string&lt;/FONT&gt;

&lt;FONT COLOR="#6464b4"&gt;module &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;Unit &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;=&lt;/FONT&gt;
    &lt;FONT COLOR="#6464b4"&gt;let &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;(|&amp;gt;) &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;x f &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;= &lt;/FONT&gt;&lt;FONT COLOR="#6464b4"&gt;let &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;r &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;= &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;f x &lt;/FONT&gt;&lt;FONT COLOR="#6464b4"&gt;in &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;r &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;|&amp;gt; &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;ignore; r &lt;/FONT&gt;&lt;FONT COLOR="#008000"&gt;//work-around for broken debug info.&lt;/FONT&gt;
    &lt;FONT COLOR="#6464b4"&gt;let mutable &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;Count &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;= &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;0&lt;/FONT&gt;
    &lt;FONT COLOR="#6464b4"&gt;let &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;Errors &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;= &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;List&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;&amp;lt;&lt;/FONT&gt;&lt;FONT COLOR="#7ba402"&gt;String&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;&amp;gt;()&lt;/FONT&gt;
    &lt;FONT COLOR="#6464b4"&gt;let &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;Should &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;(&lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;matcher&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;:&lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;IMatcher&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;) = &lt;/FONT&gt;&lt;FONT COLOR="#6464b4"&gt;fun &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;e a &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;-&amp;gt;&lt;/FONT&gt;
        &lt;FONT COLOR="#000000"&gt;Count &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;&amp;lt;- &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;Count &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;+ &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;1&lt;/FONT&gt;
        &lt;FONT COLOR="#6464b4"&gt;if &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;matcher.Match e a &lt;/FONT&gt;&lt;FONT COLOR="#6464b4"&gt;then&lt;/FONT&gt;
            &lt;FONT COLOR="#000000"&gt;Console.Write&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;(&lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;'.'&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;)&lt;/FONT&gt;
        &lt;FONT COLOR="#6464b4"&gt;else&lt;/FONT&gt;
            &lt;FONT COLOR="#6464b4"&gt;let &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;frame &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;= &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;StackTrace&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;(&lt;/FONT&gt;&lt;FONT COLOR="#6464b4"&gt;true&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;)&lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;.GetFrame&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;(&lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;1&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;)&lt;/FONT&gt;
            &lt;FONT COLOR="#6464b4"&gt;let &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;trace &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;= &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;String.Format&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;(&lt;/FONT&gt;&lt;FONT COLOR="#981040"&gt;&amp;quot; ({0}({1}))&amp;quot;&lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;,&lt;/FONT&gt;
                &lt;FONT COLOR="#000000"&gt;frame.GetFileName&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;()&lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;,&lt;/FONT&gt;
                &lt;FONT COLOR="#000000"&gt;frame.GetFileLineNumber&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;())&lt;/FONT&gt;
            &lt;FONT COLOR="#000000"&gt;Console.Write&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;(&lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;'F'&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;)&lt;/FONT&gt;
            &lt;FONT COLOR="#000000"&gt;Errors.Add&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;((&lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;matcher.Format e a&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;) + &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;trace&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;)&lt;/FONT&gt;

    &lt;FONT COLOR="#6464b4"&gt;let &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;Equal &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;= {&lt;/FONT&gt;
        &lt;FONT COLOR="#6464b4"&gt;new &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;IMatcher &lt;/FONT&gt;&lt;FONT COLOR="#6464b4"&gt;with&lt;/FONT&gt;
            &lt;FONT COLOR="#6464b4"&gt;member &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;x.Match e a &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;= &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;a.Equals&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;(&lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;e&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;)&lt;/FONT&gt;
            &lt;FONT COLOR="#6464b4"&gt;member &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;x.Format e a &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;=&lt;/FONT&gt;
                &lt;FONT COLOR="#000000"&gt;String.Format&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;(&lt;/FONT&gt;&lt;FONT COLOR="#981040"&gt;&amp;quot;Expected:{0}, Actual:{1}&amp;quot;&lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;, e, a&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;)}&lt;/FONT&gt;
&lt;FONT COLOR="#6464b4"&gt;open &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;Unit&lt;/FONT&gt;
&lt;FONT COLOR="#008000"&gt;//Tests goes here&lt;/FONT&gt;
&lt;FONT COLOR="#000000"&gt;2 &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;* &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;4 &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;|&amp;gt; &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;Should Equal 8&lt;/FONT&gt;
&lt;FONT COLOR="#000000"&gt;2 &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;+ &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;1 &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;|&amp;gt; &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;Should Equal 2&lt;/FONT&gt;

&lt;FONT COLOR="#008000"&gt;//Report the result&lt;/FONT&gt;
&lt;FONT COLOR="#000000"&gt;Console.WriteLine&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;(&lt;/FONT&gt;&lt;FONT COLOR="#981040"&gt;&amp;quot;{2}{2}{0} tests run, {1} failed.&amp;quot;&lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;, Count, Errors.Count, Environment.NewLine&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;)&lt;/FONT&gt;
&lt;FONT COLOR="#6464b4"&gt;if &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;Errors.Count &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;&amp;lt;&amp;gt; &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;0 &lt;/FONT&gt;&lt;FONT COLOR="#6464b4"&gt;then&lt;/FONT&gt;
    &lt;FONT COLOR="#000000"&gt;Errors &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;|&amp;gt; &lt;/FONT&gt;&lt;FONT COLOR="#5f0551"&gt;Seq.iter&lt;/FONT&gt;
        &lt;FONT COLOR="#ff8000"&gt;(&lt;/FONT&gt;&lt;FONT COLOR="#6464b4"&gt;fun &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;e &lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;-&amp;gt; &lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;Console.WriteLine&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;(&lt;/FONT&gt;&lt;FONT COLOR="#981040"&gt;&amp;quot;{0}&amp;quot;&lt;/FONT&gt;&lt;FONT COLOR="#000000"&gt;, e&lt;/FONT&gt;&lt;FONT COLOR="#ff8000"&gt;))&lt;/FONT&gt;&lt;/PRE&gt;
And the output from the above:
&lt;pre&gt;.F

2 tests run, 1 failed.
(Expected:2, Actual:3 (F:\Pencil.Unit.fs(34))&lt;/pre&gt;

Less than 40 lines of F# and we're on our way to unit testing goodness.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-8259562250434287128?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/8259562250434287128/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/01/minimal-unit-tests-in-f.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/8259562250434287128'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/8259562250434287128'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/01/minimal-unit-tests-in-f.html' title='Minimal Unit Tests in F#'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-4730214522240622671</id><published>2009-01-26T20:58:00.003+01:00</published><updated>2009-01-26T21:03:31.809+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='users'/><category scheme='http://www.blogger.com/atom/ns#' term='business value'/><category scheme='http://www.blogger.com/atom/ns#' term='done'/><title type='text'>Why done should be "in use".</title><content type='html'>Done. Funny word that. When is something done? 
Is it when it's checked into version control? 
When is passes all our autmated acceptance tests?
When QA says so? 
Or is it when we got real users deriving value from it? 

I would say the later based upon this simple observation.
As a user theese things are all equal:
* Feature not implemented.
* Feature not deployed.
* Don't know about the feature.
* Can't find the feature.

The implication is that unless we figure out how to build, deploy and educate users we simply haven't delivered busniess value. 

Scary isn't it?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-4730214522240622671?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/4730214522240622671/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/01/why-done-should-be-in-use.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/4730214522240622671'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/4730214522240622671'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/01/why-done-should-be-in-use.html' title='Why done should be &quot;in use&quot;.'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-2519989647922915184</id><published>2009-01-15T16:13:00.003+01:00</published><updated>2009-01-15T16:36:32.774+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='C#'/><category scheme='http://www.blogger.com/atom/ns#' term='IDisposable'/><title type='text'>Falling into the pit of success, by design.</title><content type='html'>&lt;a href="http://www.codinghorror.com/blog/archives/001211.html"&gt;Jeff doesn't care&lt;/a&gt; about resource cleanups. And I can agree to some part,but the problem is that his solution "forget it and write an article making fun of overzealous disposers" seems a bit, well, short sighted. 

The thing is that I agree on the point that it's silly that our best mainstream "solution" to disposal thusfar is "using". Now, come on the best we could do was invent sugar so that our try finally blocks looks prettier? 

Let us have a quick look at the problem using File instead of SqlConnections, the semantics are the same but it's possible to illustrate something that people actually do with fewer lines using it. It seems that Jeff thinks that we should be fine with doing this:
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; JeffIsWingingIt()
{
    var target = File.CreateText(&lt;span class="str"&gt;"output.file"&lt;/span&gt;);
    target.WriteLine(&lt;span class="str"&gt;"Very important stuff."&lt;/span&gt;);
}&lt;/pre&gt;

The sad part here is that code like this often *seems* to be working but in reality quite often you'll end up with truncated output and a long hunt to find the responsible party. 

So the correct version looks like this:
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; CorrectButNoFun()
{
    &lt;span class="kwrd"&gt;using&lt;/span&gt;(var target = File.CreateText(&lt;span class="str"&gt;"output.file2"&lt;/span&gt;))
        target.WriteLine(&lt;span class="str"&gt;"Very important stuff."&lt;/span&gt;);
}&lt;/pre&gt;

Sadly that not at all as appealing, but at least we get all the data written to disk and the file handle reclaimed in an orderly matter. But I would say the API is to blame in this case, it encourages us to do the wrong thing (forgetting to Dispose when done). There's quite easy to fix this and make it like this instead.
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; DesignedForSuccess()
{
    FileUtil.Write(&lt;span class="str"&gt;"output.file3"&lt;/span&gt;,
        target =&amp;gt; target.WriteLine(&lt;span class="str"&gt;"Very important stuff."&lt;/span&gt;));
}

&lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; FileUtil
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Write(&lt;span class="kwrd"&gt;string&lt;/span&gt; path,
    Action&amp;lt;TextWriter&amp;gt; action)
    {
        &lt;span class="kwrd"&gt;using&lt;/span&gt;(var file = File.CreateText(path))
            action(file);
    }
}&lt;/pre&gt;

Here resource handling and work are cleanly separated and abstracted. Using a similar approach you can easily and safely work with SqlConnection,SqlCommand,SqlDataReader and a huge varaity of other error prone but Disposable classes. 

Once and only once. Don't repeat yourself. It applies to resource handling to.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-2519989647922915184?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/2519989647922915184/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/01/falling-into-pit-of-success-by-design.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/2519989647922915184'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/2519989647922915184'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/01/falling-into-pit-of-success-by-design.html' title='Falling into the pit of success, by design.'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-3885869680485301395</id><published>2009-01-15T09:56:00.006+01:00</published><updated>2009-01-15T10:23:27.208+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='bug'/><category scheme='http://www.blogger.com/atom/ns#' term='fix'/><title type='text'>Fixing a bug, more than a local hack.</title><content type='html'>This is the true story of a bug, and the process of solving it. 
For reasons not relevant to the discussion I had the need to determine if a given 'Type' was part of the "System" namespace and hence could be considred a Framework type, it was deemed enough that just checking that the full name began with "System." was good enough for our purpose. 

The implementation is obvious and self-explanatory: 
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsFrameworkType(Type type)
{
        &lt;span class="kwrd"&gt;return&lt;/span&gt; type.FullName.StartsWith(&lt;span class="str"&gt;"System."&lt;/span&gt;);
}&lt;/pre&gt;

Simple elegant and to the point. But since I said this was the story of a bug something went astray. The thing is that under certain quite arcane circumstances "Type.FullName" can return null, the details aren't really important, the problem is that the code above crashes with a NullReferenceException if that happens. And that's important for me since then I won't get to see the result of my program run.

The quick, obvious fix is to check for null. As seen below:
&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsFrameworkType(Type type)
{
        var name = type.FullName;
        &lt;span class="kwrd"&gt;return&lt;/span&gt; name != &lt;span class="kwrd"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; name.StartsWith(&lt;span class="str"&gt;"System."&lt;/span&gt;);
}&lt;/pre&gt;

And that's how the majority of bugs get "fixed", a local fix at the point of failiure, a pat on the back for a now passing test and away we dart to the next challange. And that I  think is part of the problem why software takes so long. 
If we keep our local focus what can we do to both fix this bug and design safety in? 
We can reengineer our API to handle this gracefully. In languages with open classes we could fix our string API, in C# we have extension methods and if we work in an environment without them utility classes and free functions can aid us. 
So what's the root cause here?
I would say that "StartsWith" is the culprit in this case. Because we know that we will have something to check against "System.", but we're not sure that we have a target for our StartsWith call. For this situation "System.".IsStartOf would make more sense, since that way we know that we have a instance to start with. 
Using extension methods we arrive at this:

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; StringExtensions
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsStartOf(&lt;span class="kwrd"&gt;this&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; prefix, &lt;span class="kwrd"&gt;string&lt;/span&gt; s)
    {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; s != &lt;span class="kwrd"&gt;null&lt;/span&gt; &amp;amp;&amp;amp; s.StartsWith(prefix);
    }
}

&lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; IsFrameworkType(Type type)
{
        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="str"&gt;"System."&lt;/span&gt;.IsStartOf(type.FullName);
}&lt;/pre&gt;

Hunting through the code-base I found a couple of other places where this could be used to solve similar problems.

How often do you take this extra step to not only fix the problem locally but ponder if you can modify the API or system to prevent it from happening somewhere else? 
Make it part of your routine, and you're one "why" closer to a clean and productive code base. 

Further analysis also made it possible to ensure that all types that eventually got sent to this function indeed did have proper FullNames. But that's another story.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-3885869680485301395?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/3885869680485301395/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/01/fixing-bug-more-than-local-hack.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/3885869680485301395'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/3885869680485301395'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/01/fixing-bug-more-than-local-hack.html' title='Fixing a bug, more than a local hack.'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-1016417066099241645</id><published>2009-01-10T10:06:00.003+01:00</published><updated>2009-01-10T10:13:25.571+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='comments'/><category scheme='http://www.blogger.com/atom/ns#' term='version control'/><category scheme='http://www.blogger.com/atom/ns#' term='habit'/><title type='text'>How to write a good commit comment.</title><content type='html'>When using version control one common problem area are the dreaded commit comments. Most teams and individuals seems to gravitate towards simply not using them, wich is really sad. 
My best advice to remedy this situation is really really simple. Don't write your commit comment after you done your changes, write it *before* you start working, that way you already have it done when you're done, and you get the added benefit of clearly articulating what you're currently working on. 

As Stephen Covey puts it "Begin with the end in mind.", it's true for highly successfull people, it ought to be true for highly successfull programmers.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-1016417066099241645?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/1016417066099241645/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/01/how-to-write-good-commit-comment.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/1016417066099241645'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/1016417066099241645'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/01/how-to-write-good-commit-comment.html' title='How to write a good commit comment.'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-4621047770343380150</id><published>2009-01-08T14:00:00.003+01:00</published><updated>2009-02-03T13:28:03.247+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quality'/><category scheme='http://www.blogger.com/atom/ns#' term='theory'/><category scheme='http://www.blogger.com/atom/ns#' term='clean'/><category scheme='http://www.blogger.com/atom/ns#' term='code'/><title type='text'>Clean Code and Mom</title><content type='html'>&lt;p&gt;If you've ever seen a code rot you know that few substances can so quickly go from shining examples of good to festering bug infested piles that everyone is affraid to touch. Why does this happen and what can we do to combat it? 
&lt;/p&gt;&lt;p&gt;
There's much good advice out there for prevention, "Clean Code" by Robert C Martin is a good starting point and if things have already begun to stink have a look at Micheal Feathers "Working Effectivly Witch Legacy Code". They're well worth your time but since you're reading a blog Im guessing that right now you're searching for a quick snack. 
&lt;/p&gt;&lt;p&gt;
It's quite easy to explain how we manage to get ourselves into this mess and basicly it's one portion human nature and an equal serving of wisdom from mom. 
&lt;/p&gt;&lt;p&gt;
&lt;span style="font-weight:bold;"&gt;We follow examples.&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;
As humans and developers we're extremly good at following examples, it's what we've evolved and trained to do. We learn to talk and behave by following the examples of our parents and peers, we aquire new skills by copying those who mastered them before us and we invent new ideas most of the time by missunderstanding something we set out to copy. Based on this it's deceptivly simple to conclude that in theory achiving and maintaining high code quality should simply be a matter of establishing a good set of practices and have people learn from and copy them. And as far as theory goes Im quite sure that it does actually hold true, apart from when it doesn't, and in practice that is most of the time.  
&lt;/p&gt;&lt;p&gt;
Why does such a wonderull theory fail so miserably in practice? We could speculate that it's becuase we don't provide the right examples, or that people are ignorant of the wonderful code we've written and therefore doesn't emulate our flawless style. Or could it be that they simply lack the skill and aptitude for it? There's probably truth to be found in all of theese but I find it easier to lean on what mom used to tell me when I was little.
&lt;/p&gt;&lt;p&gt;
&lt;span style="font-weight:bold;"&gt;You become what you eat.
&lt;/span&gt;
Now before you dismiss me by saying that this actually reinforces the previous point (wich would be true) the underlying assumption in that dissmissal would be that we on average eat high quality code. If that was the case bad stinking code with wtf/minute ratios approaching positive infinity would not be a problem. Basicly I think the core problem is that most of the code we work with on a daily basis through maintenance and enhancement is the code that didn't work right! In any given codebase changes and work tend to cluster in the worst written, badly designed pockets of crap to ever compile and that's where we send our young and untrained. They come out of it producing sub-par code from the bad examples that have now ingrained their previously healthy minds, the examples they've seen are all terrible examples of what not to do. With experience we can learn to see the differance, we become hardened and learn that the code we see most often are the examples to not follow, we go on expiditions to find the code that have been working and elegantly solving our needs without us even realizing it was there, and we learn to emulate that. 
&lt;/p&gt;&lt;p&gt;
So how does this answer the question how things can go so fast downhill? The answer is that on average people will produce code looking quite much what they last saw. Most of the code people see is horrible that's why they're staring at it. As the amount of bad code increases so does the probability of seeing bad code. 
&lt;/p&gt;&lt;p&gt;
How to break the cycle is left as an exercise for the reader.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-4621047770343380150?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/4621047770343380150/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/01/clean-code-and-mom.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/4621047770343380150'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/4621047770343380150'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2009/01/clean-code-and-mom.html' title='Clean Code and Mom'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-6912581198478070057</id><published>2008-11-27T10:31:00.003+01:00</published><updated>2009-02-03T13:28:51.452+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='BDD'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='MoSCoW'/><title type='text'>Take your system for a SWiM</title><content type='html'>Marcus Ahnve voiced some intresting thoughts about 'should' and BDD in his post &lt;a href="http://marcus.ahnve.net/2008/11/26/words-dont-come-easy-moscow-and-bdd/"&gt;"Words dont come easy: MoSCov and BDD"&lt;/a&gt;. Here's a few follow-up thoughts.
&lt;p&gt;
Since we write tests mainly for two reasons, to validate that we built something right, and often even more important, that we built the right thing. We often seek answers along the lines of, how does this class or compononent work? How do I use it? What precondition must be fullfilled? In short, we want answers. 
&lt;/p&gt;&lt;p&gt;
I propse we learn our tests to SWiM! 
&lt;/p&gt;&lt;p&gt;
&lt;span style="font-weight:bold;"&gt;S(hould)&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;
The SUT should do something, the core of BDD. "The index page SHOULD have the title...".  Great for starting conversations, discussion friendly since it's a quite soft expression that's easy to question with a simple "should it really?".
&lt;/p&gt;&lt;p&gt;
&lt;span style="font-weight:bold;"&gt;W(on't)&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;
The SUT simply shouldn't do this. "Reading the same item twice WON'T cause multiple database calls." Good for thoose "Should not" moments. 
&lt;/p&gt;&lt;p&gt;
&lt;span style="font-weight:bold;"&gt;i(nstruct) &lt;/span&gt;
&lt;/p&gt;&lt;p&gt;
How do I use this component? Learning tests, code samples and the like qualify. Capturing small scenarios as tests can be a nice way to spread knowledge on how to use the SUT, show best practice's and document often raised questions.
&lt;/p&gt;&lt;p&gt;
&lt;span style="font-weight:bold;"&gt;M(ust)&lt;/span&gt;
&lt;/p&gt;&lt;p&gt;
The SUT must always do this, "Authentication MUST fail if given the wrong username and password".
&lt;/p&gt;&lt;p&gt;
As Marcus points out in his comments "BDD is all about conversation" good conversations need strong and shared vocabularies.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-6912581198478070057?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/6912581198478070057/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2008/11/take-your-system-for-swim.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/6912581198478070057'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/6912581198478070057'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2008/11/take-your-system-for-swim.html' title='Take your system for a SWiM'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-4988670965309258707.post-2575026912056839524</id><published>2008-11-17T09:52:00.007+01:00</published><updated>2009-02-03T13:29:35.673+01:00</updated><title type='text'>Scrum ate my baby!</title><content type='html'>Parts of the agile blogosphere is ablaze with a heated debate on the topic if Agile is failing, and if it is, shoulde we all just blame Scrum?
&lt;p&gt;
James Shore posted &lt;a href="http://jamesshore.com/Blog/The-Decline-and-Fall-of-Agile.html"&gt;"The Deciline and Fall of Agile"&lt;/a&gt; not really denouncing Scrum, others have been pointing at it for some time now, and Robert C(raft manship over Crap) Martin has replied to much of the debacle with the witty 
&lt;a href="http://blog.objectmentor.com/articles/2008/11/16/dirty-rotten-scrumdrels"&gt;"Dirty Rotten Scrumdrels"&lt;/a&gt; putting blame where it belongs right smack in our own laps. 
&lt;/p&gt;&lt;p&gt;
Someone left a comment with "Scrum is the VB of Agile" a utterance that actually deserves some exploration.
&lt;/p&gt;&lt;p&gt;
What they share is that they took something complex, hard and arcane, creating rich UI applciations and Agile respectivly. And made it approacable for the so called unwashed masses.
I've seen people without programming experience build their first usefull applications mere hours after installing VB, and I've seen well meaning people skim a Scrum brouschure and then going of to lead an Agile, no SCRUM! transition. Neither turned out maintenable or sustainable in the long run. 
&lt;/p&gt;&lt;p&gt;
Strange that.
&lt;/p&gt;&lt;p&gt;
Where they differ is that VB was basicly from the ground up designed for novice users in mind, Scrum on the other hand can argubly be called an expert system.
Scrum is most often presented like "Do things that work!", if you got a bit longer attention span it's more like "Do more of what works, and STOP doing stupid stuff we know doesn't work." for thoose really instrested a catalouge of simple (as Chess and Othello) princiles are given that have proven their worth for a good bit over 20years. Scrum doesn't tell you to eat brakefast (a generally good advice nontheless) and it doesn't have a prescription on how to figure out what to really build, it simply states in essence that the Prouct Owner is resoponsible for the viability, marketabillity and vision of the product.
&lt;/p&gt;&lt;p&gt;
Now, that's a hard problem by any means and it's given about two sentences in the offical Scrum litterature, you're supposed to look at your situation, your experience and the countless tomes written on Use Cases, User Stories, segmentation etc to achive the goal of actually knowin' where you're goin'. 
&lt;/p&gt;&lt;p&gt;
Scrum tells you to deliver working, shippable software every iteration. It doesn't tell you how to actually achive that, and that's the beauty of it. It's also what makes it insanly hard and why people are basicly setting them selves up for disaster when proclaming "We'll do Scrum and all our problems will vanish!".
Thus, uncle Bob is right, we can't blame Scrum, it's like trying to blame the sane albeit open advice of "Do what works!". 
&lt;/p&gt;&lt;p&gt;
The problem with Scrum and much of how it's marketed is that in relation to the Shu-Ha-Ri model it is most often communicated on a "Ri" or fluent level it's a framework built on philosophy and basicly that's why there's such intense discussion and so many pleas for help in the practical things. That's also what makes "Scrum and XP from the Trenches" such a valuable book for many, it's author calls it "Sample code for doing Scrum and XP" it's a code sample not the only way, but it's often cited as a definitive refrence on the one way to do things. Simply because it's the most readable and readily available book with both concrete advice and Scrum in it's name. Other methodologies like Kent Becks XP and Alastair Cockburns Crystal family does communicate in a broader way catering to both beginners needing practices and procedures and giving experienced users the needed background to understand why they work. 
&lt;/p&gt;&lt;p&gt;
The community and our proffession needs to grow up, there's no easy way to greatness, there's no silver bullet, and nothing substitues hard work and understanding.
I look forward to seeing this unfold, perhaps it will for a moment reverse the current trend of trying to earn badges for being agile and start the road to understanding why agility works and apprication for the large body of knowledge present on how to successfully deliver projects that please their stakeholders, sponsors and users alike.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4988670965309258707-2575026912056839524?l=torbjorn-gyllebring.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://torbjorn-gyllebring.blogspot.com/feeds/2575026912056839524/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2008/11/scrum-ate-my-baby.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/2575026912056839524'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/4988670965309258707/posts/default/2575026912056839524'/><link rel='alternate' type='text/html' href='http://torbjorn-gyllebring.blogspot.com/2008/11/scrum-ate-my-baby.html' title='Scrum ate my baby!'/><author><name>Torbjörn Gyllebring</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='22' height='32' src='http://2.bp.blogspot.com/_HeRwgf8wL4c/SKQob260bHI/AAAAAAAAAAU/9qygXP2WYNk/s1600-R/torbj%C3%B6rn.JPG'/></author><thr:total>0</thr:total></entry></feed>
