<?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-8514833315479218736</id><updated>2011-11-28T05:07:59.877+04:00</updated><category term='tricks'/><category term='Dormidontus'/><category term='TDD'/><category term='MVC'/><category term='The Ugly Side'/><category term='Amazing stuff'/><category term='Programming practices'/><category term='Adventures in test-driven development'/><category term='CMS'/><category term='Tools'/><category term='Ivonna'/><category term='CodeProject'/><category term='NHibernate'/><category term='Flex'/><category term='XML'/><category term='VB.Net'/><category term='CThru'/><category term='FreshReports'/><category term='Inka'/><title type='text'>Fresh.Thoughts</title><subtitle type='html'>Random revelations on .Net programming and other earthly stuff</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>64</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-6123824443665323364</id><published>2011-06-02T16:18:00.000+04:00</published><updated>2011-06-02T16:18:37.673+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Adventures in test-driven development'/><category scheme='http://www.blogger.com/atom/ns#' term='Ivonna'/><title type='text'>Look who's got a new home!</title><content type='html'>Finally I have built a new Web site for Ivonna, a &lt;a href="http://ivonna.biz/"&gt;tool for testing Asp.Net sites&lt;/a&gt;. So, I decided to move all my blogging efforts to the new site, and give it all my love (not really). I do have a couple of great posts there already, on &lt;a href="http://ivonna.biz/blog.aspx?filterby=TDD"&gt;Test Driven Development&lt;/a&gt; and other stuff. Expect more to come in the nearest future.&lt;br /&gt;&lt;br /&gt;Enjoy!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-6123824443665323364?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://ivonna.biz/blog/2011/5/8/look-who%27s-got-a-new-home!.aspx' title='Look who&apos;s got a new home!'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/6123824443665323364'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/6123824443665323364'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2011/06/look-whos-got-new-home.html' title='Look who&apos;s got a new home!'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-1436950862801836373</id><published>2011-01-11T22:43:00.001+03:00</published><updated>2011-01-15T14:52:13.895+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tricks'/><category scheme='http://www.blogger.com/atom/ns#' term='NHibernate'/><title type='text'>A Flush In The Night</title><content type='html'>Often you want to do some "fix" on your data before pushing it to the database. Typically it's some auditty thingie --  CreatedBy and UpdatedOn kind of stuff. After spreading it all around your application, you finally decide you should keep these things in one place.&lt;br /&gt;&lt;a href="http://www.codeproject.com/script/Articles/BlogFeedList.aspx?amid=646967" rel="tag" style="display:none;"&gt;  codeproject  &lt;/a&gt;&lt;br /&gt;If you, like me, is an NHibernate user, most likely you find advice to use a &lt;a href="http://www.nhforge.org/doc/nh/en/index.html#manipulatingdata-interceptors"&gt;custom IInterceptor&lt;/a&gt; or &lt;a href="http://ayende.com/Blog/archive/2009/04/29/nhibernate-ipreupdateeventlistener-amp-ipreinserteventlistener.aspx"&gt;IPreUpdateEventListener&lt;/a&gt;. Both are quite ugly solutions, since you have to manipulate the raw state values that are already read from the entity and are ready to be saved to the database. What's even worse, in the latter case you should sync it manually with the entity properties as well. One may think that the original code had been ported from Hibernate before IDictionary was invented (I do understand that there might be some excuses, like performance considerations for example). Find the index of the required field in one array, then fix the value at the corresponding index in another one. Oh joy!&lt;br /&gt;&lt;br /&gt;So, it's quite understandable that I wanted a more elegant solution. Just "fix" the entity before being saved, and also do it in a more, well, object oriented fashion. Naturally this should happen just before the property values are read.&lt;br /&gt;&lt;br /&gt;So, I put a breakpoint on a property getter and started the debugger. Turned out the property was read by an instance of NHibernate.Event.Default.DefaultFlushEntityEventListener, which leads me to believe that its OnFlushEntity method is what actually turns my properties into arrays of raw values. Further investigation showed that this listener is an element of an array of IFlushEntityEventListener-s. So, my plan (which, unsurprisingly, succeeded), was to put my custom implementation in this array &lt;i&gt;before&lt;/i&gt; the default one.&lt;br /&gt;&lt;br /&gt;Just show us the code! I hear you say. Ok, ok, I'm coming to that. Suppose you have a base entity class (but you're not quite sure, 'cause there might be some 3rd party entities floating around). You just add a template method to it called EnsureConsistency, or PerformAudit, whatever. Here is my custom listener:&lt;br /&gt;&lt;br /&gt;&lt;pre style="font-family: consolas"&gt;&lt;span &lt;br /&gt;  style="font-weight: 700;color: #eaeaac"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span &lt;br /&gt;  style="font-weight: 700;color: #eaeaac"&gt;class&lt;/span&gt;&amp;nbsp;&lt;span &lt;br /&gt;  style="color: #f0dfaf"&gt;CustomFlushEntityEventListener :&lt;/span&gt;&lt;br /&gt;&lt;span &lt;br /&gt;  style="color: #2b91af"&gt;IFlushEntityEventListener&lt;/span&gt;&amp;nbsp;{&lt;br /&gt;  &lt;span style="font-weight: 700;color: #eaeaac"&gt;public&lt;/span&gt;&amp;nbsp;&lt;span &lt;br /&gt;  style="font-weight: 700;color: #eaeaac"&gt;void&lt;/span&gt;&amp;nbsp;&lt;span &lt;br /&gt;  style="color: #dfdfbf"&gt;OnFlushEntity&lt;/span&gt;(&lt;span style="color: #f0dfaf"&gt;FlushEntityEvent&lt;/span&gt;&amp;nbsp;&lt;span &lt;br /&gt;  style="color: #dfdfbf"&gt;@event&lt;/span&gt;)&amp;nbsp;{&lt;br /&gt;   &lt;span style="font-weight: 700;color: #eaeaac"&gt;var&lt;/span&gt;&amp;nbsp;&lt;span &lt;br /&gt;  style="color: #dfdfbf"&gt;entity&lt;/span&gt;&amp;nbsp;=&amp;nbsp;&lt;span style="color: #dfdfbf"&gt;@event&lt;/span&gt;.&lt;span &lt;br /&gt;  style="color: #dfdfbf"&gt;Entity&lt;/span&gt;&amp;nbsp;&lt;span &lt;br /&gt;  style="font-weight: 700;color: #eaeaac"&gt;as&lt;/span&gt;&amp;nbsp;&lt;span &lt;br /&gt;  style="color: #f0dfaf"&gt;EntityBase&lt;/span&gt;;&lt;br /&gt;   &lt;span style="font-weight: 700;color: #eaeaac"&gt;if&lt;/span&gt;&amp;nbsp;(&lt;span &lt;br /&gt;  style="color: #dfdfbf"&gt;entity&lt;/span&gt;&amp;nbsp;!=&amp;nbsp;&lt;span &lt;br /&gt;  style="font-weight: 700;color: #eaeaac"&gt;null&lt;/span&gt;)&amp;nbsp;&lt;br /&gt;    &lt;span style="color: #dfdfbf"&gt;entity&lt;/span&gt;.&lt;span &lt;br /&gt;  style="color: #dfdfbf"&gt;EnsureConsistency&lt;/span&gt;();&lt;br /&gt;  }&lt;br /&gt; }&lt;/pre&gt;Now you have your class, here is how to tell NHibernate it should use it (during application startup):&lt;br /&gt;&lt;pre style="font-family: consolas"&gt;&lt;span style="color: #dfdfbf"&gt;configuration&lt;/span&gt;.&lt;span &lt;br /&gt;  style="color: #dfdfbf"&gt;SetListeners&lt;/span&gt;(&lt;span style="color: #2b91af"&gt;ListenerType&lt;/span&gt;.&lt;span &lt;br /&gt;  style="color: #dfdfbf"&gt;FlushEntity&lt;/span&gt;,&lt;br /&gt; &lt;span style="font-weight: 700;color: #eaeaac"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span &lt;br /&gt;  style="color: #2b91af"&gt;IFlushEntityEventListener&lt;/span&gt;[]&lt;br /&gt;  {&lt;br /&gt;  &lt;span style="font-weight: 700;color: #eaeaac"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span &lt;br /&gt;  style="color: #f0dfaf"&gt;CustomFlushEntityEventListener&lt;/span&gt;(),&lt;br /&gt;  &lt;span style="font-weight: 700;color: #eaeaac"&gt;new&lt;/span&gt;&amp;nbsp;&lt;span &lt;br /&gt;  style="color: #f0dfaf"&gt;DefaultFlushEntityEventListener&lt;/span&gt;()&lt;br /&gt;  });&lt;/pre&gt;&lt;br /&gt;Here "configuration" is an instance of NHibernate.Cfg.Configuration, and the code should be run before you build you SessionFactory. The result is, for each entity being flushed, its EnsureConsistency method is being called. The entity itself knows what to do (if anything) in this case. Audit, denormalization, whatever.&lt;br /&gt;&lt;br /&gt;Now I do feel like a real Pro. Please tell me I am.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update.&lt;/b&gt; &lt;a href="http://jfromaniello.blogspot.com"&gt;José F. Romaniello&lt;/a&gt; published a response on the &lt;a href="http://groups.google.com/group/nhusers"&gt;nhusers&lt;/a&gt; Google group, in which he notes that the aforementioned method is being executed for every damn entity, not just for the changed ones. I need to rewrite the code. It seems like I have to inherit from DefaultFlushEntityEventListener and use its IsUpdateNecessary method in order to update just the changed entities. Thanks José!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-1436950862801836373?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/1436950862801836373/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=1436950862801836373' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/1436950862801836373'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/1436950862801836373'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2011/01/flush-in-night.html' title='A Flush In The Night'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-8655306192988821119</id><published>2010-07-12T23:01:00.004+04:00</published><updated>2010-08-21T23:00:39.272+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tricks'/><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><category scheme='http://www.blogger.com/atom/ns#' term='The Ugly Side'/><title type='text'>Just can't plug this in, baby!</title><content type='html'>I've just lost about half a day fighting with a stupid StructureMap exception:&lt;br /&gt;&lt;blockquote&gt;&lt;span class="logStreamMarker-Exception"&gt;&lt;span class="logStreamMarker-ExceptionType"&gt;StructureMap&lt;wbr&gt;&lt;/wbr&gt;.Exceptions&lt;wbr&gt;&lt;/wbr&gt;.StructureMapConfigu&lt;wbr&gt;&lt;/wbr&gt;rationException&lt;/span&gt;&lt;wbr&gt;&lt;/wbr&gt;: &lt;wbr&gt;&lt;/wbr&gt;&lt;span class="logStreamMarker-ExceptionMessage"&gt;StructureMap &lt;wbr&gt;&lt;/wbr&gt;configuration &lt;wbr&gt;&lt;/wbr&gt;failures&lt;wbr&gt;&lt;/wbr&gt;:&lt;br /&gt;Error&lt;wbr&gt;&lt;/wbr&gt;: &lt;wbr&gt;&lt;/wbr&gt; &lt;wbr&gt;&lt;/wbr&gt;104&lt;br /&gt;Source&lt;wbr&gt;&lt;/wbr&gt;: &lt;wbr&gt;&lt;/wbr&gt; &lt;wbr&gt;&lt;/wbr&gt;Registry&lt;wbr&gt;&lt;/wbr&gt;: &lt;wbr&gt;&lt;/wbr&gt; &lt;wbr&gt;&lt;/wbr&gt;StructureMap&lt;wbr&gt;&lt;/wbr&gt;.ConfigurationExpres&lt;wbr&gt;&lt;/wbr&gt;sion,StructureMap&lt;br /&gt;Type &lt;wbr&gt;&lt;/wbr&gt;Instance &lt;wbr&gt;&lt;/wbr&gt;'bf0f9bf6-304d-4d7b-&lt;wbr&gt;&lt;/wbr&gt;9cd4-59437e94eb10' &lt;wbr&gt;&lt;/wbr&gt;&lt;wbr&gt;&lt;/wbr&gt;(Smart &lt;wbr&gt;&lt;/wbr&gt;Instance &lt;wbr&gt;&lt;/wbr&gt;for &lt;wbr&gt;&lt;/wbr&gt;System&lt;wbr&gt;&lt;/wbr&gt;.Data&lt;wbr&gt;&lt;/wbr&gt;.SqlClient&lt;wbr&gt;&lt;/wbr&gt;.SqlClientFactory)&lt;wbr&gt;&lt;/wbr&gt; &lt;wbr&gt;&lt;/wbr&gt;cannot &lt;wbr&gt;&lt;/wbr&gt;be &lt;wbr&gt;&lt;/wbr&gt;plugged &lt;wbr&gt;&lt;/wbr&gt;into &lt;wbr&gt;&lt;/wbr&gt;type &lt;wbr&gt;&lt;/wbr&gt;System&lt;wbr&gt;&lt;/wbr&gt;.Data&lt;wbr&gt;&lt;/wbr&gt;.Common&lt;wbr&gt;&lt;/wbr&gt;.DbProviderFactory, &lt;wbr&gt;&lt;/wbr&gt;System&lt;wbr&gt;&lt;/wbr&gt;.Data, &lt;wbr&gt;&lt;/wbr&gt;Version=2&lt;wbr&gt;&lt;/wbr&gt;.0&lt;wbr&gt;&lt;/wbr&gt;.0&lt;wbr&gt;&lt;/wbr&gt;.0, &lt;wbr&gt;&lt;/wbr&gt;Culture=neutral, &lt;wbr&gt;&lt;/wbr&gt;PublicKeyToken=b77a5&lt;wbr&gt;&lt;/wbr&gt;c561934e089&lt;br /&gt;--------------------&lt;wbr&gt;&lt;/wbr&gt;--------------------&lt;wbr&gt;&lt;/wbr&gt;--------------------&lt;wbr&gt;&lt;/wbr&gt;--------------------&lt;wbr&gt;&lt;/wbr&gt;--------------------&lt;wbr&gt;&lt;/wbr&gt;-&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="logStreamMarker-StackTrace"&gt; &lt;wbr&gt;&lt;/wbr&gt; &lt;wbr&gt;&lt;/wbr&gt; &lt;wbr&gt;&lt;/wbr&gt;at &lt;wbr&gt;&lt;/wbr&gt;StructureMap&lt;wbr&gt;&lt;/wbr&gt;.Diagnostics&lt;wbr&gt;&lt;/wbr&gt;.GraphLog&lt;wbr&gt;&lt;/wbr&gt;.AssertFailures&lt;wbr&gt;&lt;/wbr&gt;()&lt;wbr&gt;&lt;/wbr&gt;&lt;br /&gt;&lt;wbr&gt;&lt;/wbr&gt; &lt;wbr&gt;&lt;/wbr&gt; &lt;wbr&gt;&lt;/wbr&gt;at &lt;wbr&gt;&lt;/wbr&gt;StructureMap&lt;wbr&gt;&lt;/wbr&gt;.Container&lt;wbr&gt;&lt;/wbr&gt;.Configure&lt;wbr&gt;&lt;/wbr&gt;(Action`1 &lt;wbr&gt;&lt;/wbr&gt;configure)&lt;wbr&gt;&lt;/wbr&gt;&lt;br /&gt;&lt;wbr&gt;&lt;/wbr&gt; &lt;wbr&gt;&lt;/wbr&gt; &lt;wbr&gt;&lt;/wbr&gt;at &lt;wbr&gt;&lt;/wbr&gt;StructureMap&lt;wbr&gt;&lt;/wbr&gt;.ObjectFactory&lt;wbr&gt;&lt;/wbr&gt;.Configure&lt;wbr&gt;&lt;/wbr&gt;(Action`1 &lt;wbr&gt;&lt;/wbr&gt;configure)&lt;wbr&gt;&lt;/wbr&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;My actual code was this:&lt;br /&gt;&lt;blockquote&gt;ObjectFactory.Configure(expr =&amp;gt;&lt;br /&gt;{                              &lt;br /&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;expr&lt;/span&gt;.&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;For&lt;/span&gt;&amp;lt;DbProviderFactory&amp;gt;().&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;Use&lt;/span&gt;&amp;lt;SqlClientFactory&amp;gt;();&lt;br /&gt;});&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;What&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;do&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;you&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;mean&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;by&lt;/span&gt; "&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;cannot&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;be&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;plugged&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;in&lt;/span&gt;", &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;and&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;why&lt;/span&gt; Google &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_14"&gt;can&lt;/span&gt;'t &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_15"&gt;help&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_16"&gt;me&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_17"&gt;here&lt;/span&gt;???&lt;br /&gt;&lt;br /&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_18"&gt;So&lt;/span&gt;, a &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_19"&gt;couple&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_20"&gt;of&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_21"&gt;hours&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_22"&gt;later&lt;/span&gt; (&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_23"&gt;and&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_24"&gt;with&lt;/span&gt; a &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_25"&gt;big&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_26"&gt;help&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_27"&gt;from&lt;/span&gt; &lt;a href="http://cthru.codeplex.com/"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_28"&gt;CThru&lt;/span&gt; &lt;/a&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_29"&gt;and&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_30"&gt;Reflector&lt;/span&gt;), &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_31"&gt;and&lt;/span&gt; I &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_32"&gt;find&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_33"&gt;the&lt;/span&gt; StructureMap.Graph.TypeRules.CanBeCast &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_34"&gt;method&lt;/span&gt;, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_35"&gt;which&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_36"&gt;is&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_37"&gt;not&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_38"&gt;just&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_39"&gt;about&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_40"&gt;casting&lt;/span&gt;, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_41"&gt;but&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_42"&gt;says&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_43"&gt;no&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_44"&gt;when&lt;/span&gt;,  &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_45"&gt;among&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_46"&gt;other&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_47"&gt;things&lt;/span&gt;, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_48"&gt;the&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_49"&gt;concrete&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_50"&gt;type&lt;/span&gt; (&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_51"&gt;SqlClientFactory&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_52"&gt;in&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_53"&gt;our&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_54"&gt;case&lt;/span&gt;) &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_55"&gt;has&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_56"&gt;no&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_57"&gt;default&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_58"&gt;constructor&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_59"&gt;Ok&lt;/span&gt;, I &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_60"&gt;can&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_61"&gt;understand&lt;/span&gt;. &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_62"&gt;StructureMap&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_63"&gt;doesn&lt;/span&gt;'t &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_64"&gt;know&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_65"&gt;how&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_66"&gt;to&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_67"&gt;create&lt;/span&gt; a &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_68"&gt;concrete&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_69"&gt;instance&lt;/span&gt;. &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_70"&gt;How&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_71"&gt;about&lt;/span&gt; &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_72"&gt;this&lt;/span&gt;:&lt;br /&gt;&lt;blockquote&gt;expr.ForRequestedType&amp;lt;DbProviderFactory&amp;gt;().Use(SqlClientFactory.Instance);&lt;/blockquote&gt;Still no luck:&lt;br /&gt;&lt;blockquote&gt;&lt;span class="logStreamMarker-Exception"&gt;&lt;span class="logStreamMarker-ExceptionType"&gt;StructureMap&lt;wbr&gt;&lt;/wbr&gt;.Exceptions&lt;wbr&gt;&lt;/wbr&gt;.StructureMapConfigu&lt;wbr&gt;&lt;/wbr&gt;rationException&lt;/span&gt;&lt;wbr&gt;&lt;/wbr&gt;: &lt;wbr&gt;&lt;/wbr&gt;&lt;span class="logStreamMarker-ExceptionMessage"&gt;StructureMap &lt;wbr&gt;&lt;/wbr&gt;configuration &lt;wbr&gt;&lt;/wbr&gt;failures&lt;wbr&gt;&lt;/wbr&gt;:&lt;br /&gt;Error&lt;wbr&gt;&lt;/wbr&gt;: &lt;wbr&gt;&lt;/wbr&gt; &lt;wbr&gt;&lt;/wbr&gt;104&lt;br /&gt;Source&lt;wbr&gt;&lt;/wbr&gt;: &lt;wbr&gt;&lt;/wbr&gt; &lt;wbr&gt;&lt;/wbr&gt;Registry&lt;wbr&gt;&lt;/wbr&gt;: &lt;wbr&gt;&lt;/wbr&gt; &lt;wbr&gt;&lt;/wbr&gt;StructureMap&lt;wbr&gt;&lt;/wbr&gt;.ConfigurationExpres&lt;wbr&gt;&lt;/wbr&gt;sion,StructureMap&lt;br /&gt;Type &lt;wbr&gt;&lt;/wbr&gt;Instance &lt;wbr&gt;&lt;/wbr&gt;'42b890e6-54dc-457e-&lt;wbr&gt;&lt;/wbr&gt;897a-3e8becc7d0fb' &lt;wbr&gt;&lt;/wbr&gt;&lt;wbr&gt;&lt;/wbr&gt;(Object&lt;wbr&gt;&lt;/wbr&gt;: &lt;wbr&gt;&lt;/wbr&gt; &lt;wbr&gt;&lt;/wbr&gt;System&lt;wbr&gt;&lt;/wbr&gt;.Data&lt;wbr&gt;&lt;/wbr&gt;.SqlClient&lt;wbr&gt;&lt;/wbr&gt;.SqlClientFactory)&lt;wbr&gt;&lt;/wbr&gt; &lt;wbr&gt;&lt;/wbr&gt;cannot &lt;wbr&gt;&lt;/wbr&gt;be &lt;wbr&gt;&lt;/wbr&gt;plugged &lt;wbr&gt;&lt;/wbr&gt;into &lt;wbr&gt;&lt;/wbr&gt;type &lt;wbr&gt;&lt;/wbr&gt;System&lt;wbr&gt;&lt;/wbr&gt;.Data&lt;wbr&gt;&lt;/wbr&gt;.Common&lt;wbr&gt;&lt;/wbr&gt;.DbProviderFactory, &lt;wbr&gt;&lt;/wbr&gt;System&lt;wbr&gt;&lt;/wbr&gt;.Data, &lt;wbr&gt;&lt;/wbr&gt;Version=2&lt;wbr&gt;&lt;/wbr&gt;.0&lt;wbr&gt;&lt;/wbr&gt;.0&lt;wbr&gt;&lt;/wbr&gt;.0, &lt;wbr&gt;&lt;/wbr&gt;Culture=neutral, &lt;wbr&gt;&lt;/wbr&gt;PublicKeyToken=b77a5&lt;wbr&gt;&lt;/wbr&gt;c561934e089&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;This is more weird, but a look into the code tells me that we still require the target type to have a default constructor (cause we call the same method). Must be a bug in StructureMap. Too bad, since that would be the most clear and logical solution.&lt;br /&gt;&lt;br /&gt;Finally this one worked for me:&lt;br /&gt;&lt;blockquote&gt;expr.ForRequestedType&amp;lt;DbProviderFactory&amp;gt;() .AsSingletons(). TheDefault.Is.ConstructedBy (ctx =&amp;gt; SqlClientFactory.Instance);&lt;/blockquote&gt;&lt;br /&gt;Have fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-8655306192988821119?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/8655306192988821119'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/8655306192988821119'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2010/07/just-cant-plug-this-in-baby.html' title='Just can&apos;t plug this in, baby!'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-3322370433432148218</id><published>2010-07-05T20:54:00.000+04:00</published><updated>2010-07-05T20:54:39.363+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Adventures in test-driven development'/><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><category scheme='http://www.blogger.com/atom/ns#' term='Ivonna'/><category scheme='http://www.blogger.com/atom/ns#' term='CodeProject'/><title type='text'>Testing Asp.Net pages with Telerik's JustMock</title><content type='html'>It is always nice when a competitor publishes a piece of their code. You can always sneak into the comments and, like, look, I'm better! and put a link to your blog where you show your version proudly, and get a massive following.&lt;br /&gt;&lt;br /&gt;Guess what, this is what I'm doing right now commenting on the &lt;a href="http://weblogs.asp.net/mehfuzh/archive/2010/04/29/playing-with-aspx-page-cycle-using-justmock.aspx"&gt;Mehfuz's post.&lt;/a&gt; But the main thing I realized reading his post is that this is the perfect example of how using mocks in certain situations can turn testing into a nightmare. The following is not a problem with JustMock, it's a problem with trying to write a unit test involving a complex framework, and isolating parts of it not meant to be isolated.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size: x-small;"&gt;(Disclaimer: I do understand that the purpose of the original post is not to teach us how to test Asp.Net pages, but to demonstrate the capabilities of JustMock. So, my intent is not to prove that the author is wrong, but rather to take his example as a perfect situation where mock should absolutely &lt;i&gt;not&lt;/i&gt; be used.)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So, in order to write the test, we have to&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Mock the &lt;span style="color: #2b91af;"&gt;HttpBrowserCapabilities &lt;/span&gt; class and stub a couple of its properties so that it returns &lt;span style="font-style: italic;"&gt;something&lt;/span&gt; when needed.&lt;/li&gt;&lt;li&gt;Mock the &lt;span style="color: #2b91af;"&gt;HttpRequest&lt;/span&gt; class (of &lt;span style="font-style: italic;"&gt;course&lt;/span&gt;) and make the mock return our mocked Browser.&lt;/li&gt;&lt;li&gt;Mock the &lt;span style="color: #2b91af;"&gt;HttpResponse&lt;/span&gt; class as well.&lt;/li&gt;&lt;li&gt;Mock the &lt;span style="color: #2b91af;"&gt;HttpContext&lt;/span&gt; class and stub its Request and Response properties (make the getters return our mock instances).&lt;/li&gt;&lt;li&gt;Finally, we are stubbing the &lt;span style="color: #2b91af;"&gt;Page.&lt;/span&gt;RenderControl method, and it's unclear whether we do it to avoid exceptions, or just for fun.&lt;/li&gt;&lt;/ol&gt;The main purpose is to test whether the Page instance fires all (well, just some) its lifecycle events, and it's done not using mocks but rather adding event handlers (since we already have our Page instance).&lt;br /&gt;&lt;br /&gt;Why do we have to mock all these classes? Why do we have to fire up Reflector and dig into the Framework source in order to make our test pass? Because we have this idea that unit testing means testing a particular class in isolation. Somehow all calculator examples left us with an idea that "unit" == "class".&lt;br /&gt;&lt;br /&gt;Now, let's back off a bit and consider this: we are testing a high-level ProcessRequest method, which does a lot of lower-level calls to various classes, which are tightly coupled with each other. So, I think it's logical to say that our "unit" is a good part of the System.Web assembly. With that assumption, everything becomes simple: we don't test just our Page instance, we test the whole unit. Assuming we are the developers of the framework, we can also test the lower level methods which have less dependencies, so that we can mock them more easily.&lt;br /&gt;&lt;br /&gt;Back to our integration test, here's what it looks like when we use &lt;a href="http://sm-art.biz/Ivonna.aspx"&gt;Ivonna&lt;/a&gt;. I have omitted all asserts for clarity; instead, we just write messages to the console, as we would in an exploratory test:&lt;br /&gt;&lt;blockquote&gt;&lt;pre style="font-family: consolas;"&gt;[Test]&lt;br /&gt;public void TestingPageEvents()&lt;br /&gt;{&lt;br /&gt; var session = new TestSession();&lt;br /&gt; var request = new WebRequest("Default.aspx");&lt;br /&gt; request.EventHandlers.Page_Init = &lt;br /&gt;             (sender, e) =&amp;gt; Console.WriteLine("Init fired");&lt;br /&gt; request.EventHandlers.Page_Load = &lt;br /&gt;             (sender, e) =&amp;gt; Console.WriteLine("Load fired");&lt;br /&gt; session.ProcessRequest(request);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/blockquote&gt;This code executes a test against a "real" Web page, with a "real" HttpContext and other necessary objects, so it gives us much more valuable information about the behavior of our system in "real world" situations.&lt;br /&gt;&lt;br /&gt;Check out a fresh version of Ivonna &lt;a href="http://sm-art.biz/Ivonna.aspx"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-3322370433432148218?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://weblogs.asp.net/mehfuzh/archive/2010/04/29/playing-with-aspx-page-cycle-using-justmock.aspx' title='Testing Asp.Net pages with Telerik&apos;s JustMock'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/3322370433432148218'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/3322370433432148218'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2010/07/testing-aspnet-pages-with-teleriks.html' title='Testing Asp.Net pages with Telerik&apos;s JustMock'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-9084840942069442513</id><published>2010-06-18T11:38:00.003+04:00</published><updated>2010-06-18T15:17:50.041+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><category scheme='http://www.blogger.com/atom/ns#' term='Ivonna'/><category scheme='http://www.blogger.com/atom/ns#' term='CThru'/><title type='text'>C-eeing Thru Your Code</title><content type='html'>&lt;a href="http://www.codeproject.com/script/Articles/BlogFeedList.aspx?amid=646967" rel="tag" style="display: none;"&gt;  codeproject  &lt;/a&gt;&lt;br /&gt;Ladies and gentlemen, let me introduce you to this exciting library, &lt;a href="http://cthru.codeplex.com/"&gt;CThru&lt;/a&gt;. (I planned to add several jokes here, but changed my mind). This is an open source AOP framework built on top of &lt;a href="http://typemock.com/"&gt;Typemock Isolator&lt;/a&gt;. Recently I added several improvements to the built-in aspects, and thought I might write a blog post about it.&lt;br /&gt;&lt;br /&gt;CThru requires Typemock Isolator to be installed on the target box, so you probably want to use it in your test projects. CThru does not require you to modify the original code, nor the compiled binaries, so you're free to use it on, say, BCL libraries (except for mscorlib). It works by intercepting method calls and add or change their behavior. Each aspect is responsible for deciding which calls to intercept by implementing the ShouldIntercept method. You can make a decision based on the target instance, class name, or method name. For example, you could apply it to all implementors of a particular interface, or for all types in a particular namespace.&lt;br /&gt;&lt;br /&gt;In order to make it work, you add all necessary aspects by calling CThruEngine.AddAspect(), then call CThruEngine.StartListening(). The cleanup is done by calling CThruEngine.StopListeningAndReset().&lt;br /&gt;&lt;br /&gt;So, how do you write your own aspect? First, you inherit from the abstract Aspect class, and implement the ShouldIntercept method. As I said before, it determines the condition for which the aspect is applied. To add specific behavior, you should override the MethodBehavior or ConstructorBehavior methods.  By default, your code is run before the actual method is invoked. You can also skip the original method, return custom value, or throw an exception by manipulating the properties of the DuringCallbackEventArgs valued argument. If you want to add some behavior &lt;span style="font-style: italic;"&gt;after&lt;/span&gt; the original method is invoked, you can execute the Aspect.CallOriginalMethod method (don't forget to set e.MethodBehavior = MethodBehaviors.SkipActualMethod so that it isn't called twice).&lt;br /&gt;&lt;br /&gt;There are aspects that are generic in nature: the behavior is the same, but they are applied in different situation, so it doesn't make sense to hardcode the ShouldIntercept method. For example, the Stub aspect just ignores the method call, but which call it ignores should be determined by the code that uses the aspect. So, there's a convenient base class called "CommonAspect". It makes it possible to pass the intercepting decision in the constructor argument. For example, if you want to ignore all methods with names starting with "My", you write:&lt;br /&gt;&lt;blockquote&gt;CThruEngine.AddAspect(new Stub(info =&gt; info.MethodName.StartsWith("My")));&lt;br /&gt;&lt;/blockquote&gt;That said, let's review some of the built-in aspects:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;SkipAllByTypeName -- very simple aspect, designed to illustrate how aspects should be written. Skips all method calls of classes that contain the specified string in their names.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;MissingMethodAspect -- implements Ruby-like behavior in VB.Net (when you try and execute a non-existent method, it invokes the method called "method-missing" instead).&lt;/li&gt;&lt;li&gt;TraceAspect -- traces all intercepted calls to the console (or the supplied TextWriter instance), optionally with the stack trace.&lt;/li&gt;&lt;li&gt;TraceResultAspect -- same but traces the results as well. Due to the CThru limitation, all calls invoked by the traced call are not traced (unlike with TraceAspect).&lt;/li&gt;&lt;li&gt;DebugAspect -- if you have attached the debugger, it pauses the execution before calling the intercepted method. Very useful for investigating the state of the system at a particular point, when you don't have access to the code at that point.&lt;/li&gt;&lt;li&gt;Stub -- just ignore the call and return null. ToDo: implement returning a custom value.&lt;/li&gt;&lt;/ul&gt;Several projects that are built on top of, or developed using, CThru:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;SilverUnit, a framework for testing Silverlight applications. &lt;a href="http://cthru.codeplex.com/"&gt;Bundled with CThru&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;&lt;a href="http://Balder.codeplex.com"&gt;Balder&lt;/a&gt;. Managed 2D and 3D graphics engine, targetting Silverlight, Xna and  OpenGL.&lt;/li&gt;&lt;li&gt;&lt;a href="http://sm-art.biz/Ivonna.aspx"&gt;Ivonna&lt;/a&gt;, an Asp.Net unit and integration testing tool.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;So, whether you just need some exploratory testing, or building a domain-specific test framework, CThru can save you a lot of effort.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-9084840942069442513?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/9084840942069442513'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/9084840942069442513'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2010/06/c-eeing-thru-your-code.html' title='C-eeing Thru Your Code'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-1392196094234165120</id><published>2010-06-14T22:11:00.020+04:00</published><updated>2010-06-17T17:40:38.521+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tricks'/><category scheme='http://www.blogger.com/atom/ns#' term='Adventures in test-driven development'/><category scheme='http://www.blogger.com/atom/ns#' term='Ivonna'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>On structuring your tests</title><content type='html'>&lt;a href="http://www.codeproject.com/script/Articles/BlogFeedList.aspx?amid=646967" rel="tag" style="display: none;"&gt;  codeproject  &lt;/a&gt;&lt;br /&gt;The ideas presented here are nothing new; however, a &lt;a href="http://blogs.microsoft.co.il/blogs/dhelper/archive/2010/06/06/when-to-use-the-setup-attribute.aspx"&gt;recent discussion&lt;/a&gt; with Dror Helper made me want to state my views on this subject (and make the whole world agree with me, whatever it takes), because to be honest, despite my best efforts in meditation, when I see a class called "MyClassTester" it makes me.. &lt;strike&gt;wanna start a holy war&lt;/strike&gt; nervous.&lt;br /&gt;&lt;br /&gt;The idea  is, if you do TDD, you don't start with a class, because if you do, you already have some design before you have written any tests. So, you start with a user story. Ant let it be a Web app, to be more concrete. Here it goes:&lt;blockquote&gt;&lt;span style="font-style: italic;"&gt;When a user fills the registration form correctly and hits the "Register" button, several things happen:&lt;br /&gt;&lt;/span&gt;&lt;ul&gt;&lt;li style="font-style: italic;"&gt;she becomes, in some sense, "registered" in the system;&lt;/li&gt;&lt;li style="font-style: italic;"&gt;an email is sent, containing the confirmation link;&lt;/li&gt;&lt;li&gt;&lt;span style="font-style: italic;"&gt;she's redirected to a particular screen.&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-style: italic;"&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;/span&gt;&lt;/blockquote&gt;Now, if I were to start writing unit tests for a particular class, which class would it be? The specs say nothing about classes or such. So, first, I decide that it's going to be an MVC app, like all the cool guys doing these days. And I'm going to start with the most exciting thing: my controller. So, I'm creating a class called AccountControllerTester or something. Next, I have to write a test, so I meditate over the requirements, and here's what I think:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;"Registered" is kinda vague, but let's do it with the built-in Membership system. I'll inject this service into my controller, mock the service in my test and verify the call to it.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Email is easy. A service again, I'll write it later (after the lunch), let's use an interface for the moment.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Redirection is just return View(".."). Easy to test.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;So you end up with either one test with three asserts (which is a bad practice), or three test methods related to one particular feature. What makes it a mess is that you're going to add more tests: related to input validation, and to the other features that are handled by this controller: password change and retrieval, email confirmation etc. For every action method, you can have 5-10 tests. On the other hand, the actual confirmation email sending belongs to a different class, so you probably put the test there, together with other email-related tests.&lt;br /&gt;&lt;br /&gt;You see, one big problem is that each test class becomes huge. But what's more important, it is hard to tell what your system does. One purpose of tests is documentation, and it should be readable for outsiders. If I am to figure out the behavior of the system in the registration process, where should I look? How do I know that part of it is in the AccountControllerTests, and another part is in the EmailServiceTests?&lt;br /&gt;&lt;br /&gt;And still another problem is that you just wrote a lot of code, but made &lt;span style="font-weight: bold;"&gt;zero&lt;/span&gt; business value with it. I mean, I can't register at your site yet! And won't be able until you write all the pieces and connect them together (for which you probably should write an integration test).&lt;br /&gt;&lt;br /&gt;To summarize, what you get with this approach is:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;premature, rather than test-driven, design;&lt;/li&gt;&lt;li&gt;potentially brittle tests (since they are coupled to your classes, you can't refactor easily);&lt;/li&gt;&lt;li&gt;huge test classes;&lt;/li&gt;&lt;li&gt;documenting your classes rather than your system;&lt;/li&gt;&lt;li&gt;no clear relationship between the specs and your tests;&lt;/li&gt;&lt;li&gt;no business value until you have all the pieces.&lt;/li&gt;&lt;/ul&gt;&lt;h2&gt;There's a better way&lt;/h2&gt;Now, let's do it another way. Let's create a folder called Membership, and inside it a folder called "Registration". We're testing the case when we submit valid registration data, so let's make a test class called "IfSubmittedValidRegistrationData". The test methods will be called "ShouldSendConfirmationEmail" etc, so the test output will show something like,&lt;br /&gt;&lt;blockquote&gt;WhenSubmittedValidRegistrationData.ShouldSendConfirmationEmail -- &lt;span style="font-style: italic;"&gt;passed&lt;/span&gt;.&lt;/blockquote&gt;This is quite close to documenting your system!&lt;br /&gt;&lt;br /&gt;Now, you can still write it as a unit test for your controller, if you prefer, but I suggest you start with integration tests. I use &lt;a href="http://sm-art.biz/Ivonna.aspx"&gt;Ivonna&lt;/a&gt; for testing, and it makes it a lot easier: my "integration" is only server-side. In addition, I can use several built-in CThru aspects, like EmailSpy, and I can use a lightweight in-memory database. I initialize the posted values (Arrange) and execute the request (Act) in the FixtureSetup method, and all my test methods are one or two lines of code where I verify the results.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;UserShouldBeRegistered -- I just check it via the MembershipAPI.&lt;/li&gt;&lt;li&gt;ShouldSendConfirmationEmail-- I use EmailSpy that prevents the message from being sent, and saves it for further investigation, so that I can verify that it contains the confirmation link, is being sent to the correct address etc.&lt;/li&gt;&lt;li&gt;ShouldRedirectToTheWelcomeScreen -- check the Ivonna.Framework.WebResponse.RedirectLocation property.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Now I can go the full Red-Green-Refactor way.  I stuff all the code into my action method until all my tests pass. At this moment &lt;span style="font-style: italic;"&gt;my system actually works&lt;/span&gt;: I can register a user! But my code is ugly: it is a quick-and-dirty solution written just in order to make my tests pass. I want to make it better. So I refactor it.&lt;br /&gt;&lt;br /&gt;It's at the refactoring phase that unit tests can provide a big value. Yes  we all know that unit testing can lead us to a much better design. But sometimes it is enough to do it mentally. For example, "how would I unit test my controller"? Oh yes, I should refactor the email-related code into a separate class, and do dependency injection. Probably extract an interface like IMessagingService and implement it as EmailService. Whatever. But I actually write a unit test only if I can think of a good name for it. EmailServiceTester totally won't do. TheConfirmationMessageShouldBeActuallySentByEmail is more like it (and the corresponding unit test for the controller is ShouldSendTheConfirmationMessage -- note that it doesn't mention "email"). But in this particular case, it's probably not worth it.&lt;br /&gt;&lt;br /&gt;There is another situation when we have a particular feature that produces some output depending on various inputs, and it's not a yes/no situation, like in the previous case. Take searching, for example. You start with an integration test, like before. And make it work. For one of several search form parameters, you know that the search produces the correct results that appear in a grid on the search results page. It would be wasteful to write integration test for every search parameter. So, assume we already have it refactored into several units  (note that I don't say "classes"): SearchParamsReader (this is actually the MVC Binder), TheThingThatGivesUsSearchResultsDependingOnTheSearchParams, and SearchResultsWriter (the one responsible for displaying the results). You make three subfolders in your Searching folder (which already contains the integration test), each responsible for the corresponding piece of functionality. Actually, it's probably worth it to make just one subfolder and test TheThingThat.. Again, you don't put everything  for testing TheThing.. into one huge class, but you create  several classes: SearchByKeyword, SearchByMinMaxPrice etc. This is unit, not integration, testing, and yet it corresponds to user requirements and documents the system behavior. I could refactor TheThing.. into several classes, I could rename it, and the tests won't break.&lt;br /&gt;&lt;h2&gt;Here's the recipe for happiness&lt;/h2&gt;&lt;ol&gt;&lt;li&gt;Make a folder corresponding to a feature, then a subfolder for a sub-feature etc, until you have a concrete action, like registration or search, or maybe a concrete context.&lt;/li&gt;&lt;li&gt;Inside, create a fixture for each combination of context + action (like "submitting a duplicate username") and name it accordingly (WhenSubmittedExistingUsername).&lt;/li&gt;&lt;li&gt;Put all preparation into the FixtureSetup method. You want it to be readable, so refactor all the nasty details into private methods and move them to the end.&lt;/li&gt;&lt;li&gt;Each check should go to a separate Test method. Name them so that they match the requirements.&lt;/li&gt;&lt;li&gt;More granular tests, if you need them, should go to subfolders.&lt;/li&gt;&lt;li&gt;If you can't think of a decent test name (something that doesn't use the class/method names), it's probably not worth writing (but might be useful for driving your design).&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-1392196094234165120?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/1392196094234165120'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/1392196094234165120'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2010/06/on-structuring-your-tests.html' title='On structuring your tests'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-3277986621446264080</id><published>2010-05-04T14:10:00.003+04:00</published><updated>2010-05-04T14:49:47.196+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VB.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='XML'/><title type='text'>Fixing the namespace problem in VB.Net XML literals</title><content type='html'>Recently I tried to parse a Web page output using the shiny VB.Net syntax. I had an XElement representing a dropdown, and tried to count the options using something like&lt;br /&gt;&lt;blockquote&gt;purposeChooser.&lt;option&gt;.Count&lt;/blockquote&gt;Although I could clearly see that there is one child "option" element, it kept returning a zero. Then I realized that there might be some namespace trouble. Indeed, the top html tag had some namespace attached, and, naturally, it was inherited by the select (and the option) element. However, it didn't include a prefix, so how do I tell what to look for? The answer is, you can import an XML namespace just like you can a "regular" one, putting this at the top of your code:&lt;br /&gt;&lt;blockquote&gt;Imports &lt;xmlns:ns="http://www.w3.org/1999/xhtml"&gt;&lt;/blockquote&gt;And now this expression&lt;br /&gt;&lt;blockquote&gt;purposeChooser.&lt;ns:option&gt;.Count&lt;/blockquote&gt;returns 1, as expected.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-3277986621446264080?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/3277986621446264080'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/3277986621446264080'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2010/05/fixing-namespace-problem-in-vbnet-xml.html' title='Fixing the namespace problem in VB.Net XML literals'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-1844636361577452734</id><published>2010-04-17T13:18:00.003+04:00</published><updated>2010-04-17T13:53:56.221+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tricks'/><category scheme='http://www.blogger.com/atom/ns#' term='MVC'/><title type='text'>Using the EditorFor method in MVC2 to display child collections</title><content type='html'>I was very excited when I discovered the new DisplayFor and EditorFor extensions in the new MVC release. In fact, they look even better than the similar MVCContrib features.&lt;br /&gt;&lt;br /&gt;The only problem is that when I tried to render a child collection, it displayed nothing. This is kinda weird, because when your model &lt;span style="font-style: italic;"&gt;is&lt;/span&gt; a collection, it shows just fine. However, as &lt;a href="http://blogs.msdn.com/stuartleeks/archive/2010/03/30/collections-and-asp-net-mvc-templated-helpers-displayfor-editorfor.aspx"&gt;this post&lt;/a&gt; explains, anything complex enough (that is, not convertible to a string) is just filtered out.&lt;br /&gt;&lt;br /&gt;It turned out that it could be fixed relatively easily. You have to override the default Object template and fix the logic. Just create a view called Object.ascx in your Views/Shared/EditorTemplates folder, copy the default template from &lt;a href="http://bradwilson.typepad.com/blog/2009/10/aspnet-mvc-2-templates-part-3-default-templates.html"&gt;here&lt;/a&gt;, and modify the filtering logic. Took me  a while, since I had to convert it to VB.Net. Here's the result:&lt;br /&gt;&lt;br /&gt;&lt;%@ Control Language="VB" Inherits="System.Web.Mvc.ViewUserControl" %&gt;&lt;br /&gt;&lt;%@ Import Namespace="System.Globalization"%&gt;&lt;br /&gt;&lt;%@ Import Namespace="System.Linq" %&gt;&lt;br /&gt;&lt;br /&gt;&lt;%  If (ViewData.ModelMetadata.Model Is Nothing) Then%&gt;&lt;br /&gt;       &lt;%=ViewData.ModelMetadata.NullDisplayText%&gt;&lt;br /&gt;&lt;% Else%&gt;  &lt;br /&gt;   &lt;%  If (ViewData.TemplateInfo.TemplateDepth &gt; 3) Then%&gt;&lt;br /&gt;           &lt;%=Me.ViewData.ModelMetadata.SimpleDisplayText%&gt;&lt;br /&gt;   &lt;% Else%&gt;&lt;br /&gt;       &lt;%             Dim props = From pm In Me.ViewData.ModelMetadata.Properties Where pm.ShowForEdit AndAlso Not ViewData.TemplateInfo.Visited(pm)             For Each prop In props                 If prop.HideSurroundingHtml Then%&gt;&lt;br /&gt;                   &lt;%= Html.Editor(prop.PropertyName) %&gt;&lt;br /&gt;               &lt;% Else                     Dim str As String = Html.Label(prop.PropertyName).ToHtmlString                     If Not String.IsNullOrEmpty(str) Then%&gt;&lt;br /&gt;                       &lt;div class="editor-label"&gt;&lt;%= Html.Label(prop.PropertyName) %&gt;&lt;/div&gt;&lt;br /&gt;                   &lt;% End If%&gt;&lt;br /&gt;                   &lt;div class="editor-field"&gt;&lt;br /&gt;                   &lt;%= Html.Editor(prop.PropertyName) %&gt;&lt;br /&gt;                   &lt;%= Html.ValidationMessage(prop.PropertyName, "*") %&gt;&lt;br /&gt;                   &lt;/div&gt;&lt;br /&gt;               &lt;% End If%&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;           &lt;%Next%&gt;&lt;br /&gt;   &lt;% End If%&gt;&lt;br /&gt;&lt;% End If%&gt;&lt;br /&gt;&lt;br /&gt;Don't forget to check the line related to TemplateDepth. Originally, it makes a shallow copy: everything with the depth&gt;1 is just displayed as a simple string. You might want to make this number greater, or remove the check entirely.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-1844636361577452734?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/1844636361577452734'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/1844636361577452734'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2010/04/using-editorfor-method-in-mvc2-to.html' title='Using the EditorFor method in MVC2 to display child collections'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-2047546705821892179</id><published>2010-04-09T23:30:00.003+04:00</published><updated>2010-04-09T23:47:25.952+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='VB.Net'/><category scheme='http://www.blogger.com/atom/ns#' term='NHibernate'/><category scheme='http://www.blogger.com/atom/ns#' term='The Ugly Side'/><title type='text'>Using the latest NHibernate features in your VB.Net code.</title><content type='html'>No doubt you have tried the newest LINQ-to-NHibernate bits in your VB.Net application already. If you have gotten past retrieving all records from a specific table, you might been getting an exception similar to this one:&lt;br /&gt;&lt;br /&gt;System.Exception: Unrecognised method call in epression CompareString(aUser.Name, value(Web.Controllers.Membership.AccountMembershipService+_Closure$__1).$VB$Local_userName, False)&lt;br /&gt; at NHibernate.Impl.ExpressionProcessor.FindMemberExpression(Expression expression) in f:\Разные штуки\Visual Studio 2008\Projects\OpenSource\NHibernate\nhibernate\src\NHibernate\Impl\ExpressionProcessor.cs:line 170&lt;br /&gt; at NHibernate.Impl.ExpressionProcessor.ProcessSimpleExpression(BinaryExpression be) in f:\Разные штуки\Visual Studio 2008\Projects\OpenSource\NHibernate\nhibernate\src\NHibernate\Impl\ExpressionProcessor.cs:line 295&lt;br /&gt; at NHibernate.Impl.ExpressionProcessor.ProcessBinaryExpression(BinaryExpression expression) in f:\Разные штуки\Visual Studio 2008\Projects\OpenSource\NHibernate\nhibernate\src\NHibernate\Impl\ExpressionProcessor.cs:line 358&lt;br /&gt; at NHibernate.Impl.ExpressionProcessor.ProcessExpression(Expression expression) in f:\Разные штуки\Visual Studio 2008\Projects\OpenSource\NHibernate\nhibernate\src\NHibernate\Impl\ExpressionProcessor.cs:line 388&lt;br /&gt; at NHibernate.Impl.ExpressionProcessor.ProcessLambdaExpression(LambdaExpression expression) in f:\Разные штуки\Visual Studio 2008\Projects\OpenSource\NHibernate\nhibernate\src\NHibernate\Impl\ExpressionProcessor.cs:line 395&lt;br /&gt; at NHibernate.Impl.ExpressionProcessor.ProcessExpression[T](Expression`1 expression) in f:\Разные штуки\Visual Studio 2008\Projects\OpenSource\NHibernate\nhibernate\src\NHibernate\Impl\ExpressionProcessor.cs:line 406&lt;br /&gt; at NHibernate.Criterion.QueryOver`2.Add(Expression`1 expression) in f:\Разные штуки\Visual Studio 2008\Projects\OpenSource\NHibernate\nhibernate\src\NHibernate\Criterion\QueryOver.cs:line 568&lt;br /&gt; at NHibernate.Criterion.QueryOver`2.Where(Expression`1 expression) in f:\Разные штуки\Visual Studio 2008\Projects\OpenSource\NHibernate\nhibernate\src\NHibernate\Criterion\QueryOver.cs:line 248&lt;br /&gt; at NHibernate.Criterion.QueryOver`2.NHibernate.IQueryOver&lt;troot,tsubtype&gt;.Where(Expression`1 expression) in f:\Разные штуки\Visual Studio 2008\Projects\OpenSource\NHibernate\nhibernate\src\NHibernate\Criterion\QueryOver.cs:line 619&lt;br /&gt;&lt;br /&gt;The code I have is quite innocent:&lt;br /&gt;Return _session.QueryOver(Of User).Where(_&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;Function(aUser) aUser.Name = userName).List().First&lt;br /&gt;&lt;br /&gt;It returns the first instance of the User class that matches the Name property. The problem is that the VB compiler transforms the lambda into something like&lt;br /&gt;(CompareString(aUser.Name, value(Web.Controllers.Membership.AccountMembershipService+_Closure$__1).$VB$Local_userName, False) = 0)&lt;br /&gt;&lt;br /&gt;Now, CompareString is a shared method of the Microsoft.VisualBasic.CompilerServices.Operators class, which is probably not something the NHibernate developers expected to appear in a lambda. Time for a patch. A quick fix is to add the following piece of code in the beginning of the NHibernate.Impl.ExpressionProcessor.ProcessSimpleExpression method:&lt;br /&gt;&lt;br /&gt;if (be.Left.NodeType == ExpressionType.Call) {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;var left = (MethodCallExpression) be.Left;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;if (left.Method.Name == "CompareString") {&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return ProcessSimpleExpression(Expression.Equal(left.Arguments[0], left.Arguments[1]));&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;Actually, the CompareString method has 3 arguments. The third one, when set to false, signifies the literal comparison, while being set to true means textual (case insensitive) comparison. So, if you use the LIKE operator, you might want to check for left.Arguments[2].&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-2047546705821892179?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/2047546705821892179'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/2047546705821892179'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2010/04/using-latest-nhibernate-features-in.html' title='Using the latest NHibernate features in your VB.Net code.'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-1759323695066663142</id><published>2010-02-21T20:03:00.002+03:00</published><updated>2010-02-21T20:07:04.932+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ivonna'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Ivonna 2.1 is out</title><content type='html'>Finally, the next release of Ivonna is out! You can read more about this release &lt;a href="http://sm-art.biz/ivonna-21-is-out.aspx"&gt;here&lt;/a&gt;. For those of you unfamiliar with Ivonna, it is server-side &lt;a href="http://sm-art.biz/Ivonna.aspx"&gt;Asp.Net unit and integration testing tool&lt;/a&gt; I develop in partnership with TypeMock.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-1759323695066663142?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://sm-art.biz/ivonna-21-is-out.aspx' title='Ivonna 2.1 is out'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/1759323695066663142'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/1759323695066663142'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2010/02/ivonna-21-is-out.html' title='Ivonna 2.1 is out'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-2441920229944641191</id><published>2010-01-28T18:41:00.002+03:00</published><updated>2010-01-28T18:55:24.428+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='The Ugly Side'/><title type='text'>Fixing the " 'Telerik.Web.UI.GridInsertionObject' does not contain a property with the name" problem</title><content type='html'>Telerik's RadGrid has a handy possibility to insert a new object. Works fine with DataTables, but since I sure prefer using ObjectDataSources, sometimes I get the abovementioned exception when clicking the Insert button whenever the grid is empty.&lt;br /&gt;&lt;br /&gt;The problem is, the grid can't figure out the type of the new record when it doesn't have any records yet. This is sorta silly, since it is bound to an ObjectDataSource object and (theoretically) could get the class name from it. Anyway, it just creates an instance of Telerik.Web.UI.GridInsertionObject and then complains that it can't do the databinding.&lt;br /&gt;&lt;br /&gt;There are tons of solutions out there, even provided by the Telerik team, and they typically involve a lot of manual labour. Typically you would create an object yourself or provide some Dictionary with all properties initialized etc. Not exactly a DRY style of work.&lt;br /&gt;&lt;br /&gt;My solution is.. just return a generic List rather than an Enumerable for the Select method of your ObjectDataSource. For example, this&lt;br /&gt;&lt;blockquote style="color: rgb(51, 51, 51);"&gt;Return From product In Me.FetchAll Where product.CategoryId = categoryId&lt;/blockquote&gt;will give an exception when trying to add a record. Change it to&lt;br /&gt;&lt;blockquote style="color: rgb(51, 51, 51);"&gt;Return (From product In Me.FetchAll Where product.CategoryId = categoryId).ToList()&lt;/blockquote&gt;and you'll be fine.&lt;br /&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-2441920229944641191?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/2441920229944641191'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/2441920229944641191'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2010/01/fixing-telerikwebuigridinsertionobject.html' title='Fixing the &quot; &apos;Telerik.Web.UI.GridInsertionObject&apos; does not contain a property with the name&quot; problem'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-1629301695630935031</id><published>2009-12-31T01:54:00.003+03:00</published><updated>2009-12-31T02:41:37.161+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='The Ugly Side'/><title type='text'>ExecutionEngineException in Silverlight 3</title><content type='html'>I just started playing with Silverlight (you know, waiting for the patform to mature and stuff), plus I've got WCF on the other end, which I'm learning from scratch as well. So, I managed to make a working but messy project, and after that (ok, actually after it stopped compiling) I decided to start from scratch (ok, just copypaste the relevant bits of the working code).&lt;br /&gt;&lt;br /&gt;This is when my FireFox started to quietly die instead of showing me the results of the WCF query.&lt;br /&gt;&lt;br /&gt;Debugging gave me the exception, and it better didn't. It was the ill-famous ExecutionEngineException, something that, as MSDN itself admits, Should Never Happen. What's worse, the exception was somehow related to a MessageBox. I forgot to mention that I used an evaluation version of some control, and it was displaying a message box spontaneously inviting me to buy the full version. Googling told me that message boxes do cause such issues.&lt;br /&gt;&lt;br /&gt;Anyway, the actual problem was that I forgot to configure my service in web.config, so the actual exception was quite different. I was calling the service asynchronously, so the exception happened on a non-UI thread, and it could somehow interfere with the abovementioned message box.&lt;br /&gt;&lt;br /&gt;So, my guess is that the exception has been caused by these ingredients, in order of appearance:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;a message box;&lt;/li&gt;&lt;li&gt;unhandled exception&lt;/li&gt;&lt;li&gt;on a non-UI thread&lt;/li&gt;&lt;li&gt;possibly, some code in the Application_UnhandledException handler.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-1629301695630935031?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/1629301695630935031'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/1629301695630935031'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2009/12/executionengineexception-in-silverlight.html' title='ExecutionEngineException in Silverlight 3'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-694992046856517930</id><published>2009-12-21T18:36:00.002+03:00</published><updated>2009-12-21T20:10:37.066+03:00</updated><title type='text'>Experiment in persistence ignorance</title><content type='html'>Having read a lot about how cool NHibernate is in helping with persistence ignorance, I decided to check if I can go far enough with it. More precisely, I decided to check if I can live without the Id property on my entities.&lt;br /&gt;&lt;br /&gt;Now, you might ask, how do I show say products of a particular category. I mean, if I have a Web site, there should be some Url for it, and this Url should look like Products.aspx?CategoryId=1 or Products/List/CategoryId/1, whatever, but you should include the Id somehow. The answer is, you can always use session.Get() or session.Load() to get the entity by its Id, and the reverse is also true: you can use session.GetIdentifier() to retrieve the entity's Id.&lt;br /&gt;&lt;br /&gt;At the same time, I switched from entities to models in my pages (WebForms or MVC). Doing this was a big relief because I felt myself dirty when adding a lot of properties to my entities just for the purpose of viewing (like, CategoryName, ItemCount etc). On the other hand, it means a lot of additional boring work: creating model classes and adding the mapping code. Fortunately, the first task is easy with the help of T4 templates, while the second is what AutoMapper (and other mappers) is created for.&lt;br /&gt;&lt;br /&gt;Long story short, even though I managed to automate a lot, including the custom mapping code, I still got a lot of places where I had to repetively write session.GetIdentifier() in order to retrieve the Id. So, I'd recommend leaving it in place, although it doesn't seem to make much sense in terms of my domain.&lt;br /&gt;&lt;br /&gt;Disclaimer: by entities, models and stuff I don't want to say that I'm doing DDD or any other cool stuff. The system is too simple for that. Nevertheless, separating models from entities, provided it doesn't require much effort, pays off in my case.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-694992046856517930?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/694992046856517930'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/694992046856517930'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2009/12/experiment-in-persistence-ignorance.html' title='Experiment in persistence ignorance'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-4997861767410285605</id><published>2009-07-13T01:09:00.002+04:00</published><updated>2009-07-13T01:37:38.136+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Flex'/><category scheme='http://www.blogger.com/atom/ns#' term='The Ugly Side'/><title type='text'>Interacting with embedded Flash content in Flex</title><content type='html'>I've been doing some Flex development lately (sorry Microsoft), so I though I might share a little discovery of mine in return to numerous advices from the community.&lt;br /&gt;&lt;br /&gt;While creating a complex Flash application, it is a common situation that the graphical content and animations created by designers in Flash, while developers load them into a Flex application. While loading is pretty straightforward, often you need to manipulate them, i.e., play a different clip, detect then a clip reaches a certain label, etc. What you usually do is have your flash content have a certain base class (called Document class) which is known to your flex app, and cast loader.content to this class once it's loaded.&lt;br /&gt;&lt;br /&gt;The problem is, the above solution doesn't work with embedded content. Don't know whether it is a bug or a feature, but the content cannot be cast to the document class. The docs say, use embedded content for static stuff like images or static swfs. Well, my content was an intro to a module, and I had to detect it's finished playing in order to hide it and show the actual content. On the other hand, I wanted it embedded so that my preloader would work correctly. In addition, the module had a base class, and I wanted to have the intro-related code in the base class, while embedding the intro into the actual module.&lt;br /&gt;&lt;br /&gt;So, utilizing some hints from the community plus a little debugging session, and here's my solution (I still don't see any reason why it works this particular way).&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Embed the flash content via the metadata tag:        &lt;br /&gt;[Embed(source="../../flex_bin/someflash.swf", mimeType="application/x-shockwave-flash")]&lt;br /&gt;      private var SWFBytes:Class;&lt;/li&gt;&lt;li&gt;Use it in your SWFLoader (note the source):&lt;br /&gt;&amp;lt;mx:swfloader id="introLoader" source="{new SWFBytes()}" scalecontent="false" creationcomplete="intro_complete(event)"&gt;&lt;/li&gt;&lt;li&gt;Handle the CreationComplete event like this:&lt;br /&gt;var content:MovieClip= this["introLoader"].content as MovieClip;&lt;br /&gt;var loader:Loader = content.getChildAt(0) as Loader;&lt;br /&gt;var intro:RoomIntro = RoomIntro(loader.content);&lt;/li&gt;&lt;/ol&gt;Here's the "intro" variable we're interested it, RoomIntro is the document class of the flash movie. Note that the content of our loader is a movie clip, but it's not what we need: it has a child, which is another loader, and the content of *this* loader is what we actually need. In short, we need the content of the first child of the content of our loader.&lt;br /&gt;&lt;br /&gt;Tricky, eh?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-4997861767410285605?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/4997861767410285605'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/4997861767410285605'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2009/07/interacting-with-embedded-flash-content.html' title='Interacting with embedded Flash content in Flex'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-6316171202871598017</id><published>2009-05-19T18:59:00.001+04:00</published><updated>2009-05-19T19:30:22.277+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ivonna'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Get a free TypeMock Isolator + Ivonna</title><content type='html'>&lt;a href="http://www.typemock.com/"&gt;Unit Testing&lt;/a&gt; ASP.NET? &lt;a href="http://www.typemock.com/ASP.NET_unit_testing_page.php"&gt;ASP.NET unit testing&lt;/a&gt; has never been this easy.&lt;br /&gt;&lt;br /&gt;Typemock is launching a new product for ASP.NET developers – the &lt;strong&gt;ASP.NET Bundle&lt;/strong&gt; - and for the launch will be giving out &lt;span style="color: rgb(0, 102, 0);"&gt;&lt;strong&gt;FREE licenses&lt;/strong&gt;&lt;/span&gt; to bloggers and their readers.&lt;br /&gt;&lt;br /&gt;The ASP.NET Bundle is the ultimate ASP.NET unit testing solution, and offers both &lt;a href="http://www.typemock.com/"&gt;Typemock Isolator&lt;/a&gt;, a &lt;a href="http://www.typemock.com/"&gt;unit test&lt;/a&gt; tool and &lt;a href="http://sm-art.biz/Ivonna.aspx"&gt;Ivonna&lt;/a&gt;, the Isolator add-on for &lt;a href="http://sm-art.biz/Ivonna.aspx"&gt;ASP.NET unit testing&lt;/a&gt;, for a bargain price.&lt;br /&gt;&lt;br /&gt;Typemock Isolator is a leading &lt;a href="http://www.typemock.com/"&gt;.NET unit testing&lt;/a&gt; tool (C# and VB.NET) for many ‘hard to test’ technologies such as &lt;a href="http://typemock.com/sharepointpage.php"&gt;SharePoint&lt;/a&gt;, &lt;a href="http://www.typemock.com/ASP.NET_unit_testing_page.php"&gt;ASP.NET&lt;/a&gt;, &lt;a href="http://www.typemock.com/ASP.NET_unit_testing_page.php"&gt;MVC&lt;/a&gt;, &lt;a href="http://www.typemock.com/wcfpage.php"&gt;WCF&lt;/a&gt;, WPF, &lt;a href="http://www.typemock.com/Silverlight_unit_testing_page.php"&gt;Silverlight&lt;/a&gt; and more. Note that for &lt;a href="http://www.typemock.com/Silverlight_unit_testing_page.php"&gt;unit testing Silverlight&lt;/a&gt; there is an open source Isolator add-on called &lt;a href="http://www.typemock.com/Silverlight_unit_testing_page.php"&gt;SilverUnit&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The first 60 bloggers who will blog this text in their blog and &lt;a href="http://blog.typemock.com/2009/05/get-free-typemock-licenses-aspnet.html"&gt;tell us about it&lt;/a&gt;, will get a Free Isolator ASP.NET Bundle license (Typemock Isolator + Ivonna). If you post this in an ASP.NET &lt;strong&gt;dedicated&lt;/strong&gt; blog, you'll get a license automatically (even if more than 60 submit) during the first week of this announcement.&lt;br /&gt;&lt;br /&gt;Also 8 bloggers will get an &lt;strong&gt;additional 2 licenses&lt;/strong&gt; (each) to give away to their readers / friends.&lt;br /&gt;&lt;br /&gt;Go ahead, click the following link for &lt;a href="http://blog.typemock.com/2009/05/get-free-typemock-licenses-aspnet.html"&gt;more information &lt;/a&gt;on how to get your free license.&lt;script src="http://shots.snap.com//client/inject.js?site_name=0" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-6316171202871598017?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://blog.typemock.com/' title='Get a free TypeMock Isolator + Ivonna'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/6316171202871598017'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/6316171202871598017'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2009/05/get-free-typemock-isolator-ivonna.html' title='Get a free TypeMock Isolator + Ivonna'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-8012129434530310176</id><published>2008-11-24T00:19:00.004+03:00</published><updated>2009-04-17T15:10:51.853+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CodeProject'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Unit testing private methods.. not again!</title><content type='html'>This is a question often raised on TDD forums. How do I test a private (protected, internal, Friend) method. Those not so bold ask, should I? A typical answer is, if you want to test a private method, extract it into another class and make it public, and make the first class hold a private instance of this new class.&lt;br /&gt;&lt;br /&gt;I think that this answer is too general. While newbies generally want a universal recipe (and this one is good enough), I'd start gathering more info. Like a Zen master wannabe, I'd ask a question which should be an answer to the original one. Oh, and then I'd ask some more.&lt;br /&gt;&lt;br /&gt;So, &lt;span style="font-weight: bold;"&gt;why&lt;/span&gt; do you want to test it?&lt;br /&gt;&lt;br /&gt;Is it just the idea that every method in a class should be tested? Then resist this temptation.&lt;br /&gt;&lt;br /&gt;Another option is that your public method that calls your private method just started acting weird. Well, the next question, what portion of the code just changed that caused this behavior? Still another option, that you &lt;span style="font-weight: bold;"&gt;dared to write some code without writing the test first&lt;/span&gt;, and now you're trying to cover your ass. My humble advice would be to delete the bastard and start all over.&lt;br /&gt;&lt;br /&gt;But there are several other important questions to ask. Does the private method have a well defined semantic meaning? If yes, why do you resist making it public? Are you afraid that someone will call it? Why? Are you lazy to document it?&lt;br /&gt;&lt;br /&gt;The only reason I can accept here is that your private method puts a system into an inconsistent state. For example, you can have a public Transfer method, which takes money from one account and moves it to another. The two private methods would be manipulation the two respective accounts. If you call one of them, some money would be, say, taken from one account but not moved to the other. In this case, it is unacceptable to move the method to another class and make it public: calling it from outside would be a disaster. In this case, I would simply refactor the system so that no such method exists.&lt;br /&gt;&lt;br /&gt;As this begins to sound &lt;span style="font-style: italic;"&gt;very&lt;/span&gt; confusing, I'd give some reasons for choosing what to test.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;A test is a usage example, a documentation in an executable form. A &lt;span style="font-style: italic;"&gt;unit test&lt;/span&gt; is, more or less, a feature: you provide a code example on how to use your product. This might be wrong for desktop or Web applications, but the essence remains the same. It would be weird to provide a usage example for a private method.&lt;/li&gt;&lt;li&gt;One of the main reasons for hiding a method is "encapsulation", as the proponents put it. In other words, you want to hide the implementation details. This is usually a good idea, given that you have a solid reason to do so. Typically, the reason is that you might change it in the future. So, the simple logic conclusion is that you shouldn't test it, since it makes your tests brittle. On the other hand, if you make it public, nothing prevents you from making a changed version later, and keeping this one unchanged (or maybe enhanced, but keeping the same functionality).&lt;/li&gt;&lt;li&gt;Still another reason: if I make all these methods public, my API will be bloated, and my customers confused. This is a valid reason only for those who are lazy enough to write a good doc. Other possible solutions are: use the EditorBrowsableAttribute; move this method to another class (here we go again!), and place this class in the Internals namespace (or invent some ever more scary name).&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;script src="http://shots.snap.com//client/inject.js?site_name=0" type="text/javascript"&gt;&lt;/script&gt;&lt;script src="http://shots.snap.com//client/inject.js?site_name=0" type="text/javascript"&gt;&lt;/script&gt;&lt;script src="http://shots.snap.com//client/inject.js?site_name=0" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-8012129434530310176?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/8012129434530310176'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/8012129434530310176'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2008/11/unit-testing-private-methods-not-again.html' title='Unit testing private methods.. not again!'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-573246677468042747</id><published>2008-11-10T16:29:00.002+03:00</published><updated>2008-11-10T17:08:31.466+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='The Ugly Side'/><title type='text'>Localizing the GridView date values</title><content type='html'>This is weird. I should have bumped into this problem ages ago. The problem is, whenever I'm trying to enter a localized date into a datagrid, it is saved as if it were an American date. I.e., 1.02.2008, which is the 1st of February, is saved as 01/02/08 (January 2nd).&lt;br /&gt;&lt;br /&gt;Setting the page's Culture to Russian didn't work. A quick Reflectoring showed that ObjectDataSource uses InvariantCulture for parsing the supplied values.&lt;br /&gt;&lt;br /&gt;The solution is sort of ugly: use the grid's Updating event and swap the string with the corresponding date:&lt;br /&gt;&lt;div style="background: rgb(63, 63, 63) none repeat scroll 0% 0%; font-family: Consolas; font-size: 8pt; color: rgb(220, 220, 204); -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"&gt; &lt;pre style="margin: 0px;"&gt;    &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;Protected&lt;/span&gt; &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;Sub&lt;/span&gt; &lt;span style="color: rgb(223, 223, 191);"&gt;gridDjSchedules_RowUpdating&lt;/span&gt;(&lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;ByVal&lt;/span&gt; &lt;span style="color: rgb(223, 223, 191);"&gt;sender&lt;/span&gt; &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;As&lt;/span&gt; &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;Object&lt;/span&gt;, &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;ByVal&lt;/span&gt; &lt;span style="color: rgb(223, 223, 191);"&gt;e&lt;/span&gt; &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;As&lt;/span&gt; &lt;span style="color: rgb(223, 223, 191);"&gt;System&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;Web&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;UI&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;WebControls&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;GridViewUpdateEventArgs&lt;/span&gt;)&lt;/pre&gt; &lt;pre style="margin: 0px;"&gt;        &lt;span style="color: rgb(223, 223, 191);"&gt;e&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;NewValues&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"TheDate"&lt;/span&gt;) = &lt;span style="color: rgb(223, 223, 191);"&gt;Convert&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;ToDateTime&lt;/span&gt;(&lt;span style="color: rgb(223, 223, 191);"&gt;e&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;NewValues&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"TheDate"&lt;/span&gt;), &lt;span style="color: rgb(223, 223, 191);"&gt;System&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;Globalization&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;CultureInfo&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;CurrentCulture&lt;/span&gt;)&lt;/pre&gt; &lt;pre style="margin: 0px;"&gt;    &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;End&lt;/span&gt; &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;Sub&lt;/span&gt;&lt;/pre&gt; &lt;/div&gt; &lt;br /&gt;Looks like it's time to create a custom control..&lt;br /&gt;&lt;script src="http://shots.snap.com//client/inject.js?site_name=0" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-573246677468042747?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/573246677468042747'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/573246677468042747'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2008/11/localizing-gridview-date-values.html' title='Localizing the GridView date values'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-2772197288379370266</id><published>2008-10-14T13:13:00.002+04:00</published><updated>2008-10-14T13:35:55.824+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CMS'/><title type='text'>In search of a developer-friendly CMS</title><content type='html'>After a lot of frustration with DotNetNuke, which was quite a while ago, and some recent adventures with &lt;a href="http://www.mojoportal.com/"&gt;mojoPortal &lt;/a&gt;(by the way, Joe, the maintainer and almost a single contributor for this project, does excellent job fixing all the bugs in no time after they are reported), I decided that no way I'm gonna use a CMS again, ever. Yes, I used it on my own site, &lt;a href="http://sm-art.biz"&gt;http://sm-art.biz&lt;/a&gt;, but then, it required no custom modules.&lt;br /&gt;&lt;br /&gt;The problem is, all these frameworks focus on how simple it is to get your site up and running, provided that you don't need any additional functionality, other than included in one of the million modules. When you start to add something that is unique to this site, you quickly realize that it's much simpler to start from scratch than follow the module development guidelines. At the very least, they require that youк module inherits from a base class, and is initialized in such a way that it is totally impossible to test it outside of the framework.&lt;br /&gt;&lt;br /&gt;So, here are the qualities of a CMS I wish existed. Has anybody seen this puppy?&lt;br /&gt;&lt;br /&gt;1. Respect the composition-over-inheritance principle. Don't make me inherit, let me use a plain old ascx control.&lt;br /&gt;2. Make it simle to plug this control into my site. Don't make me write these manifests and put sql scripts in a predefined place. However, I do want this possibility to exist, and also custom installer classes.&lt;br /&gt;3. Use Convention over Configuration, it's the latest trend.&lt;br /&gt;4. Make it decoupled. I don't want to see a column "totalforumposts" in the users table.&lt;br /&gt;5. Use Ivonna for testing, I don't want a buggy product :)&lt;br /&gt;6. I want to go from a regular site to a CMS and back in small steps. I want to be able to use various parts of it independently and switch off other parts if necessary. It should be more like a framework. There shouldn't be one "switch to a CMS" step, but rather start using various pieces one by one.&lt;br /&gt;&lt;br /&gt;Until I see something like this, I'll be trying to write my own.&lt;br /&gt;&lt;script src="http://shots.snap.com//client/inject.js?site_name=0" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-2772197288379370266?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/2772197288379370266'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/2772197288379370266'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2008/10/in-search-of-developer-friendly-cms.html' title='In search of a developer-friendly CMS'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-7289036288890604219</id><published>2008-07-29T15:07:00.002+04:00</published><updated>2009-04-17T15:12:44.640+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><category scheme='http://www.blogger.com/atom/ns#' term='CodeProject'/><title type='text'>A Dose Of Code</title><content type='html'>&lt;div id="ctl01_mainContent_ctl02_divSingleItem" class="modulecontent"&gt;&lt;p&gt;While developing Ivonna, I often have to figure out how various stuff in System.Web works. Sometimes Reflectoring it is enough; however, there are some particularly gigantic methods, full of loops and branches, that are hard to figure out. In any case, Reflector gives a static picture, while I need to see it live. Sure now you can download the source and debug through it (although I've never managed), but the real hackers don't use debuggers, preferring asserts and console output.&lt;br /&gt;&lt;br /&gt;Anyway, I needed to inject some code (or stop the debugger) at some particular method call in some assembly I don't have the code of. I've been using the TypeMock's MockMethodCalled event for it. After a while, it became tedious, so I decided to put some repetitive code into a class. Soon I found that it could have a couple of more useful features, but I wanted it to be really simple, and I didn't need much, so I'm keeping it to one class, three methods, three relaxed evenings of development.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;How does it work.&lt;/b&gt;&lt;/p&gt; &lt;ol&gt;&lt;li&gt;Create an instance of Njector using the target type (this is something like creating a mocked instance).&lt;/li&gt;&lt;li&gt;Add one or more injected pieces of code (something similar to adding expectations).&lt;/li&gt;&lt;li&gt;Call the main code, in which an instance of the target type is created, and the target methods are called.&lt;/li&gt;&lt;li&gt;The injected pieces are invoked before, after, or instead of the target methods. You also gain access to the target instance, target method parameters, and return value (in case you use the After injection).&lt;/li&gt;&lt;/ol&gt; &lt;p&gt;&lt;br /&gt;&lt;b&gt;Example&lt;/b&gt;&lt;br /&gt;This is something that I actually used to figure out how the System.Web.HttpMultipartContentTemplateParser class parses the input using the ParseIntoElementList method. This method has several loops and branches, so it's not easy to find out what's happening given a particular piece of data. What you see here is just the preparation; after that I prepare the input data and call the framework code using Ivonna, but that's outside the scope of this post. GetPrivateField() is an utility extension method doing guess what.&lt;/p&gt; &lt;div   style="background: rgb(63, 63, 63) none repeat scroll 0% 50%; color: rgb(220, 220, 204); -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:8pt;"&gt;&lt;div   style="background: rgb(63, 63, 63) none repeat scroll 0% 50%; color: rgb(220, 220, 204); -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:8pt;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;var&lt;/span&gt; &lt;span style="color: rgb(223, 223, 191);"&gt;web&lt;/span&gt; = &lt;span style="color: rgb(240, 223, 175);"&gt;Assembly&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;GetAssembly&lt;/span&gt;(&lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;typeof&lt;/span&gt;(&lt;span style="color: rgb(223, 223, 191);"&gt;System&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;Web&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;HttpRequest&lt;/span&gt;));&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;var&lt;/span&gt; &lt;span style="color: rgb(223, 223, 191);"&gt;parserType&lt;/span&gt; = &lt;span style="color: rgb(223, 223, 191);"&gt;web&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;GetType&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"System.Web.HttpMultipartContentTemplateParser"&lt;/span&gt;, &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;true&lt;/span&gt;, &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;true&lt;/span&gt;);&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;var&lt;/span&gt; &lt;span style="color: rgb(223, 223, 191);"&gt;inject&lt;/span&gt; = &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;new&lt;/span&gt; &lt;span style="color: rgb(240, 223, 175);"&gt;Njector&lt;/span&gt;(&lt;span style="color: rgb(223, 223, 191);"&gt;parserType&lt;/span&gt;);&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(223, 223, 191);"&gt;inject&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;After&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"GetNextLine"&lt;/span&gt;, &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;null&lt;/span&gt;, &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;delegate&lt;/span&gt;(&lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;object&lt;/span&gt; &lt;span style="color: rgb(223, 223, 191);"&gt;target&lt;/span&gt;, &lt;span style="color: rgb(240, 223, 175);"&gt;MethodBase&lt;/span&gt; &lt;span style="color: rgb(223, 223, 191);"&gt;method&lt;/span&gt;, &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;object&lt;/span&gt;[] &lt;span style="color: rgb(223, 223, 191);"&gt;parameters&lt;/span&gt;, &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;object&lt;/span&gt; &lt;span style="color: rgb(223, 223, 191);"&gt;retValue&lt;/span&gt;) {&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color: rgb(240, 223, 175);"&gt;Console&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;WriteLine&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"GetNextLine: {0}"&lt;/span&gt;, &lt;span style="color: rgb(223, 223, 191);"&gt;retValue&lt;/span&gt;);&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color: rgb(240, 223, 175);"&gt;Console&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;WriteLine&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"Pos={0}"&lt;/span&gt;, &lt;span style="color: rgb(223, 223, 191);"&gt;target&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;GetPrivateField&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"_pos"&lt;/span&gt;));&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color: rgb(240, 223, 175);"&gt;Console&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;WriteLine&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"line={0}"&lt;/span&gt;, &lt;span style="color: rgb(223, 223, 191);"&gt;target&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;GetPrivateField&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"_lineStart"&lt;/span&gt;));&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color: rgb(240, 223, 175);"&gt;Console&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;WriteLine&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"partDataStart={0}"&lt;/span&gt;, &lt;span style="color: rgb(223, 223, 191);"&gt;target&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;GetPrivateField&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"_partDataStart"&lt;/span&gt;));&lt;/p&gt; &lt;p style="margin: 0px;"&gt;});&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(223, 223, 191);"&gt;inject&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;After&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"AtBoundaryLine"&lt;/span&gt;, &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;null&lt;/span&gt;, &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;delegate&lt;/span&gt;(&lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;object&lt;/span&gt; &lt;span style="color: rgb(223, 223, 191);"&gt;target&lt;/span&gt;, &lt;span style="color: rgb(240, 223, 175);"&gt;MethodBase&lt;/span&gt; &lt;span style="color: rgb(223, 223, 191);"&gt;method&lt;/span&gt;, &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;object&lt;/span&gt;[] &lt;span style="color: rgb(223, 223, 191);"&gt;parameters&lt;/span&gt;, &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;object&lt;/span&gt; &lt;span style="color: rgb(223, 223, 191);"&gt;retValue&lt;/span&gt;) {&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color: rgb(240, 223, 175);"&gt;Console&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;WriteLine&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"AtBoundaryLine: {0}"&lt;/span&gt;, &lt;span style="color: rgb(223, 223, 191);"&gt;retValue&lt;/span&gt;);&lt;/p&gt; &lt;p style="margin: 0px;"&gt;});&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(223, 223, 191);"&gt;inject&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;After&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"AtEndOfData"&lt;/span&gt;, &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;null&lt;/span&gt;, &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;delegate&lt;/span&gt;(&lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;object&lt;/span&gt; &lt;span style="color: rgb(223, 223, 191);"&gt;target&lt;/span&gt;, &lt;span style="color: rgb(240, 223, 175);"&gt;MethodBase&lt;/span&gt; &lt;span style="color: rgb(223, 223, 191);"&gt;method&lt;/span&gt;, &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;object&lt;/span&gt;[] &lt;span style="color: rgb(223, 223, 191);"&gt;parameters&lt;/span&gt;, &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;object&lt;/span&gt; &lt;span style="color: rgb(223, 223, 191);"&gt;retValue&lt;/span&gt;) {&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color: rgb(240, 223, 175);"&gt;Console&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;WriteLine&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"AtEndOfData: {0}"&lt;/span&gt;, &lt;span style="color: rgb(223, 223, 191);"&gt;retValue&lt;/span&gt;);&lt;/p&gt; &lt;p style="margin: 0px;"&gt;});&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(223, 223, 191);"&gt;inject&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;After&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"ParsePartHeaders"&lt;/span&gt;, &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;null&lt;/span&gt;, &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;delegate&lt;/span&gt;( &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;object&lt;/span&gt; &lt;span style="color: rgb(223, 223, 191);"&gt;target&lt;/span&gt;, &lt;span style="color: rgb(240, 223, 175);"&gt;MethodBase&lt;/span&gt; &lt;span style="color: rgb(223, 223, 191);"&gt;method&lt;/span&gt;,&lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;object&lt;/span&gt;[] &lt;span style="color: rgb(223, 223, 191);"&gt;parameters&lt;/span&gt;, &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;object&lt;/span&gt; &lt;span style="color: rgb(223, 223, 191);"&gt;retValue&lt;/span&gt;) {&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color: rgb(240, 223, 175);"&gt;Console&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;WriteLine&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"ParsePartHeaders"&lt;/span&gt;);&lt;/p&gt; &lt;p style="margin: 0px;"&gt;});&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(223, 223, 191);"&gt;inject&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;Before&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"ParsePartData"&lt;/span&gt;, &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;null&lt;/span&gt;, &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;delegate&lt;/span&gt;(&lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;object&lt;/span&gt; &lt;span style="color: rgb(223, 223, 191);"&gt;target&lt;/span&gt;, &lt;span style="color: rgb(240, 223, 175);"&gt;MethodBase&lt;/span&gt; &lt;span style="color: rgb(223, 223, 191);"&gt;method&lt;/span&gt;, &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;object&lt;/span&gt;[] &lt;span style="color: rgb(223, 223, 191);"&gt;parameters&lt;/span&gt;, &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;object&lt;/span&gt; &lt;span style="color: rgb(223, 223, 191);"&gt;retValue&lt;/span&gt;) {&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color: rgb(240, 223, 175);"&gt;Console&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;WriteLine&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"ParsePartData Before"&lt;/span&gt;);&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color: rgb(240, 223, 175);"&gt;Console&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;WriteLine&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"Pos={0}"&lt;/span&gt;, &lt;span style="color: rgb(223, 223, 191);"&gt;target&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;GetPrivateField&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"_pos"&lt;/span&gt;));&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color: rgb(240, 223, 175);"&gt;Console&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;WriteLine&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"line={0}"&lt;/span&gt;, &lt;span style="color: rgb(223, 223, 191);"&gt;target&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;GetPrivateField&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"_lineStart"&lt;/span&gt;));&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color: rgb(127, 159, 127);"&gt;//System.Diagnostics.Debugger.Break();&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;});&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(223, 223, 191);"&gt;inject&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;After&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"ParsePartData"&lt;/span&gt;, &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;null&lt;/span&gt;, &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;delegate&lt;/span&gt;(&lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;object&lt;/span&gt; &lt;span style="color: rgb(223, 223, 191);"&gt;target&lt;/span&gt;, &lt;span style="color: rgb(240, 223, 175);"&gt;MethodBase&lt;/span&gt; &lt;span style="color: rgb(223, 223, 191);"&gt;method&lt;/span&gt;, &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;object&lt;/span&gt;[] &lt;span style="color: rgb(223, 223, 191);"&gt;parameters&lt;/span&gt;, &lt;span style="color: rgb(234, 234, 172); font-weight: bold;"&gt;object&lt;/span&gt; &lt;span style="color: rgb(223, 223, 191);"&gt;retValue&lt;/span&gt;) {&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color: rgb(240, 223, 175);"&gt;Console&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;WriteLine&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"ParsePartData After"&lt;/span&gt;);&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color: rgb(240, 223, 175);"&gt;Console&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;WriteLine&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"Pos={0}"&lt;/span&gt;, &lt;span style="color: rgb(223, 223, 191);"&gt;target&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;GetPrivateField&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"_pos"&lt;/span&gt;));&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color: rgb(240, 223, 175);"&gt;Console&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;WriteLine&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"line={0}"&lt;/span&gt;, &lt;span style="color: rgb(223, 223, 191);"&gt;target&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;GetPrivateField&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"_lineStart"&lt;/span&gt;));&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color: rgb(240, 223, 175);"&gt;Console&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;WriteLine&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"partDataLength={0}"&lt;/span&gt;, &lt;span style="color: rgb(223, 223, 191);"&gt;target&lt;/span&gt;.&lt;span style="color: rgb(223, 223, 191);"&gt;GetPrivateField&lt;/span&gt;(&lt;span style="color: rgb(200, 145, 145);"&gt;"_partDataLength"&lt;/span&gt;));&lt;/p&gt; &lt;p style="margin: 0px;"&gt;});&lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(127, 159, 127);"&gt;//Prepare the data&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(127, 159, 127);"&gt;//Do the POST&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(127, 159, 127);"&gt;//The framework creates an instance of System.Web.HttpMultipartContentTemplateParser and calls its ParseIntoElementList method, &lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(127, 159, 127);"&gt;//which in turn calls the methods like GetNextLine, AtBoundaryLine, etc.&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(127, 159, 127);"&gt;//After the GetNextLine method is called, our code is executed, and we're able to see the result. &lt;/span&gt;&lt;/p&gt; &lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;br /&gt;Download the source &lt;a href="http://sm-art.biz/NJect.aspx"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Update: there's a much better project now, called &lt;a href="http://www.codeplex.com/CThru"&gt;CThru&lt;/a&gt;, developed by TypeMock.&lt;br /&gt;&lt;script src="http://shots.snap.com//client/inject.js?site_name=0" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-7289036288890604219?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://sm-art.biz/NJect.aspx' title='A Dose Of Code'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/7289036288890604219'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/7289036288890604219'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2008/07/dose-of-code.html' title='A Dose Of Code'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-8891967971338817761</id><published>2008-05-29T23:47:00.003+04:00</published><updated>2009-04-17T15:12:58.218+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='CodeProject'/><title type='text'>Multiple AppDomains on a single Web</title><content type='html'>I was getting some weird errors when using a &lt;a href="http://neo.sourceforge.net/"&gt;Neo&lt;/a&gt; ObjectContext on a Web as a global variable. This thing is supposed to be dependency-injected into factories and stuff, but I've set it to be a static property long time ago and saved me a lot of effort, since most stuff became possible with the Neo code generation tool.&lt;br /&gt;&lt;br /&gt;This was long before I learned that singletons are evil.&lt;br /&gt;&lt;br /&gt;Anyway, I've been getting very weird errors. Such as, I see a page with a record that should have been deleted, I refresh the page and it's not there, I refresh it again and it's there etc. It looked as if there were two contexts, and the record has been deleted from only one of them. However, since a Context was a static variable, there couldn't possibly be two contexts, right?&lt;br /&gt;&lt;br /&gt;Or so I thought. Recently, I've been investigating the whole remoting thing in connection with Ivonna, and I discovered the trivial fact that different static variables exist in different AppDomains. So, I thought that maybe there are two AppDomains for the same site? A quick experiment showed that this is true indeed, if there are two (almost) simultaneous requests.&lt;br /&gt;&lt;br /&gt;And the moral of the story is.. dunno, will figure out tomorrow.&lt;script src="http://shots.snap.com//client/inject.js?site_name=0" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-8891967971338817761?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/8891967971338817761/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=8891967971338817761' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/8891967971338817761'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/8891967971338817761'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2008/05/multiple-appdomains-on-single-web.html' title='Multiple AppDomains on a single Web'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-6401887536287359429</id><published>2008-05-14T12:22:00.003+04:00</published><updated>2008-05-14T22:54:32.034+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Amazing stuff'/><title type='text'>LOLCode, DLR Edition</title><content type='html'>This is a code snippet that actually works.&lt;br /&gt;&lt;pre&gt;&lt;span style="font-family: courier new;"&gt;HAI&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;CAN HAS STDIO?&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;VISIBLE "HAI WORLD!"&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;I HAS A CODE ITZ "CRAZY"&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;VISIBLE CODE&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;I HAS A NUMBR&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;LOL NUMBR R 2&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;VISIBLE NUMBR TIEMZ 2&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;I HAS A FIB&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;I HAS A A ITZ 1&lt;/span&gt;&lt;br /&gt;I HAS A B ITZ 0&lt;br /&gt;&lt;br /&gt;It's written in &lt;a href="http://code.google.com/p/lolcode-dot-net/"&gt;LOLCode.NET&lt;/a&gt;, a brand new .Net language that quickly gathers support among agile developers. &lt;a href="http://www.hanselman.com/blog/TheWeeklySourceCode11LOLCodeDLREdition.aspx"&gt;Read the full story&lt;/a&gt; on the Scott Hanselman's &lt;a href="http://www.hanselman.com/blog/"&gt;blog&lt;/a&gt;.&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-6401887536287359429?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.hanselman.com/blog/TheWeeklySourceCode11LOLCodeDLREdition.aspx' title='LOLCode, DLR Edition'/><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/6401887536287359429/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=6401887536287359429' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/6401887536287359429'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/6401887536287359429'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2008/05/lolcode-dlr-edition.html' title='LOLCode, DLR Edition'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-616447036751847782</id><published>2008-05-11T22:17:00.004+04:00</published><updated>2009-04-17T15:13:37.259+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><category scheme='http://www.blogger.com/atom/ns#' term='CodeProject'/><title type='text'>Activating the Record</title><content type='html'>Lots of things happened since I last cared to blog. Here's the first one, chronologically. While I'm trying to not get too excited about Dependency Injection, I realized that it's about time to use some services in Inka, and I sort of needed an IoC container. My first idea was to use &lt;a href="http://structuremap.sourceforge.net/"&gt;StructureMap&lt;/a&gt; by &lt;a href="http://codebetter.com/blogs/jeremy.miller/default.aspx"&gt;Jeremy Miller&lt;/a&gt;, but I wanted an automocking container for my tests as well, and I was forced to choose &lt;a href="http://www.castleproject.org/container/index.html"&gt;Castle Windsor&lt;/a&gt;. Or so I thought at that time -- it turned out that, first, I didn't have time to implement these things, and second, StructureMap also has an automocking container. But that's not the point.&lt;br /&gt;&lt;br /&gt;The point is, I thought, hell, why not move to a decent ORM as well? Meaning Castle ActiveRecord.&lt;br /&gt;&lt;br /&gt;My first ORM was &lt;a href="http://neo.sourceforge.net/"&gt;Neo&lt;/a&gt; (Net Entity Objects, I think the name has been invented before The Matrix). Unlike Castle AR, which is really a nice interface for NHibernate, Neo is Active Record in a true sense. I'd even say, it's Typed DataSets Done Right. Each entity class is a wrapper over the DataRow class, so we can track the state (is it added, deleted, or modified) automatically. Each object is created via a factory, and added to the context automatically, so it can appear in your query results without being saved to a database. Cool. And also very convenient for testing.&lt;br /&gt;&lt;br /&gt;Speaking of testing, I still can't figure out how to test AR applications without a database connection.&lt;br /&gt;&lt;br /&gt;So, Neo is not for purists (nor is AR), they want POCOs. But I''m just a script kiddie, so it's OK for me. Neo's got a code generator, so I quickly enjoyed the idea and put all sorts of stuff into my templates, including some UI-related things. Don't blame me, I haven't heard about SoC in these days. In return, I managed to do some boilerplate stuff extra quickly.&lt;br /&gt;&lt;br /&gt;Unfortunately, there's a very small community around Neo, and the development seems to stop. I've fixed a few bugs, but never got to publishing the fixes (only recently I learned that I had violated the LPGL license). Also, it's pretty simple, and perhaps won't cover more complex situations, including fat query results.&lt;br /&gt;&lt;br /&gt;I'm only learning Active Record, and it has some very nice points (including a great graphic schema editor, Active Writer), but I've had some really weird moments with it. One, for example, is that I've been getting some weird exceptions that I wasn't able to reproduce in my tests. Almost intuitively, I invoked a Scope constructor at startup, and the problem was gone, although I never used the created scope variable  anywhere! Turned out there's some dirty game with shared (static in C# :) variables here and there. I used to wonder why people hate these statics, now I know!&lt;br /&gt;&lt;br /&gt;I'd like to learn more about AR, but now I'm totally thrilled by &lt;a href="http://sm-art.biz/Ivonna.aspx"&gt;Ivonna&lt;/a&gt; being released soon, so I'm leaving the applied programming world for a while..&lt;script src="http://shots.snap.com//client/inject.js?site_name=0" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-616447036751847782?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/616447036751847782/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=616447036751847782' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/616447036751847782'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/616447036751847782'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2008/05/activating-record.html' title='Activating the Record'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-6775618889949722675</id><published>2008-02-26T22:19:00.002+03:00</published><updated>2008-02-26T22:24:20.986+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Adventures in test-driven development'/><category scheme='http://www.blogger.com/atom/ns#' term='Inka'/><category scheme='http://www.blogger.com/atom/ns#' term='The Ugly Side'/><title type='text'>Oops</title><content type='html'>Hmm.. finally my layout engine for &lt;a href="https://sourceforge.net/projects/inka"&gt;Inka&lt;/a&gt; is ready. Or so I thought. All tests are green, well, some are yellow, but come on. I was sure that I over-tested it and began planning to dramatically reduce the number of tests -- I start a demo app and discover that everything looks wrong!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-6775618889949722675?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/6775618889949722675/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=6775618889949722675' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/6775618889949722675'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/6775618889949722675'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2008/02/oops.html' title='Oops'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-6765459702868812523</id><published>2008-02-21T12:35:00.004+03:00</published><updated>2009-04-17T15:16:57.153+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><category scheme='http://www.blogger.com/atom/ns#' term='Ivonna'/><category scheme='http://www.blogger.com/atom/ns#' term='CodeProject'/><title type='text'>Just can't help it!</title><content type='html'>Well, finally I'm at the point where I have to prepare an installer for Ivonna. Actually, I'm stuck at this point for about two weeks. Not because of installer itself, but because of the documentation. No, I diligently wrote all the xml comments, believe me. But these comments have to make way into a nice docs, preferably with some custom ("conceptual" in Sandcastle terms) content. And it has to be in Html Help 2.x format. This morning I finally discovered that my help can be viewed in the Document explorer. Was it because of the electricity been cut for a moment?&lt;br /&gt;&lt;br /&gt;Anyway, here's my recipe. I'll be using VS 2005 with the  2007 SDK, &lt;a href="http://www.codeplex.com/Sandcastle/Release/ProjectReleases.aspx?ReleaseId=9921"&gt;Sandcastle January 2008 release&lt;/a&gt;, and &lt;a href="http://www.codeplex.com/DocProject/Release/ProjectReleases.aspx?ReleaseId=8252"&gt;DocProject 1.10.0 RC&lt;/a&gt;.&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Install the VS SDK.&lt;/li&gt;&lt;li&gt;Install Sandcastle. It is important to install it after the SDK, because the SDK contains its own version of Sandcastle, which is too old. Anyway, if you installed Sandcastle first accidentally, just edit your DXROOT environment variable so that it points to the Sandcastle's folder.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Download and extract the &lt;a href="http://www.codeplex.com/SHFB/Release/ProjectReleases.aspx?ReleaseId=9848"&gt;presentation file patches&lt;/a&gt;. This fixes a bug in Sandcastle when you don't have a root topic.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Install DocProject. A major annoyance is a bug in the 1.10 RC version: the Add-in looks for the Project toolbar that has more than 40 items. Mine had only 38. The suggested workaround is to download the code and patch it manually, but I couldn't afford that, so, instead I wrote a macro that added 3 ugly entries to my Project menu. Anybody interested? &lt;span style="font-style: italic; font-weight: bold;"&gt;Update&lt;/span&gt;: there's a 1.10.1 version that supposedly fixed this bug.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Add a DocProject to your solution. You can add a DocSite project instead if you need online help (it will build the offline help as well).&lt;/li&gt;&lt;li&gt;You might want to modify some templates offered by the DocProject wizard. But don't remove the feedback section entirely -- you'll get a JavaScript error later.&lt;/li&gt;&lt;li&gt;Modify the AssemblyInfo.cs file to reflect your documentation title and organization.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Don't ever rebuild the project -- it'll lose some essential files.&lt;/li&gt;&lt;li&gt;In the project wizard or later in the DocProject properties (available as an additional context menu item for your project), select "build html 2.0".&lt;/li&gt;&lt;li&gt;You might want to select the fastest build option -- choose "none" in the "build assembler options".&lt;/li&gt;&lt;li&gt;Now, after building the project, you have an HxS file in your output folder.&lt;/li&gt;&lt;li&gt;Unlike a chm file, you can't open it directly. Instead, you have to register it and navigate to it using the special ms-help protocol.&lt;/li&gt;&lt;li&gt;So, how do you register it?&lt;/li&gt;&lt;li&gt;The manual steps recommended copying a certain merge module from the sdk directory and manually editing it with Orca.&lt;/li&gt;&lt;li&gt;Like I was going to do that.&lt;/li&gt;&lt;li&gt;Actually I even did a first step.&lt;/li&gt;&lt;li&gt;But it turned out that there's a new kind of extensibility projects called "Help Integration Wizard". What you want is create a merge module that you'll add to your installation project. The wizard is pretty trivial, and it stores all its settings in the CollectionFiles folder, so you can edit them manually later.&lt;/li&gt;&lt;li&gt;At the first step, I chose the help file that I discovered in the Help/bin folder of my DocSite project.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;The wizard showed me the structure of my future help. It contained one topic, called "sample topic" or something. it was on the left pane, and on the right there were my topics, conveniently excluded from the future help. I renamed the sample topic to "Ivonna", and added my topics under that root topic.&lt;/li&gt;&lt;li&gt;I also chose the namespace for my help -- ivonna.docs.&lt;/li&gt;&lt;li&gt;However, building the project didn't work for me, the postbuild event (the one that actually edited the merge module) failed. Invoking it manually from the command line failed as well. So, I opened the executable in the Reflector, and it turned out that it has been designed specifically in order to hide the possible cause of an error. For example, the exception was coming from a logging statement that was inside a catch block, so it was cleverly hiding the real exception. Also, all exception messages came from some native calls, so, for example, "File not found" turned into "Invalid handle".&lt;br /&gt;&lt;/li&gt;&lt;li&gt;So, I just wrote something that mimicked this app, and it somehow worked. Now I have a patched merge module that I can add to my installer. &lt;span style="font-weight: bold; font-style: italic;"&gt;Update&lt;/span&gt;: It turned out that the problem was with the path -- it contained cyrillic characters. Once I created another project in a different location, everything went smooth.&lt;/li&gt;&lt;li&gt;Now, you should add the merge module from this project to your setup. You should probably create a Help folder under your app folder, and choose it for the merge module files. Choose the merge module in your setup project, and choose the folder in the Properties, KeyOutput -&gt; MergeModuleProperties -&gt; Module Retargetable Folder.&lt;/li&gt;&lt;li&gt;By the way, you can see all installed help namespaces via a handy utility located here: \Program Files\Visual Studio 2005 SDK\2007.02\VisualStudioIntegration\Archive\HelpIntegration\Unsupported\Namespace.exe&lt;br /&gt;&lt;/li&gt;&lt;li&gt;You probably want to include a shortcut to your documentation. It should be something like this: "%CommonProgramFiles%\Microsoft Shared\Help 8\dexplore.exe" /helpcol ms-help://ivonna.docs. Note that I put my namespace after the "ms-help://" stuff. Yes, you are even able to view it in IE.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;After you successfully made the installer, you discover that when the documentation opens it shows an empty page. If you want an introduction or something to appear, you should register it as "DefaultPage". Details can be found &lt;a href="http://www.codeplex.com/DocProject/Thread/View.aspx?ThreadId=23252"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Modify your shortcut like this: "%CommonProgramFiles%\Microsoft Shared\Help 8\dexplore.exe" /helpcol ms-help://ivonna.docs /LaunchNamedUrlTopic DefaultPage.&lt;/li&gt;&lt;/ol&gt;By the way, you can download Ivonna from my new site &lt;a href="http://sm-art.biz/IvonnaDownload.aspx"&gt;here&lt;/a&gt;, and view the online docs (produced with DocProject) &lt;a href="http://ivonnadocs.sm-art.biz/"&gt;here&lt;/a&gt;. I'll be blogging about Ivonna on my site's blog.&lt;script src="http://shots.snap.com//client/inject.js?site_name=0" type="text/javascript"&gt;&lt;/script&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-6765459702868812523?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/6765459702868812523/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=6765459702868812523' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/6765459702868812523'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/6765459702868812523'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2008/02/just-cant-help-it.html' title='Just can&apos;t help it!'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-360207507035880583</id><published>2008-02-11T14:42:00.000+03:00</published><updated>2008-02-11T14:45:44.304+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Inka'/><title type='text'>Inka moved</title><content type='html'>Inka has finally changed its Unix name at SourceForge. You can find it at https://sourceforge.net/projects/inka.&lt;br /&gt;&lt;br /&gt;Also, I'm finally building me a site, and there'll be a lot about Inka and how it should be used. Find it at &lt;a href="http://sm-art.biz"&gt;http://sm-art.biz&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-360207507035880583?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/360207507035880583/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=360207507035880583' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/360207507035880583'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/360207507035880583'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2008/02/inka-moved.html' title='Inka moved'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-310092359333677676</id><published>2008-01-29T23:05:00.000+03:00</published><updated>2008-01-29T23:26:03.307+03:00</updated><title type='text'>Binding It Twice</title><content type='html'>Last week I, like a lot of other Asp.Net newbies, got a weird validation error on my page saying, "Invalid postback or callback argument". The funny thing is, I've got another error two days earlier, even more weird, saying, &lt;span&gt;&lt;/span&gt;&lt;h2 style="font-weight: normal;"&gt;&lt;span style="font-size:100%;"&gt;Item has already been added. Key in dictionary: 'ID'  Key being added: 'ID'&lt;/span&gt;&lt;/h2&gt;The weird thing about this error is that I was adding an item to a GridView via a regular mechanism, using the prescribed DetailsView and ObjectDataSource, no funky MVP stuff. The "ID" in this error refers to the key column.&lt;br /&gt;&lt;br /&gt;What caused the error in both cases was calling the DataBind method on postback, which you shouldn't usually do if you have ViewState enabled. In the second case, I blindly called DataBind on the page itself.&lt;br /&gt;&lt;br /&gt;So, the rule for other newbie who happen to read this:&lt;br /&gt;Whenever you init your page, call DataBind for the GridView only if you haven't set the DataSourceID, and always wrap it with "If Not IsPostBack".&lt;br /&gt;If you add/change your record via a DetailsView that is bound to the same DataSource, you don't have to call DataBind on postback, since the DataSource will notify the GridView of the change.&lt;br /&gt;If you add/change your record via some other means, call DataBind after it has been changed.&lt;br /&gt;&lt;br /&gt;Here's my stack trace for Google:&lt;br /&gt;&lt;span style="font-family:Arial, Helvetica, Geneva, SunSans-Regular, sans-serif ;"&gt;&lt;pre&gt;[ArgumentException: Item has already been added. Key in dictionary: 'ID'  Key being added: 'ID']&lt;br /&gt;  System.Collections.Hashtable.Insert(Object key, Object nvalue, Boolean add) +2904181&lt;br /&gt;  System.Collections.Hashtable.Add(Object key, Object value) +11&lt;br /&gt;  System.Collections.Specialized.OrderedDictionary.Add(Object key, Object value) +49&lt;br /&gt;  System.Web.UI.WebControls.DataKey.LoadViewState(Object state) +88&lt;br /&gt;  System.Web.UI.WebControls.DataKey.System.Web.UI.IStateManager.LoadViewState(Object state) +4&lt;br /&gt;  System.Web.UI.WebControls.GridView.LoadDataKeysState(Object state) +310&lt;br /&gt;  System.Web.UI.WebControls.GridView.LoadControlState(Object savedState) +450&lt;br /&gt;  System.Web.UI.Control.LoadControlStateInternal(Object savedStateObj) +118&lt;br /&gt;  System.Web.UI.Page.LoadAllState() +212&lt;br /&gt;  System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +109&lt;/pre&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-310092359333677676?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/310092359333677676/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=310092359333677676' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/310092359333677676'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/310092359333677676'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2008/01/binding-it-twice.html' title='Binding It Twice'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-3403124373385595738</id><published>2008-01-26T23:52:00.000+03:00</published><updated>2008-01-29T23:04:54.655+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><category scheme='http://www.blogger.com/atom/ns#' term='The Ugly Side'/><title type='text'>WAMPed up!</title><content type='html'>You know, I'm not a big fan of LAMP. Let's say, I frown when I hear something good about it, and I hide my smile when I hear something bad. OK, at least I don't write that Windows Must Die in any other forum.&lt;br /&gt;&lt;br /&gt;Apparently the Gods decided that it's time that I become more tolerant. First I had to make an Asp.Net site with mySql. It was sort of OK until a nasty bug deleted almost all our forums, and then they began to reappear out of some sort of mySql's recycle bin. But that's a different story.&lt;br /&gt;&lt;br /&gt;Now I have to maintain a PHP project, and I decided that, hey, let's be tolerant! PHP is a cool object oriented language now, let's give it a try!&lt;br /&gt;&lt;br /&gt;Installing Apache was no problem at all. I ran the default page, and it said in big bold letters, "It works!". That was cool.&lt;br /&gt;&lt;br /&gt;Installing PHP was pretty straightforward too. But it was too late, so I went to sleep.&lt;br /&gt;&lt;br /&gt;OK, now I'm going to check if my PHP works. Starting Apache and... there are lots of message boxes saying that httpd "&lt;span style="font-size:-1;"&gt;&lt;b&gt;This application has failed to start&lt;/b&gt; because php_mbstring.dll was not found" &lt;/span&gt;and then lots of others with different dll names. The poor beast tried again and again, so the messages won't stop until I killed it mercifully.&lt;br /&gt;&lt;br /&gt;I decided to repair the installation and switched off all the extensions. It started nice, no message boxes. But the test PHP page I tried to view still showed nothing. In fact it showed the PHP source.&lt;br /&gt;&lt;br /&gt;Later I discovered one possible cause. As somebody suggested, my PHP page contained something like &amp;lt;? phpinfo() ?&amp;gt;. This simplified syntax, it turned out, is switched off by default, you should write &amp;lt;?php phpinfo() ?&amp;gt; instead. Correct me if I'm wrong. But now that everything works, I can't verify this.&lt;br /&gt;&lt;br /&gt;So, what did I do? I installed one of the available WAMP packages: &lt;a href="http://sourceforge.net/projects/quickeasyphp/"&gt;EasyPHP&lt;/a&gt;. Works like a charm.. almost. A truly Windows-oriented application, it had minimum installation options. It even didn't ask me which of the three products (Apache, PHP, mySql) I want to install! And I was quite thankful, believe me. At least I didn't have to deal with environment paths, console commands, and huge ini files.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:-1;"&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-3403124373385595738?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/3403124373385595738/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=3403124373385595738' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/3403124373385595738'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/3403124373385595738'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2008/01/wamped-up.html' title='WAMPed up!'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-7525095485819289089</id><published>2008-01-12T17:26:00.000+03:00</published><updated>2008-01-14T00:27:51.461+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Adventures in test-driven development'/><title type='text'>Readonly properties and testability</title><content type='html'>Sometimes an execution step requires that a property value is calculated. This value is used then in the subsequent step. When you want to test the second step in isolation, you usually mock the property. If you use "traditional" mock frameworks, or manually constructed stubs, the property should be virtual, and your object should be injected into the process somehow. This makes your design extendable, since whenever somebody wants a different behaviour, she can override the implementation of this property, and inject the custom object into the process.&lt;br /&gt;&lt;br /&gt;Recently I discovered that the most flexible solution would be to create a special object that just transfers the data between the steps. You don't have to inject anything, if you want some custom data for the second step, you just create your data object manually. Without the dependency injection and inheritance requirements, the steps become completely isolated. You need some sort of controller to drive the flow, and your users can easily implement another controller with any of the steps replaced with different objects and different behaviour.&lt;br /&gt;&lt;br /&gt;However, sometimes you, like me, are attached to the old fashioned idea of keeping behaviour with data. You need your class to expose the property and calculate its value:&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1251\uc1 \deff0{\fonttbl{\f0\fnil\fcharset204\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red0\green128\blue0;}??\fs20         \cf3 Public\cf0  \cf3 Overridable\cf0  \cf3 ReadOnly\cf0  \cf3 Property\cf0  SomeProperty() \cf3 As\cf0  SomeClass\par ??            \cf3 Get\par ??\cf0                 \cf3 Dim\cf0  result \cf3 As\cf0  \cf3 New\cf0  SomeClass\par ??                \cf4 'Set some properties\par ??\cf0                 \cf3 Return\cf0  result\par ??            \cf3 End\cf0  \cf3 Get\par ??\cf0         \cf3 End\cf0  \cf3 Property} --&gt; &lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Public&lt;/span&gt; &lt;span style="color:blue;"&gt;Overridable&lt;/span&gt; &lt;span style="color:blue;"&gt;ReadOnly&lt;/span&gt; &lt;span style="color:blue;"&gt;Property&lt;/span&gt; SomeProperty() &lt;span style="color:blue;"&gt;As&lt;/span&gt; SomeClass&lt;/p&gt; &lt;p style="margin: 0px;margin-left: 10px;"&gt;               &lt;span style="color:blue;"&gt;Get&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;margin-left: 20px;"&gt;                      &lt;span style="color:blue;"&gt;Dim&lt;/span&gt; result &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;New&lt;/span&gt; SomeClass&lt;/p&gt; &lt;p style="margin: 0px;margin-left: 20px;"&gt;                      &lt;span style="color:green;"&gt;'Set some properties&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;margin-left: 20px;"&gt;                      &lt;span style="color:blue;"&gt;Return&lt;/span&gt; result&lt;/p&gt; &lt;p style="margin: 0px;margin-left: 10px;"&gt;               &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Get&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Property&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt; &lt;/div&gt;   The obvious solution is to calculate the property if you haven't set it yet, but still make it settable:&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1251\uc1 \deff0{\fonttbl{\f0\fnil\fcharset204\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red0\green128\blue0;}??\fs20         \cf3 Private\cf0  _someProperty \cf3 As\cf0  SomeClass\par ??        \cf3 Public\cf0  \cf3 Overridable\cf0  \cf3 Property\cf0  SomeProperty() \cf3 As\cf0  SomeClass\par ??            \cf3 Get\par ??\cf0                 \cf3 If\cf0  _someProperty \cf3 Is\cf0  \cf3 Nothing\cf0  \cf3 Then\cf0  _someProperty = CalculateValue()\par ??                \cf3 Return\cf0  _someProperty\par ??            \cf3 End\cf0  \cf3 Get\par ??\cf0             \cf3 Set\cf0 (\cf3 ByVal\cf0  value \cf3 As\cf0  SomeClass)\par ??                _someProperty = value\par ??            \cf3 End\cf0  \cf3 Set\par ??\cf0         \cf3 End\cf0  \cf3 Property\par ??\par ??\cf0         \cf3 Protected\cf0  \cf3 Overridable\cf0  \cf3 Function\cf0  CalculateValue() \cf3 As\cf0  SomeClass\par ??            \cf3 Dim\cf0  result \cf3 As\cf0  \cf3 New\cf0  SomeClass\par ??            \cf4 'Set some properties\par ??\cf0             \cf3 Return\cf0  result\par ??        \cf3 End\cf0  \cf3 Function} --&gt; &lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Private&lt;/span&gt; _someProperty &lt;span style="color:blue;"&gt;As&lt;/span&gt; SomeClass&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Public&lt;/span&gt; &lt;span style="color:blue;"&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;Property&lt;/span&gt; SomeProperty() &lt;span style="color:blue;"&gt;As&lt;/span&gt; SomeClass&lt;/p&gt; &lt;p style="margin: 0px;margin-left: 10px;"&gt;               &lt;span style="color:blue;"&gt;Get&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;margin-left: 20px;"&gt;                      &lt;span style="color:blue;"&gt;If&lt;/span&gt; _someProperty &lt;span style="color:blue;"&gt;Is&lt;/span&gt; &lt;span style="color:blue;"&gt;Nothing&lt;/span&gt; &lt;span style="color:blue;"&gt;Then&lt;/span&gt; _someProperty = CalculateValue()&lt;/p&gt; &lt;p style="margin: 0px;margin-left:20px;"&gt;                      &lt;span style="color:blue;"&gt;Return&lt;/span&gt; _someProperty&lt;/p&gt; &lt;p style="margin: 0px;margin-left:10px;"&gt;               &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Get&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;margin-left:10px;"&gt;               &lt;span style="color:blue;"&gt;Set&lt;/span&gt;(&lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; value &lt;span style="color:blue;"&gt;As&lt;/span&gt; SomeClass)&lt;/p&gt; &lt;p style="margin: 0px;margin-left:20px;"&gt;      _someProperty = value&lt;/p&gt; &lt;p style="margin: 0px;margin-left:10px;"&gt;    &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Set&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Property&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Protected&lt;/span&gt; &lt;span style="color:blue;"&gt;Overridable&lt;/span&gt; &lt;span style="color:blue;"&gt;Function&lt;/span&gt; CalculateValue() &lt;span style="color:blue;"&gt;As&lt;/span&gt; SomeClass&lt;/p&gt; &lt;p style="margin: 0px;margin-left:10px;"&gt;               &lt;span style="color:blue;"&gt;Dim&lt;/span&gt; result &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;New&lt;/span&gt; SomeClass&lt;/p&gt; &lt;p style="margin: 0px;margin-left:10px;"&gt;               &lt;span style="color:green;"&gt;'   Set some properties&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;margin-left:10px;"&gt;               &lt;span style="color:blue;"&gt;Return&lt;/span&gt; result&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Function&lt;/span&gt;&lt;/p&gt; &lt;/div&gt;&lt;br /&gt;A similar pattern can be applied to value objects. The trick is to make the associated private variable nullable:&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1251\uc1 \deff0{\fonttbl{\f0\fnil\fcharset204\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red0\green128\blue0;}??\fs20         \cf3 Private\cf0  _someProperty \cf3 As\cf0  Nullable(\cf3 Of\cf0  \cf3 Boolean\cf0 )\par ??        \cf3 Public\cf0  \cf3 Overridable\cf0  \cf3 Property\cf0  SomeProperty() \cf3 As\cf0  \cf3 Boolean\par ??\cf0             \cf3 Get\par ??\cf0                 \cf3 If\cf0  \cf3 Not\cf0  _someProperty.HasValue \cf3 Then\cf0  _someProperty = CalculateValue()\par ??                \cf3 Return\cf0  _someProperty\par ??            \cf3 End\cf0  \cf3 Get\par ??\cf0             \cf3 Set\cf0 (\cf3 ByVal\cf0  value \cf3 As\cf0  \cf3 Boolean\cf0 )\par ??                _someProperty = value\par ??            \cf3 End\cf0  \cf3 Set\par ??\cf0         \cf3 End\cf0  \cf3 Property\par ??\par ??\cf0         \cf3 Protected\cf0  \cf3 Overridable\cf0  \cf3 Function\cf0  CalculateValue() \cf3 As\cf0  \cf3 Boolean\par ??\cf0             \cf4 'Do stuff\par ??\cf0         \cf3 End\cf0  \cf3 Function\par ??} --&gt; &lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Private&lt;/span&gt; _someProperty &lt;span style="color:blue;"&gt;As&lt;/span&gt; Nullable(&lt;span style="color:blue;"&gt;Of&lt;/span&gt; &lt;span style="color:blue;"&gt;Boolean&lt;/span&gt;)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Public&lt;/span&gt; &lt;span style="color:blue;"&gt;Overridable&lt;/span&gt; &lt;span style="color:blue;"&gt;Property&lt;/span&gt; SomeProperty() &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;Boolean&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;margin-left:10px;"&gt;               &lt;span style="color:blue;"&gt;Get&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;margin-left:20px;"&gt;                      &lt;span style="color:blue;"&gt;If&lt;/span&gt; &lt;span style="color:blue;"&gt;Not&lt;/span&gt; _someProperty.HasValue &lt;span style="color:blue;"&gt;Then&lt;/span&gt; _someProperty = CalculateValue()&lt;/p&gt; &lt;p style="margin: 0px;margin-left:20px;"&gt;                      &lt;span style="color:blue;"&gt;Return&lt;/span&gt; _someProperty&lt;/p&gt; &lt;p style="margin: 0px;margin-left:10px;"&gt;               &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Get&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;margin-left:10px;"&gt;               &lt;span style="color:blue;"&gt;Set&lt;/span&gt;(&lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; value &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;Boolean&lt;/span&gt;)&lt;/p&gt; &lt;p style="margin: 0px;margin-left:20px;"&gt;      _someProperty = value&lt;/p&gt; &lt;p style="margin: 0px;margin-left:10px;"&gt;               &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Set&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Property&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Protected&lt;/span&gt; &lt;span style="color:blue;"&gt;Overridable&lt;/span&gt; &lt;span style="color:blue;"&gt;Function&lt;/span&gt; CalculateValue() &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;Boolean&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;margin-left:10px;"&gt;            &lt;span style="color:green;"&gt;'Do stuff&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Function&lt;/span&gt;&lt;/p&gt; &lt;/div&gt;&lt;br /&gt;Finally, let's try a similar thing with enumerables. Typically, we expose an enumerable as a readonly property, and fill the values at the initialization stage. Here we do a similar trick, but on a certain condition. We add a boolean property AutoCalculateValues and calculate them only if it is set to true, which is the default behaviour:&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1251\uc1 \deff0{\fonttbl{\f0\fnil\fcharset204\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red0\green128\blue0;}??\fs20         \cf3 Private\cf0  _autoCalculateValues \cf3 As\cf0  \cf3 Boolean\cf0  = \cf3 True\par ??\cf0         \cf3 Public\cf0  \cf3 Property\cf0  AutoCalculateValues() \cf3 As\cf0  \cf3 Boolean\par ??\cf0             \cf3 Get\par ??\cf0                 \cf3 Return\cf0  _autoCalculateValues\par ??            \cf3 End\cf0  \cf3 Get\par ??\cf0             \cf3 Set\cf0 (\cf3 ByVal\cf0  value \cf3 As\cf0  \cf3 Boolean\cf0 )\par ??                _autoCalculateValues = value\par ??            \cf3 End\cf0  \cf3 Set\par ??\cf0         \cf3 End\cf0  \cf3 Property\par ??\par ??\par ??\cf0         \cf3 Private\cf0  _someProperty \cf3 As\cf0  IList(\cf3 Of\cf0  SomeClass)\par ??        \cf3 Public\cf0  \cf3 Overridable\cf0  \cf3 ReadOnly\cf0  \cf3 Property\cf0  SomeProperty() \cf3 As\cf0  IEnumerable(\cf3 Of\cf0  SomeClass)\par ??            \cf3 Get\par ??\cf0                 \cf3 If\cf0  _someProperty \cf3 Is\cf0  \cf3 Nothing\cf0  \cf3 Then\par ??\cf0                     _someProperty = \cf3 New\cf0  List(\cf3 Of\cf0  SomeClass)\par ??                \cf3 End\cf0  \cf3 If\par ??\cf0                 \cf3 Return\cf0  _someProperty\par ??            \cf3 End\cf0  \cf3 Get\par ??\cf0         \cf3 End\cf0  \cf3 Property\par ??\par ??\cf0         \cf3 Protected\cf0  \cf3 Overridable\cf0  \cf3 Sub\cf0  CalculateValues(\cf3 ByVal\cf0  list \cf3 As\cf0  IList(\cf3 Of\cf0  SomeClass))\par ??            list.Add(\cf3 New\cf0  SomeClass)\par ??            \cf4 '...\par ??\cf0         \cf3 End\cf0  \cf3 Sub\par ??} --&gt; &lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Private&lt;/span&gt; _autoCalculateValues &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;Boolean&lt;/span&gt; = &lt;span style="color:blue;"&gt;True&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Public&lt;/span&gt; &lt;span style="color:blue;"&gt;Property&lt;/span&gt; AutoCalculateValues() &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;Boolean&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;margin-left:10px;"&gt;            &lt;span style="color:blue;"&gt;Get&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;margin-left:20px;"&gt;                &lt;span style="color:blue;"&gt;Return&lt;/span&gt; _autoCalculateValues&lt;/p&gt; &lt;p style="margin: 0px;margin-left:10px;"&gt;            &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Get&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;margin-left:10px;"&gt;            &lt;span style="color:blue;"&gt;Set&lt;/span&gt;(&lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; value &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;Boolean&lt;/span&gt;)&lt;/p&gt; &lt;p style="margin: 0px;margin-left:20px;"&gt;                _autoCalculateValues = value&lt;/p&gt; &lt;p style="margin: 0px;margin-left:10px;"&gt;            &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Set&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Property&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Private&lt;/span&gt; _someProperty &lt;span style="color:blue;"&gt;As&lt;/span&gt; IList(&lt;span style="color:blue;"&gt;Of&lt;/span&gt; SomeClass)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Public&lt;/span&gt; &lt;span style="color:blue;"&gt;Overridable&lt;/span&gt; &lt;span style="color:blue;"&gt;ReadOnly&lt;/span&gt; &lt;span style="color:blue;"&gt;Property&lt;/span&gt; SomeProperty() &lt;span style="color:blue;"&gt;As&lt;/span&gt; IEnumerable(&lt;span style="color:blue;"&gt;Of&lt;/span&gt; SomeClass)&lt;/p&gt; &lt;p style="margin: 0px;margin-left:10px;"&gt;            &lt;span style="color:blue;"&gt;Get&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;margin-left:20px;"&gt;                &lt;span style="color:blue;"&gt;If&lt;/span&gt; _someProperty &lt;span style="color:blue;"&gt;Is&lt;/span&gt; &lt;span style="color:blue;"&gt;Nothing&lt;/span&gt; &lt;span style="color:blue;"&gt;Then&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;margin-left:30px;"&gt;                    _someProperty = &lt;span style="color:blue;"&gt;New&lt;/span&gt; List(&lt;span style="color:blue;"&gt;Of&lt;/span&gt; SomeClass)&lt;/p&gt; &lt;p style="margin: 0px;margin-left:20px;"&gt;                &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;If&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;margin-left:20px;"&gt;                &lt;span style="color:blue;"&gt;Return&lt;/span&gt; _someProperty&lt;/p&gt; &lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;margin-left:10px;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Get&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Property&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Protected&lt;/span&gt; &lt;span style="color:blue;"&gt;Overridable&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt; CalculateValues(&lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; list &lt;span style="color:blue;"&gt;As&lt;/span&gt; IList(&lt;span style="color:blue;"&gt;Of&lt;/span&gt; SomeClass))&lt;/p&gt; &lt;p style="margin: 0px;margin-left:10px;"&gt;            list.Add(&lt;span style="color:blue;"&gt;New&lt;/span&gt; SomeClass)&lt;/p&gt; &lt;p style="margin: 0px;margin-left:10px;"&gt;            &lt;span style="color:green;"&gt;'...&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt;&lt;/p&gt; &lt;/div&gt;&lt;br /&gt;This time, the property is not settable, but the idea that it is initialized by default but the initialization can be switched off.&lt;br /&gt;&lt;br /&gt;So, what are the advantages? In terms of testability, we can set the desired values directly, instead of using mocks, which simplifies our life a bit, and our tests become even more clear. But the main point is about reuse. Testability with mocks implies that one can modify the behaviour of our class by inheritance. A user of our framework can create a descendant of our class, overriding the property, and inject it into the workflow, just as we do in our tests. Making the property settable, on the other hand, makes it possible to extend the behaviour by composition: a user can, for example, add another class that sets the property in response to some external conditions. Another, more important, possibility, is to set the property manually. For example, on a Web page, the block elements are usually go under each other, but sometimes you want to position your div manually. You don't override the div class, you just tell it, "don't calculate your position, I'll do it myself". Note that the old inheritance possibility is still there -- you can override the CalculateValue() method if you want.&lt;br /&gt;&lt;br /&gt;So, the system definitely becomes more open. This will definitely make the users of your component happier, but also opens more possibilities for misuse. For example, I could set the value that would put the system into an invalid state. However, the same result can be "achieved" by inheritance, only with more efforts. So, apart from validation, the best solution is writing docs properly. And remember that what seems like misusing to you might be a  perfect way of using for others.&lt;br /&gt;&lt;br /&gt;I'm using these ideas for some time with Inka, and I discovered that my design has improved. Each time I'm tempted to mock a parameterless method, I'm trying to convert it into a property, and then make it settable. I discovered that I have less dependencies and better decoupling, less pulls and more pushes, less methods that cover all possible situations, more small classes specifically designed for each situation.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-7525095485819289089?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/7525095485819289089/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=7525095485819289089' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/7525095485819289089'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/7525095485819289089'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2008/01/readonly-properties-and-testability.html' title='Readonly properties and testability'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-3085860880887548723</id><published>2008-01-12T16:46:00.000+03:00</published><updated>2008-01-12T17:15:58.975+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Adventures in test-driven development'/><category scheme='http://www.blogger.com/atom/ns#' term='Inka'/><title type='text'>Inka Layout, take three</title><content type='html'>The next release if Inka is being delayed, again and again. I decided to rewrite the layout engine. I already wrote about that ( see &lt;a href="http://dotfresh.blogspot.com/2007/09/interaction-vs-stateful-tests-or.html"&gt;here&lt;/a&gt;, for example).&lt;br /&gt;&lt;br /&gt;In short, first I tried Need Driven development: implement it step by step, mocking out the next step before implementing the current. This became a disaster: too much upfront design for me. Without seeing the whole picture, I was never sure that it works, much less that it works the way it should.&lt;br /&gt;&lt;br /&gt;My second attempt was much better. At least it began better. I implemented a quick and dirty solution first, then added a few more integration tests and made my solution a bit more complex, then began to refactor. The refactoring stage took forever though. I still haven't finished it in the last release, so I was too shy to publish the code. With only integration tests in place, I wasn't seeing the correct direction of refactoring, so I was doing it blindly, and it took ages to figure out why this particular test broke when I did this simple refactoring.&lt;br /&gt;&lt;br /&gt;Now it's the third attempt, and I've already abandoned version 3a. But I don't want to talk about it yet, until I see the results. I should say that the trunk version is the same as used in the last release, since I decided to put the new experimental version in a separate branch.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-3085860880887548723?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/3085860880887548723/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=3085860880887548723' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/3085860880887548723'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/3085860880887548723'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2008/01/inka-layout-take-three.html' title='Inka Layout, take three'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-1928245629629564510</id><published>2007-12-12T13:26:00.000+03:00</published><updated>2008-01-18T13:45:58.391+03:00</updated><title type='text'>TDDing a HelloWorld application</title><content type='html'>I'm going to write a very simple WinForms application using TDD, and I'm going to refactor it using TDD as well.&lt;br /&gt;&lt;br /&gt;As I'm just learning good OOP design, I often don't have any idea as to how to refactor my (already working) code, and how to properly implement separation of concerns. I also don't know how much I have to cover with tests: I tried too little and was lost in refactoring, I tried too much and couldn't change my design without breaking a lot of tests, so I didn't know if everything was still working or not. So, I'm going to apply my new idea of Test Driven Refactoring and hope that it would bring me somewhere.&lt;br /&gt;&lt;br /&gt;Here's the story. We have a form with a textbox and a button. I enter "Martin" in the text box, press a button, and a message box saying "Hello Martin" should appear.&lt;br /&gt;&lt;br /&gt;Should I apply MVP or MVC here? Probably, but I won't. Folks say, let the tests drive your design, so I'm letting them. But first, I want to make it work as quickly as I can, so I write a simple test using NUnitForms (see below), and I quickly get the following code:&lt;br /&gt;&lt;br /&gt;&lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;Private&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt; HelloButton_Click(&lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; sender &lt;span style="color:blue;"&gt;As&lt;/span&gt; System.Object, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; e &lt;span style="color:blue;"&gt;As&lt;/span&gt; System.EventArgs) &lt;span style="color:blue;"&gt;Handles&lt;/span&gt;       HelloButton.Click&lt;/p&gt;&lt;p style="margin: 0px;"&gt;    MessageBox.Show(&lt;span style="color: rgb(163, 21, 21);"&gt;"Hello "&lt;/span&gt; &amp;amp; &lt;span style="color:blue;"&gt;Me&lt;/span&gt;.NameTextBox.Text, &lt;span style="color: rgb(163, 21, 21);"&gt;"Hello"&lt;/span&gt;)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;p style="margin: 0px;"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;I quickly see that my form is doing too much. It's been created for the purpose of showing the UI elements and reacting to the user input. However, in this code it decides how to greet the user. It decides how to construct the message, and that the messagebox should be shown.&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;How do I refactor this code? First, let's see the test:&lt;/p&gt;&lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;    &amp;lt;Test()&amp;gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt; PressingTheButtonShowsAMessage()&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Dim&lt;/span&gt; form = CreateForm()&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        form.Show()&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Dim&lt;/span&gt; boxTester &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;New&lt;/span&gt; TextBoxTester(&lt;span style="color: rgb(163, 21, 21);"&gt;"NameTextBox"&lt;/span&gt;, form)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        boxTester.Enter(&lt;span style="color: rgb(163, 21, 21);"&gt;"Martin"&lt;/span&gt;)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Dim&lt;/span&gt; buttonTester &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;New&lt;/span&gt; ButtonTester(&lt;span style="color: rgb(163, 21, 21);"&gt;"HelloButton"&lt;/span&gt;, form)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        ExpectModal(&lt;span style="color: rgb(163, 21, 21);"&gt;"Hello"&lt;/span&gt;, &lt;span style="color:blue;"&gt;AddressOf&lt;/span&gt; HelloHandler)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        buttonTester.Click()&lt;/p&gt;&lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&lt;br /&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;Public&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt; HelloHandler()&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Dim&lt;/span&gt; messageBoxTester = &lt;span style="color:blue;"&gt;New&lt;/span&gt; MessageBoxTester(&lt;span style="color: rgb(163, 21, 21);"&gt;"Hello"&lt;/span&gt;)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        Assert.AreEqual(&lt;span style="color: rgb(163, 21, 21);"&gt;"Hello Martin"&lt;/span&gt;, messageBoxTester.Text, &lt;span style="color: rgb(163, 21, 21);"&gt;"Invalid message text"&lt;/span&gt;)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        messageBoxTester.ClickOk()&lt;/p&gt;&lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;Function&lt;/span&gt; CreateForm() &lt;span style="color:blue;"&gt;As&lt;/span&gt; Windows.Forms.Form&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Return&lt;/span&gt; &lt;span style="color:blue;"&gt;New&lt;/span&gt; TestDrivenRefactoring.Form1&lt;/p&gt;&lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Function&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;  &lt;p style="margin: 0px;"&gt;&lt;br /&gt;&lt;/p&gt;  I see that the test's setup phase is too big. In fact, the whole Test Driven Refactoring (TDR for short) process is built around the idea that too much test setup is a code smell. Specifically, we should refactor so that our unit test's setup takes just as much information as required. For example, in this case, all we need to test the message box is the text of the message. So, we should refactor our code into two components: the first, A, passes some object, X, to the second, B, and the second displays a message box. The information is somehow "packed" into X, and our test should be able to create X directly and pass it to B to test it independently of A.&lt;br /&gt;&lt;br /&gt;What is X? It should be created using a single string, and it should provide the same string to B. It could be just a string, but another TDR principle states that such intermediate objects should be flexible, so it's best to make it a custom object. Why not an interface? Could be as well an interface, but we have a simple data transfer object here, with no behaviour, so a custom class should be fine. Let's call it PersonData, and let's rename B to MessageBoxService.&lt;br /&gt;&lt;br /&gt;Here's our test for the new class:&lt;br /&gt;&lt;br /&gt;&lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;    &amp;lt;Test()&amp;gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt; CallingTheShowMessageMethodShowsAMessage()&lt;/p&gt; &lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset204\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red163\green21\blue21;\red0\green0\blue255;}??\fs20 \tab \tab ExpectModal(\cf3 "Hello"\cf0 , \cf4 AddressOf\cf0  HelloHandler)\par ??\tab \tab \cf4 Dim\cf0  messenger \cf4 As\cf0  \cf4 New\cf0  MessageService\par ??\tab \tab \cf4 Dim\cf0  message \cf4 As\cf0  \cf4 New\cf0  Message \cf4 With\cf0  \{.Text = \cf3 "Hello Martin"\cf0 \}\par ??\tab \tab messenger.ShowMessage(Message)} --&gt; &lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;        ExpectModal(&lt;span style="color: rgb(163, 21, 21);"&gt;"Hello"&lt;/span&gt;, &lt;span style="color:blue;"&gt;AddressOf&lt;/span&gt; HelloHandler)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Dim&lt;/span&gt; messenger &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;New&lt;/span&gt; MessageBoxService&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Dim&lt;/span&gt; message &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;New&lt;/span&gt; Message &lt;span style="color:blue;"&gt;With&lt;/span&gt; {.Text = &lt;span style="color: rgb(163, 21, 21);"&gt;"Hello Martin"&lt;/span&gt;}&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        messenger.ShowMessage(message)&lt;/p&gt; &lt;/div&gt;  &lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;We see that the setup portion contains just enough: the first line is an expectation which is sort of an assert, creating the two objects doesn't count, and the only nontrivial thing is setting the Text property of the Message object. Now we clearly have a messaging component that encapsulates showing a message box and has no other concerns.&lt;br /&gt;&lt;br /&gt;But what about the rest of the application? We can refactor our it straightforwardly:&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1251\uc1 \deff0{\fonttbl{\f0\fnil\fcharset204\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red163\green21\blue21;}??\fs20 \tab \cf3 Private\cf0  \cf3 Sub\cf0  HelloButton_Click(\cf3 ByVal\cf0  sender \cf3 As\cf0  System.Object, \cf3 ByVal\cf0  e \cf3 As\cf0  System.EventArgs) \cf3 Handles\cf0  HelloButton.Click\par ??\tab \tab \cf3 Dim\cf0  messenger \cf3 As\cf0  \cf3 New\cf0  MessageService\par ??\tab \tab \cf3 Dim\cf0  message \cf3 As\cf0  \cf3 New\cf0  Message \cf3 With\cf0  \{.Text = \cf4 "Hello "\cf0  &amp;amp; \cf3 Me\cf0 .NameTextBox.Text\}\par ??\tab \tab messenger.ShowMessage(Message)\par ??\tab \cf3 End\cf0  \cf3 Sub\par ??} --&gt; &lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;Private&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt; HelloButton_Click(&lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; sender &lt;span style="color:blue;"&gt;As&lt;/span&gt; System.Object, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; e &lt;span style="color:blue;"&gt;As&lt;/span&gt; System.EventArgs) &lt;span style="color:blue;"&gt;Handles&lt;/span&gt; HelloButton.Click&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Dim&lt;/span&gt; messenger &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;New&lt;/span&gt; MessageBoxService&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Dim&lt;/span&gt; message &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;New&lt;/span&gt; Message &lt;span style="color:blue;"&gt;With&lt;/span&gt; {.Text = &lt;span style="color: rgb(163, 21, 21);"&gt;"Hello "&lt;/span&gt; &amp;amp; &lt;span style="color:blue;"&gt;Me&lt;/span&gt;.NameTextBox.Text}&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        messenger.ShowMessage(Message)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt; &lt;/div&gt;  Our first, functional test still passes. But now we are unable to test the behaviour independently of the MessageBoxService object. It is more or less fine that we have a hardcoded Message class -- it's just a simple class with no behaviour. But hardcoding the MessageBoxService class is a real problem: at some point we'll want to switch all our message boxes to the new Vista-style dialogs, or provide a custom form, whatever. We'll have to search-replace thru all of our code to change that.&lt;br /&gt;&lt;br /&gt;But at this very moment the problem is that we can't test the remaining piece. So, we have to inject a dependency. Now, we don't want hold a reference to the MessageBoxService inside our form class, since we are not sure we'll need it after the refactoring is finished. So, we use a ServiceLocator pattern.&lt;br /&gt;&lt;br /&gt;First we introduce the IMessageService interface:&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1251\uc1 \deff0{\fonttbl{\f0\fnil\fcharset204\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;}??\fs20 \cf1 Public\cf0  \cf1 Interface\cf0  IMessageService\par ??\tab \cf1 Sub\cf0  ShowMessage(\cf1 ByVal\cf0  message \cf1 As\cf0  Message)\par ??\cf1 End\cf0  \cf1 Interface} --&gt; &lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;Public&lt;/span&gt; &lt;span style="color:blue;"&gt;Interface&lt;/span&gt; IMessageService&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;Sub&lt;/span&gt; ShowMessage(&lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; message &lt;span style="color:blue;"&gt;As&lt;/span&gt; Message)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Interface&lt;/span&gt;&lt;/p&gt; &lt;/div&gt;&lt;br /&gt;Next, we do something that is considered one of the worst practices: we introduce a global variable:&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1251\uc1 \deff0{\fonttbl{\f0\fnil\fcharset204\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;}??\fs20 \cf1 Module\cf0  Globals\par ??\tab \cf1 Public\cf0  Services \cf1 As\cf0  System.ComponentModel.Design.ServiceContainer\par ??\cf1 End\cf0  \cf1 Module} --&gt; &lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;Module&lt;/span&gt; Globals&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;Public&lt;/span&gt; Services &lt;span style="color:blue;"&gt;As&lt;/span&gt; System.ComponentModel.Design.ServiceContainer&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Module&lt;/span&gt;&lt;/p&gt; &lt;/div&gt;&lt;br /&gt;Now we can obtain a reference to our MessageBoxService as simple as&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1251\uc1 \deff0{\fonttbl{\f0\fnil\fcharset204\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;}??\fs20 \tab \tab \cf3 Dim\cf0  messenger = Services.GetService(\cf3 GetType\cf0 (IMessageService))\par ??} --&gt; &lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Dim&lt;/span&gt; messenger = Services.GetService(&lt;span style="color:blue;"&gt;GetType&lt;/span&gt;(IMessageService))&lt;/p&gt; &lt;/div&gt;  But of course we should set it to a concrete service somewhere in the setup code, which has nothing to do with our form:&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1251\uc1 \deff0{\fonttbl{\f0\fnil\fcharset204\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;}??\fs20 \tab \tab Services.AddService(\cf3 GetType\cf0 (IMessageService), \cf3 New\cf0  MessageBoxService)\par ??} --&gt; &lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;        Services.AddService(&lt;span style="color:blue;"&gt;GetType&lt;/span&gt;(IMessageService), &lt;span style="color:blue;"&gt;New&lt;/span&gt; MessageBoxService)&lt;/p&gt; &lt;/div&gt;  Similarly, in our test we set it to a mock service, and expect a call to its ShowMessage method.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-style: italic;"&gt;(to be continued)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-1928245629629564510?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/1928245629629564510/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=1928245629629564510' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/1928245629629564510'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/1928245629629564510'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/12/tdding-helloworld-application.html' title='TDDing a HelloWorld application'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-77422090289323262</id><published>2007-11-13T00:00:00.000+03:00</published><updated>2008-01-18T13:44:04.231+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Amazing stuff'/><title type='text'>MUMPS language sample</title><content type='html'>Just discovered this piece of code:&lt;br /&gt;&lt;pre&gt;QUE(RTN,DESC,START,ASK) ;&lt;br /&gt; ; Queues a job to Taskman with optional user interaction&lt;br /&gt; ; Inputs&lt;br /&gt; ;    RTN : The full routine info to queue&lt;br /&gt; ;   DESC : The Description for the task&lt;br /&gt; ;  START : &lt;opt&gt; The start date/time (in FM format) for this job&lt;br /&gt; ;        :  If null, uses today's date/time&lt;br /&gt; ;    ASK : &lt;opt&gt; Prompt the user to queue the job?&lt;br /&gt; ;        :  ASK = 0 (don't) or 1 (ask) If null, defaults to 1&lt;br /&gt; ; Outputs&lt;br /&gt; ;   0 if not tasked, or the Taskman task # if tasked      &lt;br /&gt; ;&lt;br /&gt; N %,QUE,TIME,I,X,Y,DTOUT,STOP,%DT&lt;br /&gt; N ZTSK,ZTRTN,ZTDESC,ZTIO,ZTDTH&lt;br /&gt; S QUE=0&lt;br /&gt; S RTN=$G(RTN)&lt;br /&gt; S DESC=$G(DESC)&lt;br /&gt; I RTN=""!(DESC="") Q 0&lt;br /&gt; S START=$G(START)&lt;br /&gt; S ASK=$G(ASK)&lt;br /&gt; I ASK="" S ASK=1&lt;br /&gt; I 'ASK S %=1&lt;br /&gt; S STOP=0&lt;br /&gt; I START="" D  ;&lt;br /&gt;&lt;/pre&gt;...&lt;br /&gt;(see &lt;a href="http://www.mcenter.com/users/8224/mumps/que.html"&gt;this link&lt;/a&gt; for the full code)&lt;br /&gt;&lt;br /&gt;I was going to add some sarcastic comments but found myself at loss of words..&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-77422090289323262?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.mcenter.com/users/8224/mumps/que.html' title='MUMPS language sample'/><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/77422090289323262/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=77422090289323262' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/77422090289323262'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/77422090289323262'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/11/mumps-language-sample.html' title='MUMPS language sample'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-4046944089007780908</id><published>2007-11-10T15:33:00.000+03:00</published><updated>2007-11-10T23:53:30.137+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Inka'/><title type='text'>Inka (formerly Freshreports) 0.6.1 is out</title><content type='html'>Well, not many new features in this release. But I decided that adding the Grouping support is worth a separate release. After all, the traditional report engines use this idea of hierarchic data display (as opposed to the master-detail idea). I was surprised myself for how little code I had to add. I guess, my data and structure part is written pretty good (I certainly can't say this about my layout engine).&lt;br /&gt;&lt;br /&gt;The bad news is that you have to group your records yourself. The good news is that with Linq it is trivial (see the example application). After that, you add the outer section (that corresponds to the group header/footer in the traditional scenario), and the inner section to the outer one. The grouped data source should be applied to the outer section, which is of type GroupSection, and the inner section and the elements of the outer section get the correct data sources automatically.&lt;br /&gt;&lt;br /&gt;See the Data.doc and the sample application included in the download.&lt;br /&gt;&lt;br /&gt;I should confess that I didn't try it with a more than 2 level scenario.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-4046944089007780908?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/4046944089007780908/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=4046944089007780908' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/4046944089007780908'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/4046944089007780908'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/11/inka-formerly-freshreports-061-is-out.html' title='Inka (formerly Freshreports) 0.6.1 is out'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-7123756895434970454</id><published>2007-11-10T11:26:00.000+03:00</published><updated>2007-11-10T15:47:21.820+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Adventures in test-driven development'/><title type='text'>Test Driven Refactoring</title><content type='html'>As you probably know, the third part of the TDD development cycle is refactoring. After the Green phase, your code works, but it works for the particular set of values that you used in your tests, and it is ugly. The first step is to remove the hardcoded variables so that your code works in a more general situation. This  is not actually refactoring, since you change the behavior of the system. This is the second part that everybody likes: moving the functionality around, creating lots of small classes (ravioli code), and injecting dependencies wherever you can. Lots of fun.&lt;br /&gt;&lt;br /&gt;The question is, should I write tests for this, or shouldn't I? The tests would mean other 3-step cycles within the first one, other refactoring steps, perhaps becoming a fractal-like structure. What's worse, tests would mean a brittle design that would be hard to change later. No tests would mean problems documenting the class behavior. Recently I chose the latter path, but got lost in the refactoring process, forgetting what I meant in the long run. In addition, being a relative novice and not having a pair (for programming), I'd like to have some guide. The refactoring process remains not very test driven, rather test-constrained, since I don't add any new tests in the process of refactoring. So, refactoring is something driven by my own ideas of a nice design.&lt;br /&gt;&lt;br /&gt;Enter Test Driven Refactoring.&lt;br /&gt;&lt;br /&gt;The initial idea was to remove the duplicated parts of my tests. Here's an example. Suppose your customer wants the following:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;If a user is logged in, she sees the "Edit my profile" and "Logout" buttons.&lt;/span&gt;&lt;br /&gt;Next, we ask what is "logged in", and we come with another requirement:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;If a user is registered, she can log in entering her username and password at the login screen.&lt;/span&gt;&lt;br /&gt;Naturally, we ask what is "registered", and here's another requirement:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;After a user has entered her username and password at the registration screen, she can log in using the same username and password.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Let's write the first user story:&lt;br /&gt;&lt;span style="font-style: italic;"&gt;1. If a user has entered "test" and "password" into the username and password boxes at the registration screen, then the same words at the login screen, she &lt;/span&gt;&lt;span style="font-style: italic;"&gt;sees the "Edit my profile" button.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;2. If a user has entered "test" and "password" into the username and password boxes at the registration screen, then the same words at the login screen, she &lt;/span&gt;&lt;span style="font-style: italic;"&gt;sees the "Logout" button.&lt;/span&gt;&lt;br /&gt;Each test would probably involve a complicated setup just to check a simple boolean value in the end. Later, we'll probably add some other tests involving various pieces of functionality available to the logged in members. On the other hand, there might be other ways to become logged in. For each, we have to write still another two tests verifying that the two buttons are visible, and perhaps other functionality is available.&lt;br /&gt;&lt;br /&gt;We quickly notice that our tests multiply exponentially, much quicker than the features are being added. In addition, we notice that the setup portion of our tests is too big, which is a &lt;a href="http://blog.james-carr.org/?p=44"&gt;well known&lt;/a&gt; code smell. So, how do we deal with it using the Test Driven Refactoring approach?&lt;br /&gt;&lt;br /&gt;Suppose we are past the Green phase, so all the required functionality is there. The Refactoring phase is now divided into three steps. The first is to get rid of the hardcoded constants, "test" and "password". Now we can use any username and password, not just these. The second part is the most interesting one. We notice that &lt;span style="font-style: italic;"&gt;all we need for the buttons to be visible or not is a boolean value&lt;/span&gt;. Now we see what "Excessive setup" means: instead of using a boolean value for the input, we have provided much more information that will be simply thrown away.&lt;br /&gt;&lt;br /&gt;So, we decide that there should be two components A and B, and the A's responsibility is to provide a boolean value of some form to B, whereas the B's responsibility is to show or hide the buttons. The boolean value can take any form: an interface with a single bool property, a variable, whatever. The point is, we can test A and B separately: first we verify that A provides the correct value, and we verify that B uses it correctly.&lt;br /&gt;&lt;br /&gt;Recalling the first user requirement, we notice that the functionality of B (and the corresponding test) bears some resemblance. Could we infer the boolean variable from the very beginning? Probably yes, but there are several disadvantages. First, we wouldn't write the initial test, so we couldn't be sure that A and B are integrated correctly. Second, it would be upfront design, which is a sin. And last, sometimes user requirements are much more vague, and it's hard to map them to classes and structures. Recently I wrote a simple search engine, and one of the requirements was that the content should be indexed for faster searches. This requirement would be hard to implement straightforwardly, and the typical TDD process with some obvious refactoring lead me to a wrong direction. After correctly applying TDR, I came up with an intermediate structure (the one that A passes to B) that was identical to the traditional representation of indexed content in a database.&lt;br /&gt;&lt;br /&gt;After the TDR part, you are free to return to the "chaotic" or "free-flow" refactoring to achieve even better design. But this part should be one without writing new tests.&lt;br /&gt;&lt;br /&gt;Why is it better than the free-flow approach? It turns out that the TDR process gives us a set of components and functionalities that are very well correlated to the client requirements. Thus, there are good chances that the tests won't be broken if you decide to improve your design. These tests are not quite unit tests, since you probably want to split the components into smaller objects. But these tests reflect the client's idea about the functionality, not your idea about the good design.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-7123756895434970454?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/7123756895434970454/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=7123756895434970454' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/7123756895434970454'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/7123756895434970454'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/11/test-driven-refactoring.html' title='Test Driven Refactoring'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-718195520293333111</id><published>2007-11-06T23:29:00.000+03:00</published><updated>2007-11-06T23:33:52.063+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Inka'/><category scheme='http://www.blogger.com/atom/ns#' term='FreshReports'/><title type='text'>FreshReports is now Inka</title><content type='html'>It's not on the site yet, but yes, I decided to change the name to something more OS-ish.&lt;br /&gt;&lt;br /&gt;For a while I thought about something trivially Arabic, like Mustafah. But I wanted something related to printing, so here it is -- &lt;span style="font-weight: bold;"&gt;Ink&lt;/span&gt;a. Sounds romantic, too.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-718195520293333111?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='https://sourceforge.net/projects/freshreports' title='FreshReports is now Inka'/><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/718195520293333111/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=718195520293333111' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/718195520293333111'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/718195520293333111'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/11/freshreports-is-now-inka.html' title='FreshReports is now Inka'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-1980820444754191825</id><published>2007-10-14T14:33:00.000+04:00</published><updated>2007-11-10T22:27:29.542+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Adventures in test-driven development'/><category scheme='http://www.blogger.com/atom/ns#' term='Inka'/><category scheme='http://www.blogger.com/atom/ns#' term='FreshReports'/><title type='text'>FreshReports 0.6 is out</title><content type='html'>PUff, finally I got this paging thing working.. more or less. I have put so much effort into it, I decided to make it a new release.&lt;br /&gt;&lt;br /&gt;In fact, I made paging work from the third attempt. First time I took the path of Need-Driven Development, as I understood it. Namely, instead of writing a functional test, I worked step by step and mocked the stuff I planned to add later. The result was a disaster -- I quickly lost all understanding of what works and what is left to be implemented yet. So, at some point I decided to hit the "delete" button.&lt;br /&gt;&lt;br /&gt;Second time I did it better. I already had a Page class that held all the element positions in a hashtable. I was pretty sure that once an element appears in this class at a correct position, it should be printed correctly. However, I was treating "unbreakable" sections (ones that cannot be split across pages) as single elements (thus having a single entry in this hashtable). Once I had all the possible tests i could think of pass, I was pretty sure that I got it.&lt;br /&gt;&lt;br /&gt;Well, I launched my test application and promptly discovered that everything is printed at wrong positions even if it fits on a single page!&lt;br /&gt;&lt;br /&gt;Had to start again.&lt;br /&gt;&lt;br /&gt;This time I decided to keep that hashtable, but now I keep all the individual elements' positions there, not sections.&lt;br /&gt;&lt;br /&gt;This change broke about half of my tests. I suspected that my tests are a mess, but not that much. Turned out that most of them are not "unit" enough, nor integration. I remember that I should refactor my code, but I'm forgetting about refactoring my tests.&lt;br /&gt;&lt;br /&gt;Anyway, I think I've nailed it this time. The code is &lt;span style="font-style: italic;"&gt;very&lt;/span&gt; ugly at the moment, so I'm not releasing it. I'll be refactoring it as well as add some additional checks about stuff like page margins and such. Probably the next release will see the section margins as well, to get finished with the layout features. But the most important things now are grouping support and aggregates.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-1980820444754191825?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='https://sourceforge.net/projects/freshreports' title='FreshReports 0.6 is out'/><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/1980820444754191825/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=1980820444754191825' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/1980820444754191825'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/1980820444754191825'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/10/freshreports-06-is-out.html' title='FreshReports 0.6 is out'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-5396383617659035560</id><published>2007-10-01T13:00:00.000+04:00</published><updated>2007-10-01T13:02:06.328+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming practices'/><title type='text'>TDDing a new feature into the existing code</title><content type='html'>Suppose you have managed to find out the conditions that lead to a crash. How do you fix it in a TDD fashion? Or, how do you add a new feature to the existing code?&lt;br /&gt;&lt;br /&gt;I usually try to resist using the existing code at first. Instead, I modify my production code so that the new conditions take a new path of execution. For example, I assign a certain ID to some object that is part of my test setup, then in the production code I check for this ID, and if it fits, I take the new path. This way I make sure that all my previous tests go to the old path, and since I don't touch the old path code, they will pass for sure.&lt;br /&gt;&lt;br /&gt;Next, I force the new test pass as usual. I don't even need to check the other tests -- they are not affected.&lt;br /&gt;&lt;br /&gt;Now comes the interesting part. I'm refactoring the new path as usual, watching the new test, but I'm trying it the way it looks "similar" to the old path. I might factor out a new method that looks like the one that's been used by the old path. Sometimes I could even use an old method. If the new test breaks, the old method needs to be modified. Or, I could modify the old method (now I should also watch the old tests). If it's too complicated to incorporate the new behavior, I repeat the same trick: split the path into two, and try to make it one in smaller steps.&lt;br /&gt;&lt;br /&gt;With each small step, the difference between the two paths diminishes, so at the end we have a common path of execution, and we can remove our initial split.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-5396383617659035560?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/5396383617659035560/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=5396383617659035560' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/5396383617659035560'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/5396383617659035560'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/10/tdding-new-feature-into-existing-code.html' title='TDDing a new feature into the existing code'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-3535427512424378360</id><published>2007-09-30T10:30:00.000+04:00</published><updated>2007-09-30T12:35:35.951+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Adventures in test-driven development'/><category scheme='http://www.blogger.com/atom/ns#' term='Ivonna'/><title type='text'>TDDing Web applications: requirments vs implementation details</title><content type='html'>Now that my &lt;a href="http://dotfresh.blogspot.com/2007/08/aspnet-tesability-finally-way-it-should.html"&gt;Asp.Net testing framework&lt;/a&gt; release is getting closer, it's time to think how we could incorporate it into our TDD precess. Specifically, I'm interested in the Red-Green-Refactor pattern.&lt;br /&gt;&lt;br /&gt;Suppose I'm trying to develop a site map with a tree-like structure. How do I test the output? In the world of domain logic, or even WinForms UI, the result is more or less well-defined by user requirements: we have to display a table of search results, for example. There's still "more or less", however: we could use a DataGridView, or a third-party grid, or use the form's OnPaint event and draw the results manually. This is what Presenters are for: the actual output is the implementation details, the Presenter is what we test for the search results. In most cases, binding the data to the UI is so trivial that we don't have to test it.&lt;br /&gt;&lt;br /&gt;With the HTML output, it's different. Retrieving the data is one thing, but my current task is to display it. So, I reformulate my story: my control has to display a hierarchic data "properly". Here "properly" means proper indentation for items that are deeper in the tree. Purely visual concept, absolutely untestable.&lt;br /&gt;&lt;br /&gt;So, I come with several choices. Usually I think of the Asp.Net controls as a high-level structure, and the raw HTML output as the implementation details. So, in other situations, I'd prefer to test the high-level structure. For example, I don't care much if my DataList renders as a table or a set of spans, but I want to make sure that the first Item's DataItem is what I expect it to be. The DataList is a part of a user story, and the HTML output is private implementation details.&lt;br /&gt;&lt;br /&gt;With the Web UI development, it's different. Looks like any decision we make is upfront design. Anyway, there are two choices, basically. I can expect some nested DataLists, or Repeaters, or a TreeView, but now &lt;span style="font-weight: bold;"&gt;this&lt;/span&gt; becomes the implementation. Or I can expect some HTML. And the more I think about it, the more I prefer HTML. Now, HTML remains implementation if you think in visual terms. Should I make a bullet list, a set of DIVs, or a table? After all, even a "b" tag will behave like a list item if you apply an appropriate CSS style. But many tags carry a semantical meaning, and if we look this way, the answer is obvious: since we have a list of items, let it be a list tag!&lt;br /&gt;&lt;br /&gt;There's also a "purist" approach: you define your own tag, TDD your HTML structure, and apply CSS wisely to satisfy your customer. But the point is, you choose the raw output for testing.&lt;br /&gt;&lt;br /&gt;Now that we know what to test, we write a test, and the Red phase is finished. At the Green phase, we just override the Render method and write what we need to make the test pass. At the Refactor phase, we could notice that we use a foreach loop and refactor it into a Repeater, or we could use a server HTML control and build it programmatically, etc. Each way, the refactoring would work only if we haven't hardcoded the entire HTML string into our test. We started with a semantic meaning of the list, let's keep it this way. For example, we can store the output in an XML document, and ignore the node attributes and extra tags like spans and such. Also note that all these server controls appear not as a part of upfront design, but at the refactoring phase, which is what we really want for a TDD process.&lt;br /&gt;&lt;br /&gt;Looking at the whole picture, we discover something we didn't expect: &lt;span style="font-weight: bold;"&gt;our implementation details became a part of a user story, and vise versa&lt;/span&gt;. To tell you the truth, I didn't expect the proven TDD principles working in a new field (who said they should?), but they did!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-3535427512424378360?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/3535427512424378360/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=3535427512424378360' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/3535427512424378360'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/3535427512424378360'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/09/tdding-web-applications-requirments-vs.html' title='TDDing Web applications: requirments vs implementation details'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-3311212948463306815</id><published>2007-09-24T20:29:00.000+04:00</published><updated>2007-09-24T20:46:35.810+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><category scheme='http://www.blogger.com/atom/ns#' term='The Ugly Side'/><title type='text'>Encoding disaster in Asp.Net</title><content type='html'>Yesterday I created a few pages that contain Russian text and uploaded it to &lt;a href="http://gudzonhost.ru/"&gt;my hosting provider&lt;/a&gt; which is located in The States.&lt;br /&gt;&lt;br /&gt;The Russian letters turned into Kryakozyabras (weird text with umlauts). Such things happen when you try to read Russian letters with ASCII encoding (or just cut off the 8th bit).&lt;br /&gt;&lt;br /&gt;Further study revealed the following facts:&lt;br /&gt;The problem is only with the static text; dynamically added text appears fine.&lt;br /&gt;The problem is with User controls and regular pages; master pages work fine.&lt;br /&gt;The problem happens with all foreign hosting servers.&lt;br /&gt;&lt;br /&gt;What's been really weird is:&lt;br /&gt;Viewing the file in a built-in viewer of my ftp client showed that the file is fine.&lt;br /&gt;Response encoding as well as charset was UTF-8.&lt;br /&gt;The hex editor showed me that the umlauts were actually 2-byte, but different from Russian 2-byte letters.&lt;br /&gt;&lt;br /&gt;And the answer is..&lt;br /&gt;.. Visual Studio was saving my files in the default system encoding, that is, Windows-1251. While it was fine for the runtime on my PC, it certainly wasn't for the remote server. So, with all that talking about internationalization, Visual Studio doesn't make its own files encoded properly by default. What's even worse, I couldn't even find a global setting to change that -- I had to resave each file manually.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-3311212948463306815?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/3311212948463306815/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=3311212948463306815' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/3311212948463306815'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/3311212948463306815'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/09/encoding-disaster-in-aspnet.html' title='Encoding disaster in Asp.Net'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-2631715967092504017</id><published>2007-09-22T14:07:00.000+04:00</published><updated>2007-09-22T14:35:30.435+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Amazing stuff'/><title type='text'>Tafiti</title><content type='html'>A few weeks ago I discovered the amazing new search engine by Microsoft. It uses Silverlight of course, and it is sort of beautiful (they improved over their initial design that looked quite childish). The main fun begins when you choose the Tree view. You actually see a tree with search results hanging like fruits. The tree spins slowly, so that you can wait till the link you want moves closer and then pick it. If you are overwhelmed by the quantity of the results, you can move the slider at the bottom, and the less relevant results will disappear.&lt;br /&gt;&lt;br /&gt;Visit http://www.tafiti.com/ and see yourself.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-2631715967092504017?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.tafiti.com/' title='Tafiti'/><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/2631715967092504017/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=2631715967092504017' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/2631715967092504017'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/2631715967092504017'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/09/tafiti.html' title='Tafiti'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-1143324207186047885</id><published>2007-09-20T13:15:00.000+04:00</published><updated>2007-09-20T18:57:41.962+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='The Ugly Side'/><title type='text'>ItemCreated Strikes Back</title><content type='html'>Being an old member of the DragNDrop fan club, I'm happily using things like ObjectDataSource in my Asp.Net pages. So, just yesterday I was fighting with the same problem for the, like, 10th time, so I decided to blog about it and maybe next time I'll be wiser.&lt;br /&gt;&lt;br /&gt;The ObjectDataSource works great after you've tuned it for your needs. It was a long story about how I have married it with Neo (my ORM tool of choice), but now that all the plumbing code is autogenerated, I can create a simple administrative page in several seconds, while still keeping my UI, model, and data access separate. (Yes I know that you can do it even faster with Rails) The problem arises when you try to do some data processing that doesn't fit well into your model, since it is more view-related.&lt;br /&gt;&lt;br /&gt;Let me explain. I'm trying to make a page that would allow to edit the schedule for a fitness club. The page has, naturally, a table: columns are days of the week, rows are hours, each cell has the trainer name and the course title. I've got two ObjectDataSources -- one for the hours and one for the days of the week. And I have a repeater inside a repeater.&lt;br /&gt;&lt;br /&gt;Now, you see that there is no way of doing this via just declarative databinding. Even if there are no records about a particular hour/day combination, there should be a table cell. So, I tried to grab the data using the Repeater's ItemDataBound event. The Item here is of type RepeaterItem, and it has a DataItem property that gives me the day of the week. Next, we have to travel up the control hierarchy and retrieve the parent repeater's item, to get the corresponding Hour object. Now we are ready to retrieve the data for the corresponding cell. Next, we have to manually find the corresponding controls inside the cell and fill the data.&lt;br /&gt;&lt;br /&gt;Doesn't sound like it's the year of 2007, eh? It actually reminds me of funny tricks I used to do with classic ASP.&lt;br /&gt;&lt;br /&gt;The real fun, however, begins when you try to &lt;span style="font-style: italic; color: rgb(102, 102, 102); font-weight: bold;"&gt;update&lt;/span&gt; the values. The truth is, you can't use the ItemDataBound event since it isn't fired again after you clicked the Update button. This makes sense, since the data has been fetched already, so there's no need to fetch it again. The ItemCreated event is fired, however. But the DataItem property is null (as it was the first time before the postback). So, thinking again, you don't have access to your data items at all: they are not persisted, what you have is just property values saved in the ViewState. Thus, no chance to retrieve the data in order to update the correct record with the new values.&lt;br /&gt;&lt;br /&gt;There are several workarounds here: you can refetch the data and keep it in a private variable, you can persist HourID in the ViewState and retrieve it on postback, you can even use hidden fields, but all of these are equally ugly. The point is, the DragNDrop thing just doesn't belong here, let's not force it to work. Back in the Asp.Net 1.1, I'd pick a data source manually and have complete control over it. This is exactly what I'm going to do now.&lt;br /&gt;&lt;br /&gt;So, the (trivial) lesson is: mainstream solutions work only in mainstream situations. If you have a straight table, go the ObjectDataSource way. If the table is complicated and the data doesn't quite fit, go the manual data source way. If the table is weird -- displays running totals every 10th row, for example, it might be even OK to remember the foreach loop with tr's and td's. Let's just hope it won't get too weird.&lt;br /&gt;&lt;br /&gt;Sadly, if I were using &lt;a href="http://dotfresh.blogspot.com/2007/08/aspnet-tesability-finally-way-it-should.html"&gt;TDD for ASP.Net&lt;/a&gt;, I won't get into that trap.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-1143324207186047885?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/1143324207186047885/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=1143324207186047885' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/1143324207186047885'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/1143324207186047885'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/09/itemcreated-strikes-back.html' title='ItemCreated Strikes Back'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-8990681523926267973</id><published>2007-09-15T00:58:00.000+04:00</published><updated>2007-09-15T01:49:31.129+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Adventures in test-driven development'/><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><title type='text'>VB Express Limited</title><content type='html'>As I said in &lt;a href="http://dotfresh.blogspot.com/2007/07/my-first-attempts-at-proper-tdd.html"&gt;one of my previous posts&lt;/a&gt;, I decided to develop &lt;a href="http://dotfresh.blogspot.com/search/label/FreshReports"&gt;FreshReports&lt;/a&gt; using VB Orcas. Funny thing, I don't feel I miss any of Visual Studio's functionality, but I miss the add-ins a lot. I can live without TestDriven.Net, but I've got to use Refactor! a lot (they still don't have native refactoring tools in VB). But another thing I miss sometimes is the "attach to process" button. Together with the missing "Debug test" feature of TestDriven it makes it almost impossible to debug your tests. Almost, because you still can use the self-testing feature of MbUnit.&lt;br /&gt;&lt;br /&gt;Anyway, at some point I discovered that I'm writing too much Console.WriteLine's and still can't get my test pass. Now, I keep saying it on every corner that I hate all limitations, but honestly, sometimes limiting possibilities can do good for dumbheads like me. So, the reason I tried to debug what's been happening in my code was a smell that something's wrong, but if I could debug it, I just wouldn't pay much attention (old habits). The amount of console output was like some annoying noise that finally woke me up.&lt;br /&gt;&lt;br /&gt;I woke up and I told myself, why am I torturing myself? I know a better way of doing this, so let's do it!&lt;br /&gt;&lt;br /&gt;Still, I miss the add-ins..&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-8990681523926267973?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/8990681523926267973/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=8990681523926267973' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/8990681523926267973'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/8990681523926267973'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/09/vb-express-limited.html' title='VB Express Limited'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-991935905975061430</id><published>2007-09-04T18:04:00.000+04:00</published><updated>2007-09-05T21:50:12.254+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><title type='text'>Neo is alive!</title><content type='html'>Finally Neo, my one and only ORM tool I've been using for several years, is resurrected! The project, originally hosted by Codehaus &lt;a href="http://neo.codehaus.org/"&gt;here&lt;/a&gt;, has been abandoned for some time, and even the Generics update by Paul Gielens hasn't made it into the main branch.&lt;br /&gt;&lt;br /&gt;What makes it different from other ORM tools?&lt;br /&gt;&lt;br /&gt;1. Built-in code generation with templated classes.&lt;br /&gt;2. The model classes themselves are not POCOs but contain a lot of DAL functionality (some consider this bad).&lt;br /&gt;3. Possibility to keep all objects in-memory. Very useful for testability.&lt;br /&gt;4. Built-in sql-like query syntax, for both database and in-memory queries.&lt;br /&gt;5. All changes can be saved in one line.&lt;br /&gt;6. Automatic inverse relationships. Spielberg.DirectedMovies.Add(AI) is the same as AI.Director = Spielberg.&lt;br /&gt;7. Child contexts. Say, you have a parent Context that can save data to a database, you can have a child context that can save data to its parent. Very useful in some WinForms scenarios.&lt;br /&gt;8. Probably a lot more.&lt;br /&gt;&lt;br /&gt;Some problems include performance issues and a few bugs. But now that the project is resurrected, we can hope that it becomes even better.&lt;br /&gt;&lt;br /&gt;The project can be found &lt;a href="http://code.google.com/p/neo2/"&gt;here&lt;/a&gt;, but there are no downloadables  yet, just the svn repository link.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-991935905975061430?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://code.google.com/p/neo2/' title='Neo is alive!'/><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/991935905975061430/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=991935905975061430' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/991935905975061430'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/991935905975061430'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/09/neo-is-alive.html' title='Neo is alive!'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-3117577714225832947</id><published>2007-09-01T21:15:00.000+04:00</published><updated>2007-11-10T22:27:29.542+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Adventures in test-driven development'/><category scheme='http://www.blogger.com/atom/ns#' term='Inka'/><category scheme='http://www.blogger.com/atom/ns#' term='FreshReports'/><title type='text'>Interaction vs stateful tests, or Falling for Need-Driven Development</title><content type='html'>A few days ago I started adding paging functionality to FreshReports, and immediately fell into a trap some people call &lt;a href="http://chrissterling.gettingagile.com/2006/09/25/need-driven-design-as-an-integration-strategy/"&gt;Need-Driven Development&lt;/a&gt; (see also &lt;a href="http://www.jmock.org/oopsla2004.pdf"&gt;this paper&lt;/a&gt;). Actually it's not a trap but rather one of thу possible strategies in TDD. However, I felt trapped for some time until just now -- I decided to rewrite my paging functionality using a more stateful approach.&lt;br /&gt;&lt;br /&gt;So, how do you do it with NDD? First, you formulate the story, as always. Mine is, "Suppose we have two sections in our report, then if the second doesn't fit on a page, it goes to the next page". Next, I start to code the Page' s CalculateLayout method, something like this:&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset204\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;}??\fs20 \cf1 For\cf0  \cf1 Each\cf0  section \cf1 In\cf0  sections} --&gt; &lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;For&lt;/span&gt; &lt;span style="color:blue;"&gt;Each&lt;/span&gt; section &lt;span style="color:blue;"&gt;In&lt;/span&gt; sections&lt;/p&gt; &lt;/div&gt;  ...&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset204\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;}??\fs20 \cf1 If\cf0  section.Fits(\cf1 New\cf0  Utils.Rectangle(\cf1 Me\cf0 ._printableArea.Width, \cf1 Me\cf0 ._origin.y + \cf1 Me\cf0 ._printableArea.Height - y), partialFit) \cf1 Then} --&gt; &lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;If&lt;/span&gt; section.Fits() &lt;span style="color:blue;"&gt;Then&lt;/span&gt;&lt;/p&gt; &lt;/div&gt;   &lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset204\fprq1 Consolas;}}{\colortbl;??\red0\green128\blue0;\red255\green255\blue255;}??\fs20 \cf1 ' &lt;summary&gt;} --&gt; &lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color:green;"&gt;'do something about it&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;So, we want to code the CalculateLayout method and not get distracted by the Fits method, which is probably a lot to code, so we just mock it out and get a green on CalculateLayout. Next we switch to the Fits method which probably depends on something else, so we mock this something and proceed with the Fits method until it's perfect.&lt;br /&gt;&lt;br /&gt;This technique seems fine from a traditional development's point of view. In fact, it is more or less design-first approach. But when I tried to move this way, after programming the TDD way for some time, I was feeling very uneasy. In the TDD fashion, I should have made a simple test that covers everything (section setup and printing), and mocked just the call I am sure of (to the actual element printing method) (note that I could have mocked the call to the section's Print method instead and save time on adding elements to the sections, but only if I'm sure that it works fine with paging). With NDD, I had to write tests for several steps, and since I don't see the whole picture from the start, I don't even know how soon I get to the actual printing. With TDD, I would have let my tests do the design for me, and even while writing the first test I would have discovered that I need a separate Pager class. With NDD, I sort of know the design of the current step before I start writing the test, and that's wrong, because, for example, later I discover that my Fits method needs two additional arguments, and changing its signature will break my tests.&lt;br /&gt;&lt;br /&gt;Why have I fallen for it? Partly because I just read an article in which some obviously smart guys told me it's good. Partly because it's tempting. In my case, while writing the first test, I didn't know how to setup this "doesn't fit" idea, so I just mocked it. It was quite easy to write a test, even easier to write the production code, but after that I didn't feel I achieved something, quite the opposite, I felt that I've just made things more complicated. So you see, it's all about feeling good or bad, so it's quite personal.&lt;br /&gt;&lt;br /&gt;So, is it that bad? Of course, not. NDD is great for more structured guys. I was feeling helpless because I didn't have a clear picture of what's happening, but that's just me. I prefer to do something quick in a very chaotic way, and then refactor it to make it more structured. NDD is for those who prefer to move step by step.&lt;br /&gt;&lt;br /&gt;In fact, I'm using NDD when I encounter an external dependency, such as FTP or file system. I resist a temptation to just save a file, instead I code an interface and use it. I still have to remember to implement it later, but at least it's an end point rather than part of a long chain of objects. So, to avoid this temptation, I made a rule for myself: never mock an interface you haven't implemented yet, save for such thin implementations of external dependencies.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-3117577714225832947?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/3117577714225832947/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=3117577714225832947' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/3117577714225832947'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/3117577714225832947'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/09/interaction-vs-stateful-tests-or.html' title='Interaction vs stateful tests, or Falling for Need-Driven Development'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-5947923855871815544</id><published>2007-08-31T11:30:00.000+04:00</published><updated>2007-08-31T12:44:49.361+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='The Ugly Side'/><title type='text'>Out Of Memory.. again!</title><content type='html'>Yesterday I plugged my quick-n-dirty Gallery module into DotNetNuke (I developed the most I could as a separate User control), and Bang! I've got this weird OutOfMemoryException. Now, I'm pretty sure that even the DotNetbeast can't eat all my virtual memory, so it should have been something else. Now the funny part: a quick Googling revealed that some poor user already have had this problem (and solved it by himself). And guess what: it was me! At least nobody else posted a message about it with a full stack trace. But I've got a pretty good reason to think that this particular error is related to me in some esoteric way.&lt;br /&gt;&lt;br /&gt;Maybe it's a sign that I &lt;span style="font-style: italic; color: rgb(51, 51, 51); font-weight: bold;"&gt;forgot&lt;/span&gt; something very important? Or I &lt;span style="font-style: italic; color: rgb(51, 51, 51); font-weight: bold;"&gt;remember&lt;/span&gt; too much?&lt;br /&gt;&lt;br /&gt;Anyway, for those who are interested in solving the problem. I've been using an ObjectDataSource (yes I'm a script kiddie), and it was referring to a class in my DAL project. It worked fine in a standalone project, but when I registered it in DotNetNuke and moved the DAL assembly to the bin, the error occurred. Acually, it has nothing to do with memory. The name of my class was written without the assembly name. Once I added it, everything went OK.&lt;br /&gt;&lt;br /&gt;The stack trace is below. As you can see, there's not a line of my code, so there's no chance I could even debug it. Also, the exception happens at the _GetType method, which is most probably native, so perhaps they just throw an OutOfMemoryException then they don't know what's just happened.&lt;br /&gt;&lt;br /&gt;So, if you get an OutOfMemoryException when doing some reflection, don't get scared, just double check your type names and make sure they are fully qualified.&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.&lt;br /&gt;at System.Reflection.Assembly._GetType(String name, Boolean throwOnError, Boolean ignoreCase)&lt;br /&gt;at System.Reflection.Assembly.GetType(String name, Boolean throwOnError, Boolean ignoreCase)&lt;br /&gt;at System.Web.Compilation.CompilationUtil.GetTypeFromAssemblies(AssemblyCollection assembliesCollection, String typeName, Boolean ignoreCase)&lt;br /&gt;at System.Web.Compilation.BuildManager.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase)&lt;br /&gt;at System.Web.UI.WebControls.ObjectDataSourceView.GetType(String typeName)&lt;br /&gt;at System.Web.UI.WebControls.ObjectDataSourceView.ExecuteSelect(DataSourceSelectArguments arguments)&lt;br /&gt;at System.Web.UI.DataSourceView.Select(DataSourceSelectArguments arguments, DataSourceViewSelectCallback callback)&lt;br /&gt;at System.Web.UI.WebControls.DataBoundControl.PerformSelect()&lt;br /&gt;at System.Web.UI.WebControls.BaseDataBoundControl.DataBind()&lt;br /&gt;at System.Web.UI.WebControls.FormView.DataBind()&lt;br /&gt;at System.Web.UI.WebControls.BaseDataBoundControl.EnsureDataBound()&lt;br /&gt;at System.Web.UI.WebControls.FormView.EnsureDataBound()&lt;br /&gt;at System.Web.UI.WebControls.CompositeDataBoundControl.CreateChildControls()&lt;br /&gt;at System.Web.UI.Control.EnsureChildControls()&lt;br /&gt;at System.Web.UI.Control.PreRenderRecursiveInternal()&lt;br /&gt;at System.Web.UI.Control.PreRenderRecursiveInternal()&lt;br /&gt;at System.Web.UI.Control.PreRenderRecursiveInternal()&lt;br /&gt;at System.Web.UI.Control.PreRenderRecursiveInternal()&lt;br /&gt;at System.Web.UI.Control.PreRenderRecursiveInternal()&lt;br /&gt;at System.Web.UI.Control.PreRenderRecursiveInternal()&lt;br /&gt;at System.Web.UI.Control.PreRenderRecursiveInternal()&lt;br /&gt;at System.Web.UI.Control.PreRenderRecursiveInternal()&lt;br /&gt;at System.Web.UI.Control.PreRenderRecursiveInternal()&lt;br /&gt;at System.Web.UI.Control.PreRenderRecursiveInternal()&lt;br /&gt;at System.Web.UI.Control.PreRenderRecursiveInternal()&lt;br /&gt;at System.Web.UI.Control.PreRenderRecursiveInternal()&lt;br /&gt;at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)&lt;br /&gt;--- End of inner exception stack trace ---&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-5947923855871815544?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/5947923855871815544/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=5947923855871815544' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/5947923855871815544'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/5947923855871815544'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/08/out-of-memory-again.html' title='Out Of Memory.. again!'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-2745026694529590707</id><published>2007-08-30T17:56:00.000+04:00</published><updated>2007-11-10T22:27:29.543+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Inka'/><category scheme='http://www.blogger.com/atom/ns#' term='FreshReports'/><title type='text'>FreshReports: elements and sections</title><content type='html'>In FreshReports, an element is a minimal unit of printed information. Typical elements are text strings and geometry shapes. Elements are organized into sections. A section is a container for elements; each element belongs to one and only one section. A section can provide logical grouping, positioning (for example, a page header section) and, most important, data. A section can have a data source and thus serve as a data provider to its elements.&lt;br /&gt;&lt;br /&gt;Most readers are familiar with traditional reporting components, starting with MS Access reports. Using this analogy, our sections correspond to traditional details and group/report headers/footers. However, in traditional reporting we typically have database rows pulled by some inner join query, so the data is essentially flat. FreshReports, on the other hand, uses object graphs as data, so we can have tree-like structure of sections inside other sections.&lt;br /&gt;&lt;br /&gt;FreshReports have a notion of "design time" or "template" section. This is essentially the section definition. Think of it as object representation of the section definition you see in the designer. At runtime, it generates one or several identical clones, named "runtime sections" (or sometimes "detail sections"), according to its data source. This data source corresponds to a table or query result in the traditional reporting scenario, while the DataItem property corresponds to a database row. Individual elements display properties of the DataItem. Note that an element can display several property values mixed with text (the syntax is very close to that of MS Access).&lt;br /&gt;&lt;br /&gt;Sections can be broken between pages in 3 different ways, according to the KeepTogether property. The first way is no limitation. If some elements don't fit on this page, they go to the next. At this point, it's not very useful: these elements are going to be printed not at the top of the page but at the same shift from the top of the section. But anyway a typical section is a row of elements, so they won't break to the next page. A more useful scenario is when a section contains some elements and another section. But anyway this is going to work properly only when I implement pushing -- this is when some elements "push" others when they grow.&lt;br /&gt;&lt;br /&gt;The second possibility is to keep each runtime section together. And the last is to keep the whole section (all its clones) on one page.&lt;br /&gt;&lt;br /&gt;At some point it's going to turn into a set of customizable rules (for example, you'll be able to keep several sections on one page -- useful for table headers).&lt;br /&gt;&lt;br /&gt;Note that the features described here are scheduled for the 0.5.1 release.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-2745026694529590707?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/2745026694529590707/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=2745026694529590707' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/2745026694529590707'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/2745026694529590707'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/08/freshreports-elements-and-sections.html' title='FreshReports: elements and sections'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-8966999305606460226</id><published>2007-08-27T17:16:00.000+04:00</published><updated>2007-11-10T22:27:29.543+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Inka'/><category scheme='http://www.blogger.com/atom/ns#' term='FreshReports'/><title type='text'>FreshReports 0.5 is out</title><content type='html'>I've just uploaded the binaries (together with a small sample) to SourceForge. This thing can't do much yet, but it's something I'm very proud of. I managed to build it very quickly, and although design is not perfect, it's just because some important features are ahead (most notably, paging support), and the design waits to be driven by them.&lt;br /&gt;&lt;br /&gt;So far, it can print just simple data. Stuff like "[Name]' age is [Age]". Note that this is already ahead of the report engines I've seen: we have two properties in one data element! Note also that I don't use curly brackets. I'm trying to make it as simple as it can be.&lt;br /&gt;&lt;br /&gt;If you need to print the object itself, rather than its property, use an empty property name, like this: "This is []". It actually uses the object's ToString() method.&lt;br /&gt;&lt;br /&gt;The main usage pattern is like this:&lt;br /&gt;1. Create a Report object.&lt;br /&gt;2. Create the layout (in the future releases it will be possible to load it from an XML file).&lt;br /&gt;3. Add a data source (or several).&lt;br /&gt;4. Print().&lt;br /&gt;&lt;br /&gt;Happy printing!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-8966999305606460226?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='https://sourceforge.net/projects/freshreports' title='FreshReports 0.5 is out'/><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/8966999305606460226/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=8966999305606460226' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/8966999305606460226'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/8966999305606460226'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/08/freshreports-05-is-out.html' title='FreshReports 0.5 is out'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-3761793588780768597</id><published>2007-08-25T21:13:00.000+04:00</published><updated>2007-09-30T12:36:18.606+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Adventures in test-driven development'/><category scheme='http://www.blogger.com/atom/ns#' term='Ivonna'/><title type='text'>ASP.Net testability.. finally the way it should be!</title><content type='html'>Now, a year or two ago I decided that all my Web apps should be test-driven too. So, my only option at this point was &lt;a href="http://nunitasp.sourceforge.net/"&gt;NUnitAsp&lt;/a&gt; (which is great). Basically, it initiated a request, parsed the output, and you could test the properties of your controls. It even allowed you to click buttons or links and process the resulting request. Pretty cool.&lt;br /&gt;&lt;br /&gt;There are several problems with this approach. First, these tests are really integration tests. There is no way to mock anything. So, before using any test data, for example, I had to put it into the database. And delete it after each test, making sure it's deleted even if the test fails. Or, when testing the logged in behavior, I had to navigate to the login page, enter the credentials, and click the button. In short, every test setup became huge. Second, The control tree should be traversed manually, meaning that I had to explicitly write things like myLabelTester = New LabelTester("ctl00:Panel1:Label1"). And third, each control type had to have its own tester (which parsed the rendered html), so for a custom control you had to write your own custom tester. Oh, and last time I checked, they had testers for Asp 1.1 version only, and even a DataList tester was missing. You can guess well that after some time I abandoned the idea because writing tests was too painful.&lt;br /&gt;&lt;br /&gt;The next thing was &lt;a href="http://www.codeplex.com/plasma"&gt;Plasma&lt;/a&gt;. It also returns the html from your requests and suggests that you parse it (it even doesn't have all the convenience parsers/testers that NUnitAsp has), but there's a big difference. It runs everything in-process. Meaning that whenever I run my favourite test runner, the objects are already there somewhere. I just need to find them.&lt;br /&gt;&lt;br /&gt;Basically, I don't want to get an html string from my test and just make sure that it contains "Hello world". I'd like to write something like this:&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1251\uc1 \deff0{\fonttbl{\f0\fnil\fcharset204\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red163\green21\blue21;}??\fs20 \tab \tab \cf3 Dim\cf0  page \cf3 As\cf0  Web.UI.Page = ExecuteRequest(\cf4 "~/Default.aspx"\cf0 )\par ??\tab \tab Assert.AreEqual(1, page.Controls.Count)\par ??\tab \tab \cf3 Dim\cf0  label \cf3 As\cf0  Web.UI.WebControls.Label = page.FindControl(\cf4 "Label1"\cf0 )\par ??\tab \tab Assert.AreEqual(\cf4 "Hello world"\cf0 , label.Text)\par ??} --&gt; &lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Dim&lt;/span&gt; page &lt;span style="color:blue;"&gt;As&lt;/span&gt; Web.UI.Page = ExecuteRequest(&lt;span style="color: rgb(163, 21, 21);"&gt;"~/Default.aspx"&lt;/span&gt;)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        Assert.AreEqual(1, page.Controls.Count)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Dim&lt;/span&gt; label &lt;span style="color:blue;"&gt;As&lt;/span&gt; Web.UI.WebControls.Label = page.FindControl(&lt;span style="color: rgb(163, 21, 21);"&gt;"Label1"&lt;/span&gt;)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        Assert.AreEqual(&lt;span style="color: rgb(163, 21, 21);"&gt;"Hello world"&lt;/span&gt;, label.Text)&lt;/p&gt; &lt;/div&gt;  In addition, now I can (theoretically) mock my dependencies. The only problem is that Plasma provides just the WorkerRequest object and the html response body. There's no way I could get to the Page object, not even with some dirty Reflection tricks.&lt;br /&gt;&lt;br /&gt;Fortunately, we also have &lt;a href="http://typemock.com/"&gt;TypeMock&lt;/a&gt;, which can do even dirtier. It can set a mock on a type, so that when an object of that type is instantiated, we can get a reference to it, intercept all method and property calls etc.&lt;br /&gt;&lt;br /&gt;There are just two minor obstacles left. First, the mock should be created in the AppDomain that is created by Plasma, meaning that I can't just create them in my tests -- I should modify the Plasma code (actually, I don't need Plasma -- there are several examples of hosting Asp.Net out there (see the references at the bottom)). Not much of an obstacle -- I'm going to put all the relevant code just before the request is executed. Second, we don't know the actual type of our page, so we can't mock it. The solution is to mock the HTTPContext object and get the page reference from it at the point it is assigned the Handler property:&lt;br /&gt;&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1251\uc1 \deff0{\fonttbl{\f0\fnil\fcharset204\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red43\green145\blue175;\red0\green128\blue0;\red0\green0\blue255;\red163\green21\blue21;}??\fs20             System.Web.UI.\cf3 Page\cf0  page; \cf4 //keep the global page variable\par ??\cf0             \cf5 internal\cf0  \cf5 int\cf0  ProcessRequest(\par ??                            \cf5 string\cf0  requestFilePath,\par ??                            \cf5 string\cf0  requestPathInfo,\par ??                            \cf5 string\cf0  requestQueryString,\par ??                            \cf5 string\cf0  requestMethod,\par ??                            \cf3 List\cf0 &lt;\cf3 KeyValuePair\cf0 &lt;\cf5 string\cf0 , \cf5 string\cf0 &gt;&gt; requestHeaders,\par ??                            \cf5 byte\cf0 [] requestBody,\par ??                            \cf5 out\cf0  \cf3 List\cf0 &lt;\cf3 KeyValuePair\cf0 &lt;\cf5 string\cf0 , \cf5 string\cf0 &gt;&gt; responseHeaders,\par ??                            \cf5 out\cf0  \cf5 byte\cf0 [] responseBody) \{\par ??\par ??                \cf3 WorkerRequest\cf0  wr = \cf5 new\cf0  \cf3 WorkerRequest\cf0 (requestFilePath, requestPathInfo,\par ??                    requestQueryString, requestMethod, requestHeaders, requestBody);\par ??\par ??                \cf4 //begin our code\par ??\cf0                 TypeMock.\cf3 MockManager\cf0 .Init();\par ??                TypeMock.\cf3 Mock\cf0  contextMock = TypeMock.\cf3 MockManager\cf0 .Mock(\cf5 typeof\cf0  (System.Web.\cf3 HttpContext\cf0 ), TypeMock.\cf3 Constructor\cf0 .NotMocked);\par ??                contextMock.MockMethodCalled += \cf5 new\cf0  TypeMock.\cf3 MockMethodCalledEventHandler\cf0 (contextMock_MockMethodCalled);\par ??                contextMock.ExpectUnmockedSet(\cf6 "Handler"\cf0 );\par ??                \cf4 //end our code\par ??\par ??\cf0                 \cf3 HttpRuntime\cf0 .ProcessRequest(wr);\par ??\par ??                \cf5 while\cf0  (!wr.Completed) \{\par ??                    \cf3 Thread\cf0 .Sleep(50);\par ??                \}\par ??\par ??                responseHeaders = wr.ResponseHeaders;\par ??                responseBody = wr.ResponseBody;\par ??                \cf5 return\cf0  wr.ResponseStatus;\par ??            \}\par ??\par ??            \cf5 void\cf0  contextMock_MockMethodCalled(\cf5 object\cf0  sender, TypeMock.\cf3 MockMethodCallEventArgs\cf0  e)\par ??            \{\par ??                \cf3 Console\cf0 .WriteLine(e.CalledMethodName);\par ??                \cf5 if\cf0  (e.CalledMethodName == \cf6 "set_Handler"\cf0 ) page = (System.Web.UI.\cf3 Page\cf0 )e.SentArguments[0];\par ??            \}\par ??} --&gt; &lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;            System.Web.UI.&lt;span style="color: rgb(43, 145, 175);"&gt;Page&lt;/span&gt; page; &lt;span style="color:green;"&gt;//keep the global page variable&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;internal&lt;/span&gt; &lt;span style="color:blue;"&gt;int&lt;/span&gt; ProcessRequest(&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                            &lt;span style="color:blue;"&gt;string&lt;/span&gt; requestFilePath,&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                            &lt;span style="color:blue;"&gt;string&lt;/span&gt; requestPathInfo,&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                            &lt;span style="color:blue;"&gt;string&lt;/span&gt; requestQueryString,&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                            &lt;span style="color:blue;"&gt;string&lt;/span&gt; requestMethod,&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                            &lt;span style="color: rgb(43, 145, 175);"&gt;List&lt;/span&gt;&lt;&lt;span style="color: rgb(43, 145, 175);"&gt;KeyValuePair&lt;/span&gt;&lt;&lt;span style="color:blue;"&gt;string&lt;/span&gt;, &lt;span style="color:blue;"&gt;string&lt;/span&gt;&gt;&gt; requestHeaders,&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                            &lt;span style="color:blue;"&gt;byte&lt;/span&gt;[] requestBody,&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                            &lt;span style="color:blue;"&gt;out&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;List&lt;/span&gt;&lt;&lt;span style="color: rgb(43, 145, 175);"&gt;KeyValuePair&lt;/span&gt;&lt;&lt;span style="color:blue;"&gt;string&lt;/span&gt;, &lt;span style="color:blue;"&gt;string&lt;/span&gt;&gt;&gt; responseHeaders,&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                            &lt;span style="color:blue;"&gt;out&lt;/span&gt; &lt;span style="color:blue;"&gt;byte&lt;/span&gt;[] responseBody) {&lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;                &lt;span style="color: rgb(43, 145, 175);"&gt;WorkerRequest&lt;/span&gt; wr = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color: rgb(43, 145, 175);"&gt;WorkerRequest&lt;/span&gt;(requestFilePath, requestPathInfo,&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                    requestQueryString, requestMethod, requestHeaders, requestBody);&lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;                &lt;span style="color:green;"&gt;//begin our code&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                TypeMock.&lt;span style="color: rgb(43, 145, 175);"&gt;MockManager&lt;/span&gt;.Init();&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                TypeMock.&lt;span style="color: rgb(43, 145, 175);"&gt;Mock&lt;/span&gt; contextMock = TypeMock.&lt;span style="color: rgb(43, 145, 175);"&gt;MockManager&lt;/span&gt;.Mock(&lt;span style="color:blue;"&gt;typeof&lt;/span&gt; (System.Web.&lt;span style="color: rgb(43, 145, 175);"&gt;HttpContext&lt;/span&gt;), TypeMock.&lt;span style="color: rgb(43, 145, 175);"&gt;Constructor&lt;/span&gt;.NotMocked);&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                contextMock.MockMethodCalled += &lt;span style="color:blue;"&gt;new&lt;/span&gt; TypeMock.&lt;span style="color: rgb(43, 145, 175);"&gt;MockMethodCalledEventHandler&lt;/span&gt;(contextMock_MockMethodCalled);&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                contextMock.ExpectUnmockedSet(&lt;span style="color: rgb(163, 21, 21);"&gt;"Handler"&lt;/span&gt;);&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                &lt;span style="color:green;"&gt;//end our code&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;                &lt;span style="color: rgb(43, 145, 175);"&gt;HttpRuntime&lt;/span&gt;.ProcessRequest(wr);&lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;                &lt;span style="color:blue;"&gt;while&lt;/span&gt; (!wr.Completed) {&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                    &lt;span style="color: rgb(43, 145, 175);"&gt;Thread&lt;/span&gt;.Sleep(50);&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                }&lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;                responseHeaders = wr.ResponseHeaders;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                responseBody = wr.ResponseBody;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                &lt;span style="color:blue;"&gt;return&lt;/span&gt; wr.ResponseStatus;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;            }&lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;void&lt;/span&gt; contextMock_MockMethodCalled(&lt;span style="color:blue;"&gt;object&lt;/span&gt; sender, TypeMock.&lt;span style="color: rgb(43, 145, 175);"&gt;MockMethodCallEventArgs&lt;/span&gt; e)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;            {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;                &lt;span style="color:blue;"&gt;if&lt;/span&gt; (e.CalledMethodName == &lt;span style="color: rgb(163, 21, 21);"&gt;"set_Handler"&lt;/span&gt;) page = (System.Web.UI.&lt;span style="color: rgb(43, 145, 175);"&gt;Page&lt;/span&gt;)e.SentArguments[0];&lt;/p&gt; &lt;p style="margin: 0px;"&gt;            }&lt;/p&gt; &lt;/div&gt;&lt;br /&gt;&lt;br /&gt;While this is still far from something I could really use in my tests, the main point is already here. By the time we get to the end of the ProcessRequest method, we have a page variable that is really our page, so we can test all its controls, not just the html output.&lt;br /&gt;&lt;br /&gt;I think it's worth of a really powerful framework, with Enterprise (I like the word!) features like IHTTPModule testing, built-in authentication and config mocking etc.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-3761793588780768597?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/3761793588780768597/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=3761793588780768597' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/3761793588780768597'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/3761793588780768597'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/08/aspnet-tesability-finally-way-it-should.html' title='ASP.Net testability.. finally the way it should be!'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-6326981192046836005</id><published>2007-08-24T13:24:00.000+04:00</published><updated>2007-08-24T13:41:56.509+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='The Ugly Side'/><title type='text'>Another sad DotNetNuke story</title><content type='html'>After spending a couple of days fighting with the Gallery module's weird errors, I finally decided to write my own module.&lt;br /&gt;&lt;br /&gt;And not just that, I finally decided to write my own portal (some day).&lt;br /&gt;&lt;br /&gt;Enough is enough. DotNetNuke is great for people who just want to create a portal site. But for developers.. Back then (2 years ago) I thought that software development is painful by nature. So I wasn't surprised when I spent hours trying to figure out that the NullReference exception in my logs is actually a HTTPParse exception. But now I know things can be better. I just put up a &lt;a href="http://heraldofeurope.co.uk"&gt;site&lt;/a&gt; in less than 10 hours that a year ago took about a month for me to create, and after that we spent several months with the designer trying to figure out the layout and trying to apply the correct css classes to the maze of control hierarchies.&lt;br /&gt;&lt;br /&gt;So, breaking with DotNetNuke is like breaking with the old hated wife: it's much simpler to leave it as it is, but once you do it, you're breathing fresh air again. I experienced it today (a little) when I started my own module (abandoning the stock Gallery), so I know for sure.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-6326981192046836005?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/6326981192046836005/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=6326981192046836005' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/6326981192046836005'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/6326981192046836005'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/08/another-sad-dotnetnuke-story.html' title='Another sad DotNetNuke story'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-7299366449170364855</id><published>2007-08-17T20:25:00.000+04:00</published><updated>2007-08-17T20:26:00.346+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Amazing stuff'/><title type='text'>Cory Foy: Too many dialog / option levels?</title><content type='html'>&lt;a href="http://www.cornetdesign.com/2007/05/too-many-dialog-option-levels.html#comments"&gt;Cory Foy: Too many dialog / option levels?&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-7299366449170364855?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.cornetdesign.com/2007/05/too-many-dialog-option-levels.html#comments' title='Cory Foy: Too many dialog / option levels?'/><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/7299366449170364855/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=7299366449170364855' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/7299366449170364855'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/7299366449170364855'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/08/cory-foy-too-many-dialog-option-levels.html' title='Cory Foy: Too many dialog / option levels?'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-6838849706911634940</id><published>2007-08-17T15:43:00.000+04:00</published><updated>2007-08-17T18:37:28.373+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Tools'/><title type='text'>What's lost, what's gained</title><content type='html'>I didn't download the full version of VS Orcas since 1) heard that installation is quit painful 2) didn't want to make my system unstable and perhaps 3) didn't need all these super-features and wanted to save my RAM from unwanted guests. For now, I'm coding the new version of FreshReports with the new VB Express.&lt;br /&gt;&lt;br /&gt;So far, what I really really miss is the Add-Ons. Namely, the ability to run my tests inside the Visual Studio (TestDriven.Net) and the refactoring support by DevExpress. Also, I still haven't used Ankh (a svn itegration addin) and now I'd try it, but I can't.&lt;br /&gt;&lt;br /&gt;What is really nice is the Intellisense. I don't see anything else I could use. But then, I didn't try a WPF app yet.&lt;br /&gt;&lt;br /&gt;I switched from &lt;a href="http://www.adapdev.com/zanebug/index.aspx"&gt;Adaptev's Zanebug&lt;/a&gt; to &lt;a href="http://docs.mbunit.com/"&gt;MbUnit&lt;/a&gt; as my testing environment. What I miss is the GUI that allowed to run only a subset of tests (which might be bad), and to automatically run when the assembly is recompiled. What I gained, supposedly, is a very rich test options (however, haven't tried these yet).&lt;br /&gt;&lt;br /&gt;(The MbUnit GUI crashed today without any meaningful message after I applied some cool refactoring to my code. Turned out to be stack overflow. I still have to find a framework that survives this thing.)&lt;br /&gt;&lt;br /&gt;I switched (for a while) from TypeMock to Rhino Mocks for my mock framework. What I gained is deeper understanding of my design -- how it should be. In addition, I like the method chaining feature (DSL), and of course the explicit method calls instead of strings when I write the expectations. Sort of, instead of writing ExpectCall(myObject, "DoStuff") I just write myObject.DoStuff in the record stage (I should say that TypeMock also can do that -- but in the paid version). Also, the explicit record/playback syntax is cool (however, I'd rename it to something like expect/verify).&lt;br /&gt;&lt;br /&gt;What really disappointed me (twice today) is the failure messages. In TDD, I'm expected to understand immediately what's wrong with my code. Here I couldn't see why my argument expectations fail (had to use the undocumented logging feature), and the worse case, an exception thrown in the middle of the test didn't show up as the source of the failure (instead, it told me that my expectations weren't fulfilled).&lt;br /&gt;&lt;br /&gt;So, you can see that my (desktop) life is full of changes -- which is always goood!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-6838849706911634940?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/6838849706911634940/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=6838849706911634940' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/6838849706911634940'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/6838849706911634940'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/08/whats-lost-whats-gained.html' title='What&apos;s lost, what&apos;s gained'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-2560817341362346281</id><published>2007-08-15T19:12:00.000+04:00</published><updated>2007-11-10T22:27:29.543+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Adventures in test-driven development'/><category scheme='http://www.blogger.com/atom/ns#' term='Inka'/><category scheme='http://www.blogger.com/atom/ns#' term='FreshReports'/><title type='text'>Adventures in test-driven development Part 4: What's next?</title><content type='html'>I'm not going to write down the whole development story -- it would take months, and I'll never finish the project. So far, we have seen several key principles of test-driven development, as well as some cool design ideas. Let's review them:&lt;br /&gt;&lt;br /&gt;1. Test-first: write a test, watch it fail, write the &lt;span style="font-style: italic;"&gt;simplest&lt;/span&gt; (production) code to make the test pass (you can even hardcore some constants in your code), then refactor in smallest possible steps while keeping the test (and the other tests) pass. This is referred to as Red-Green-Refactor cycle.&lt;br /&gt;2. Test-driven: when your testing is too complex, don't just sigh and accept it. This is a sign that your design can be improved. Let the testing drive your code.&lt;br /&gt;3. YAGNI -- you ain't gonna need it. Instead of implementing a Good Thing just because it is one of the GoF patterns or you've just read it in somebody's blog, whatever makes your tests pass is OK. You see that this method you just wrote is ugly, but wait until the next test &lt;span style="font-style: italic;"&gt;drives&lt;/span&gt; you in the right direction for refactoring. There's another similar principle, KISS (Keep It Simple, Stupid).&lt;br /&gt;4. Separation of Concerns (SoC) principle -- each object has to have a distinct responsibility. Keep in mind, though, that this is just a clue: whenever you have problems with testability and you don't know what to do, try this or some other design idea (see Dependency Injection below) and see if it simplifies things. The general idea is that you don't apply these patterns or principles blindly, but let your tests decide what to apply.&lt;br /&gt;5. Dependency Injection. We have seen it when we were getting rid of the Graphics dependency. The main idea is that it is very hard to test your class when there's an external dependency involved, such as an SMTP server, local file system, or some unmanaged stuff. So, don't hardcore it into your component, have it "injected" somehow in your production code, and mock it in your test code to make sure that your code interacts correctly with it. Again, the "weakness" of our mock framework dictated this. But this is not just designing for testability -- turns out that it opens a possibility for other reporting options -- exporting to HTML, Word, or maybe projecting onto a Star Wars style transparent screen.&lt;br /&gt;&lt;br /&gt;This is no accident that Rhino Mocks forced us for a better design. While TypeMock does its job by applying some sort of black magic, Rhino plays by the .Net rules: overrides virtual methods, extends classes, implements interfaces -- does what you or users of your component would do to extend it.&lt;br /&gt;&lt;br /&gt;So, while I'm not going to publish all the details, I'm going to share all my big moves and discoveries, especially TDD-related. The latest source of FreshReports can be found in the SVN repository at SourceForge at https://freshreports.svn.sourceforge.net/svnroot/freshreports/trunk.&lt;br /&gt;&lt;br /&gt;Further reading:&lt;br /&gt;&lt;a href="http://codebetter.com/blogs/jeremy.miller/archive/2005/07/21/129659.aspx"&gt;TDD Design Starter Kit&lt;/a&gt; by Jeremy D. Miller&lt;br /&gt;&lt;a href="http://weblogs.asp.net/rosherove/articles/Design4Tesatbility1.aspx"&gt;Achieving And Recognizing Testable Software Designs&lt;/a&gt; by Roy Osherove&lt;br /&gt;&lt;a href="http://tech.groups.yahoo.com/group/testdrivendevelopment/"&gt;testdrivendevelopment group&lt;/a&gt; on Yahoo&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-2560817341362346281?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/2560817341362346281/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=2560817341362346281' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/2560817341362346281'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/2560817341362346281'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/08/adventures-in-test-driven-development_15.html' title='Adventures in test-driven development Part 4: What&apos;s next?'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-2210796569981239043</id><published>2007-08-10T17:27:00.000+04:00</published><updated>2007-11-10T22:27:29.544+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Adventures in test-driven development'/><category scheme='http://www.blogger.com/atom/ns#' term='Inka'/><category scheme='http://www.blogger.com/atom/ns#' term='FreshReports'/><title type='text'>Adventures in test-driven development Part 3: Getting Rid Of the Ugly Stuff</title><content type='html'>As promised, today we are going to get rid of the Graphics dependency. We are also introducing &lt;a href="http://www.ayende.com/projects/rhino-mocks.aspx"&gt;Rhino Mocks &lt;/a&gt;into our project. We are going to see how the limitations of this framework are going to make our design better. It might sound as something strange at first, but we'll see how it works. Fortunately, we have written our first test using the all-mighty TypeMock, so we can be sure that nothing breaks.&lt;br /&gt;&lt;br /&gt;In order to test our behavior and not print something in the process, we need to &lt;a href="http://en.wikipedia.org/wiki/Mock_object"&gt;mock&lt;/a&gt; the Graphics object. However, it is impossible with Rhino, since the class is sealed, or NotInheritable. So, somehow we should eliminate this hardcoded dependency from our class.&lt;br /&gt;&lt;br /&gt;Why is this good, apart from testability? First, the Graphics class is a heavy &lt;span style="font-style: italic;"&gt;dependency&lt;/span&gt;. The sole fact that it is IDisposable tells us that it depends on some unmanaged resources. In addition, it brings a dependency on Win32, which is bad, since we want to develop a universal component. Sure if we want to use our component on Mono or whatever CLR implementation exists, we could find a Graphics analog, but there's no guarantee that these implementations, that are not part of the standards, are implemented the same way.&lt;br /&gt;&lt;br /&gt;Also, it carries too much with it that we just don't need. We don't want our main object perform all the low-level work, we want to serve it as a main controller, leaving all individual details to other objects.&lt;br /&gt;&lt;br /&gt;Therefore, we are going to introduce a Canvas class, which is going to serve as our main printing device. Immediately, we have two advantages. First, we can provide multiple inheritors of the Canvas class, so, in theory, we can print to PDF, HTML, Word, anything. Second, we are ruling the interface of our Canvas class. Whenever we look at it, we immediately know its responsibilities within our project. We don't have to adapt to the Graphics interface (this is done in the implementation). Since we don't need mysterious stuff that Graphics has, like GetHdc() or FromHwndInternal(), we don't include it as part of our class, so those who use our component won't be tempted to play with it.&lt;br /&gt;&lt;br /&gt;Enough said, let's code! Before we even start with our second test, we should do a little redesign.We should move in small steps, running our test after each step. This way we immediately know if we make a wrong step.  Remember that RhinoMocks requires that we mock an interface or an inheritable class. The first step is to construct a thin wrapper around the Graphics class, giving out just the methods we need.  Let's call it GraphicsCanvas, and let's put it into WinForms namespace. This is the only namespace that is going to reference the System.Drawing assembly, and eventually we are going to extract it into a separate project. Although it seems like adding complexity, actually it makes our design cleaner, since the project itself becomes clean of "the earthly stuff" in some way. For the same reason, I'm going to introduce my analog of the System.Drawing.Point structure.&lt;br /&gt;&lt;br /&gt;The first step is, unfortunately, relatively big. We have to write some basic stuff into our new class so that we have something to test. Let's have it:&lt;br /&gt;&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset204\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red163\green21\blue21;}??\fs20 \cf1 Namespace\cf0  WinForms\par ??    \cf1 Public\cf0  \cf1 Class\cf0  GraphicsCanvas\par ??        \cf1 Private\cf0  _graphics \cf1 As\cf0  Drawing.Graphics, _marginBounds \cf1 As\cf0  System.Drawing.Rectangle, _pageBounds \cf1 As\cf0  System.Drawing.Rectangle, _pageSettings \cf1 As\cf0  System.Drawing.Printing.PageSettings\par ??\par ??        \cf1 Private\cf0  \cf1 Sub\cf0  \cf1 New\cf0 ()\par ??\par ??        \cf1 End\cf0  \cf1 Sub\par ??\par ??\cf0         \cf1 Public\cf0  \cf1 Sub\cf0  \cf1 New\cf0 (\cf1 ByVal\cf0  graphics \cf1 As\cf0  System.Drawing.Graphics, \cf1 ByVal\cf0  marginBounds \cf1 As\cf0  System.Drawing.Rectangle, \cf1 ByVal\cf0  pageBounds \cf1 As\cf0  System.Drawing.Rectangle, \cf1 ByVal\cf0  pageSettings \cf1 As\cf0  System.Drawing.Printing.PageSettings)\par ??            \cf1 Me\cf0 ._graphics = graphics\par ??            \cf1 Me\cf0 ._marginBounds = marginBounds\par ??            \cf1 Me\cf0 ._pageBounds = pageBounds\par ??            \cf1 Me\cf0 ._pageSettings = pageSettings\par ??        \cf1 End\cf0  \cf1 Sub\par ??\par ??\cf0         \cf1 Sub\cf0  DrawString(\cf1 ByVal\cf0  text \cf1 As\cf0  \cf1 String\cf0 , \cf1 ByVal\cf0  position \cf1 As\cf0  Printing.Point)\par ??            \cf1 Me\cf0 ._graphics.DrawString(text, \cf1 New\cf0  Drawing.Font(\cf4 "Verdana"\cf0 , 8.0, Drawing.FontStyle.Regular), Drawing.Brushes.Black, 0, 0)\par ??        \cf1 End\cf0  \cf1 Sub\par ??\par ??\cf0     \cf1 End\cf0  \cf1 Class\par ??End\cf0  \cf1 Namespace} --&gt; &lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;&lt;/span&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;Namespace&lt;/span&gt; WinForms&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;Public&lt;/span&gt; &lt;span style="color:blue;"&gt;Class&lt;/span&gt; GraphicsCanvas&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Private&lt;/span&gt; _graphics &lt;span style="color:blue;"&gt;As&lt;/span&gt; Drawing.Graphics&lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Private&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt; &lt;span style="color:blue;"&gt;New&lt;/span&gt;()&lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Public&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt; &lt;span style="color:blue;"&gt;New&lt;/span&gt;(&lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; graphics &lt;span style="color:blue;"&gt;As&lt;/span&gt; System.Drawing.Graphics)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;Me&lt;/span&gt;._graphics = graphics&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Sub&lt;/span&gt; DrawString(&lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; text &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;String&lt;/span&gt;, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; position &lt;span style="color:blue;"&gt;As&lt;/span&gt; Printing.Point)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;Me&lt;/span&gt;._graphics.DrawString(text, &lt;span style="color:blue;"&gt;New&lt;/span&gt; Drawing.Font(&lt;span style="color: rgb(163, 21, 21);"&gt;"Verdana"&lt;/span&gt;, 8.0, Drawing.FontStyle.Regular), Drawing.Brushes.Black, 0, 0)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Class&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Namespace&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;&lt;/span&gt;&lt;/p&gt; &lt;/div&gt;&lt;br /&gt;What do we have here? First, we hold a private variable for our Graphics object. Next, we have a private parameterless constructor, which makes it impossible to construct our class without parameters. Indeed, it cannot exist without the Graphics object. Next, we have a public constructor. I should say here that while the class itself and the constructor can reference the Graphics class, all other public methods shouldn't, since we are going to convert them into an interface later. So, the last is our first printing method. The least we should provide for printing is the text and its location. In fact, it's about 90% of our needs, or close to that.&lt;br /&gt;&lt;br /&gt;Now, let's figure out our testing strategy. The way Rhino Mocks, as well as most other mock frameworks, work is quite different from TypeMock. TypeMock places a sort of hook on a class before the concrete object is created, so that when it is created, some method calls can be intercepted. So, it's fine that the object itself is created somewhere in our code. Just like the Graphics object, which is created somewhere deep in the framework. On the other hand, a Rhino Mocks mock should be created explicitly in the test. That forces us to redesign our code, so that we could somehow feed the mock object into our production code. This is done via constructor arguments, property setters, or method parameters. This procedure is generally called "dependency injection".&lt;br /&gt;&lt;br /&gt;In our case, each page corresponds to a separate Graphics object, so it makes sense that we provide a separate GraphicsCanvas object for each page. So, the first refactoring is to extract the call to DrawString() to a separate method:&lt;br /&gt;&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset204\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red163\green21\blue21;}??\fs20     \cf3 Protected\cf0  \cf3 Overrides\cf0  \cf3 Sub\cf0  OnPrintPage(\cf3 ByVal\cf0  e \cf3 As\cf0  System.Drawing.Printing.PrintPageEventArgs)\par ??        \cf3 Me\cf0 .PrintCurrentPage(e.Graphics, e.MarginBounds, e.PageBounds, e.PageSettings)\par ??    \cf3 End\cf0  \cf3 Sub\par ??\par ??\cf0     \cf3 Sub\cf0  PrintCurrentPage(\cf3 ByVal\cf0  graphics \cf3 As\cf0  System.Drawing.Graphics, \cf3 ByVal\cf0  marginBounds \cf3 As\cf0  System.Drawing.Rectangle, \cf3 ByVal\cf0  pageBounds \cf3 As\cf0  System.Drawing.Rectangle, \cf3 ByVal\cf0  pageSettings \cf3 As\cf0  System.Drawing.Printing.PageSettings)\par ??        \cf3 For\cf0  \cf3 Each\cf0  section \cf3 In\cf0  \cf3 Me\cf0 .Sections.Values\par ??            \cf3 For\cf0  \cf3 Each\cf0  element \cf3 In\cf0  section.Elements.Values\par ??                graphics.DrawString(\cf3 CType\cf0 (element, Elements.LabelElement).Text, \cf3 New\cf0  Drawing.Font(\cf4 "Verdana"\cf0 , 8.0, Drawing.FontStyle.Regular), Drawing.Brushes.Black, 0, 0)\par ??            \cf3 Next\par ??\cf0         \cf3 Next\par ??\cf0     \cf3 End\cf0  \cf3 Sub} --&gt; &lt;div face="Consolas" size="10pt" color="black" style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"&gt; &lt;p style="margin: 0px;"&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;Protected&lt;/span&gt; &lt;span style="color:blue;"&gt;Overrides&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt; OnPrintPage(&lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; e &lt;span style="color:blue;"&gt;As&lt;/span&gt; System.Drawing.Printing.PrintPageEventArgs)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Me&lt;/span&gt;.PrintCurrentPage(e.Graphics)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;Sub&lt;/span&gt; PrintCurrentPage(&lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; graphics &lt;span style="color:blue;"&gt;As&lt;/span&gt; System.Drawing.Graphics)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;For&lt;/span&gt; &lt;span style="color:blue;"&gt;Each&lt;/span&gt; section &lt;span style="color:blue;"&gt;In&lt;/span&gt; &lt;span style="color:blue;"&gt;Me&lt;/span&gt;.Sections.Values&lt;/p&gt; &lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;For&lt;/span&gt; &lt;span style="color:blue;"&gt;Each&lt;/span&gt; element &lt;span style="color:blue;"&gt;In&lt;/span&gt; section.Elements.Values&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                graphics.DrawString(&lt;span style="color:blue;"&gt;CType&lt;/span&gt;(element, Elements.LabelElement).Text, &lt;span style="color:blue;"&gt;New&lt;/span&gt; Drawing.Font(&lt;span style="color: rgb(163, 21, 21);"&gt;"Verdana"&lt;/span&gt;, 8.0, Drawing.FontStyle.Regular), Drawing.Brushes.Black, 0, 0)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;Next&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Next&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;&lt;/span&gt;&lt;/p&gt; &lt;/div&gt;  (Remember to run our first test each time we do some refactoring)&lt;br /&gt;&lt;br /&gt;In our second test, we are not going to call the Report.Print() method, since there's no way to inject the Canvas dependency. Instead, we'll call the PrintCurrentPage, but only after we figure out how to call it. So, this method should take our wrapper as an argument. The next version looks like this:&lt;br /&gt;&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset204\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;}??\fs20     \cf3 Protected\cf0  \cf3 Overrides\cf0  \cf3 Sub\cf0  OnPrintPage(\cf3 ByVal\cf0  e \cf3 As\cf0  System.Drawing.Printing.PrintPageEventArgs)\par ??        \cf3 Dim\cf0  canvas = \cf3 New\cf0  WinForms.GraphicsCanvas(e.Graphics)\par ??        \cf3 Me\cf0 .PrintCurrentPage(canvas)\par ??    \cf3 End\cf0  \cf3 Sub\par ??\par ??\cf0     \cf3 Sub\cf0  PrintCurrentPage(\cf3 ByVal\cf0  canvas \cf3 As\cf0  WinForms.GraphicsCanvas)\par ??        \cf3 For\cf0  \cf3 Each\cf0  section \cf3 In\cf0  \cf3 Me\cf0 .Sections.Values\par ??            \cf3 For\cf0  \cf3 Each\cf0  element \cf3 In\cf0  section.Elements.Values\par ??                \cf3 Dim\cf0  Text = \cf3 CType\cf0 (element, Elements.LabelElement).Text\par ??                canvas.DrawString(Text, \cf3 New\cf0  Fresh.Printing.Point)\par ??            \cf3 Next\par ??\cf0         \cf3 Next\par ??\cf0     \cf3 End\cf0  \cf3 Sub\par ??} --&gt; &lt;div face="Consolas" size="10pt" color="black" style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"&gt; &lt;p style="margin: 0px;"&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;Protected&lt;/span&gt; &lt;span style="color:blue;"&gt;Overrides&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt; OnPrintPage(&lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; e &lt;span style="color:blue;"&gt;As&lt;/span&gt; System.Drawing.Printing.PrintPageEventArgs)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Dim&lt;/span&gt; canvas = &lt;span style="color:blue;"&gt;New&lt;/span&gt; WinForms.GraphicsCanvas(e.Graphics)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Me&lt;/span&gt;.PrintCurrentPage(canvas)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;Sub&lt;/span&gt; PrintCurrentPage(&lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; canvas &lt;span style="color:blue;"&gt;As&lt;/span&gt; WinForms.GraphicsCanvas)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;For&lt;/span&gt; &lt;span style="color:blue;"&gt;Each&lt;/span&gt; section &lt;span style="color:blue;"&gt;In&lt;/span&gt; &lt;span style="color:blue;"&gt;Me&lt;/span&gt;.Sections.Values&lt;/p&gt; &lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;For&lt;/span&gt; &lt;span style="color:blue;"&gt;Each&lt;/span&gt; element &lt;span style="color:blue;"&gt;In&lt;/span&gt; section.Elements.Values&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                &lt;span style="color:blue;"&gt;Dim&lt;/span&gt; Text = &lt;span style="color:blue;"&gt;CType&lt;/span&gt;(element, Elements.LabelElement).Text&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                canvas.DrawString(Text, &lt;span style="color:blue;"&gt;New&lt;/span&gt; Fresh.Printing.Point)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;Next&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Next&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;&lt;/span&gt;&lt;/p&gt; &lt;/div&gt;  But now that we try to write our test, we have a problem. Since our GraphicsCanvas object can't be created without a Graphics object, so can't the corresponding mock. We imposed this limitation on ourselves when we added a private parameterless constructor to our class. We could remove it now, but it would be a bad idea. Instead, let's get our design driven by this limitation. We'll see that it's for the good.&lt;br /&gt;&lt;br /&gt;What are the requirements for the type of the canvas argument? First, it should allow us to pass our GraphicsCanvas object, so it should be a base class. Second, it should be mockable. In addition, it should provide our base functionality (the DrawString method) without implementing it (so the method should be abstract, or MustOverride). So, it's either an abstract class or an interface. Typically, such things are done with interfaces. Perhaps historically mock frameworks could work with interfaces but not with abstract classes. For me, an interface is some common functionality among unrelated classes (like IDisposable), whereas an abstract class is a conceptual common ground, like Shape for all geometrical shapes.&lt;br /&gt;&lt;br /&gt;So, let's shoot our Canvas class:&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset204\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;}??\fs20 \cf1 Namespace\cf0  Printing\par ??\par ??    \cf1 Public\cf0  \cf1 MustInherit\cf0  \cf1 Class\cf0  Canvas\par ??        \cf1 MustOverride\cf0  \cf1 Sub\cf0  DrawString(\cf1 ByVal\cf0  text \cf1 As\cf0  \cf1 String\cf0 , \cf1 ByVal\cf0  position \cf1 As\cf0  Point)\par ??    \cf1 End\cf0  \cf1 Class\par ??\par ??\cf0     \cf1 Public\cf0  \cf1 Structure\cf0  Point\par ??        \cf1 Public\cf0  x \cf1 As\cf0  \cf1 Integer\par ??\cf0         \cf1 Public\cf0  y \cf1 As\cf0  \cf1 Integer\par ??\cf0     \cf1 End\cf0  \cf1 Structure\par ??End\cf0  \cf1 Namespace} --&gt; &lt;div style="background: white none repeat scroll 0% 50%; font-family: Consolas; font-size: 10pt; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;&lt;/span&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;Namespace&lt;/span&gt; Printing&lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;Public&lt;/span&gt; &lt;span style="color:blue;"&gt;MustInherit&lt;/span&gt; &lt;span style="color:blue;"&gt;Class&lt;/span&gt; Canvas&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;MustOverride&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt; DrawString(&lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; text &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;String&lt;/span&gt;, &lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; position &lt;span style="color:blue;"&gt;As&lt;/span&gt; Point)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Class&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Namespace&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;&lt;/span&gt;&lt;/p&gt; &lt;/div&gt;Next, we just modify or GraphicsCanvas class so that it inherits from Canvas. And let the PrintCurrentPage accept a Canvas object as its argument:&lt;br /&gt;&lt;span style="color:blue;"&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="color:blue;"&gt;Sub&lt;/span&gt; PrintCurrentPage(&lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; canvas &lt;span style="color:blue;"&gt;As&lt;/span&gt; Printing.Canvas)&lt;/blockquote&gt;So, did it make our design better? First, we have greater control over printing. We have extracted our PrintCurrentPage method and now can call it directly. This is a big step towards being independent from the PrintDocument class by the way. Next, we can print to anything we like, provided we can implement a custom Canvas class. Our main Report object has been relieved from the printing burden, and can concentrate on more important tasks (such as handling the report structure and routing commands to other objects). This is called the Separation of Responsibilities (SoC) principle.&lt;br /&gt;&lt;br /&gt;Finally, let's see our test:&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset204\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red163\green21\blue21;\red0\green128\blue0;}??\fs20     &lt;test()&gt; \cf3 Sub\cf0  TestWithRhino()\par ??        \cf3 Dim\cf0  mocks \cf3 As\cf0  \cf3 New\cf0  MockRepository()\par ??        \cf3 Dim\cf0  canvasMock = mocks.CreateMock(\cf3 Of\cf0  Printing.Canvas)()\par ??        \cf3 Dim\cf0  TestReport = \cf3 New\cf0  Report\par ??        \cf3 Dim\cf0  TestSection \cf3 As\cf0  \cf3 New\cf0  Core.Section\par ??        TestReport.Sections.Add(\cf4 ""\cf0 , TestSection)\par ??        \cf3 Dim\cf0  TestElement \cf3 As\cf0  \cf3 New\cf0  Elements.LabelElement\par ??        TestSection.Elements.Add(\cf4 ""\cf0 , TestElement)\par ??        TestElement.Text = \cf4 "test"\par ??\par ??\cf0         \cf3 Using\cf0  mocks.Record\par ??            canvasMock.DrawString(\cf4 ""\cf0 , \cf3 New\cf0  Printing.Point()) \cf5 'we can provide any arguments here\par ??\cf0             LastCall.Constraints(Rhino.Mocks.Constraints.Text.Like(\cf4 "test"\cf0 ), \cf3 New\cf0  Rhino.Mocks.Constraints.Anything)\par ??        \cf3 End\cf0  \cf3 Using\par ??\par ??\cf0         \cf3 Using\cf0  mocks.Playback\par ??            TestReport.PrintCurrentPage(canvasMock)\par ??        \cf3 End\cf0  \cf3 Using\par ??\cf0     \cf3 End\cf0  \cf3 Sub\par ??} --&gt; &lt;div style="background: white none repeat scroll 0% 50%; font-family: Consolas; font-size: 10pt; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"&gt; &lt;p style="margin: 0px;"&gt;&lt;/p&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div style="background: white none repeat scroll 0% 50%; font-family: Consolas; font-size: 10pt; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"&gt;&lt;p style="margin: 0px;"&gt;    &amp;lt;Test()&amp;gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt; TestWithRhino()&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Dim&lt;/span&gt; mocks &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;New&lt;/span&gt; MockRepository()&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Dim&lt;/span&gt; canvasMock = mocks.CreateMock(&lt;span style="color:blue;"&gt;Of&lt;/span&gt; Printing.Canvas)()&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Dim&lt;/span&gt; TestReport = &lt;span style="color:blue;"&gt;New&lt;/span&gt; Report&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Dim&lt;/span&gt; TestSection &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;New&lt;/span&gt; Core.Section&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        TestReport.Sections.Add(&lt;span style="color: rgb(163, 21, 21);"&gt;""&lt;/span&gt;, TestSection)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Dim&lt;/span&gt; TestElement &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;New&lt;/span&gt; Elements.LabelElement&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        TestSection.Elements.Add(&lt;span style="color: rgb(163, 21, 21);"&gt;""&lt;/span&gt;, TestElement)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        TestElement.Text = &lt;span style="color: rgb(163, 21, 21);"&gt;"test"&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Using&lt;/span&gt; mocks.Record&lt;/p&gt; &lt;p style="margin: 0px;"&gt;            canvasMock.DrawString(&lt;span style="color: rgb(163, 21, 21);"&gt;""&lt;/span&gt;, &lt;span style="color:blue;"&gt;New&lt;/span&gt; Printing.Point()) &lt;span style="color:green;"&gt;'we can provide any arguments here&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;            LastCall.Constraints(Rhino.Mocks.Constraints.Text.Like(&lt;span style="color: rgb(163, 21, 21);"&gt;"test"&lt;/span&gt;), &lt;span style="color:blue;"&gt;New&lt;/span&gt; Rhino.Mocks.Constraints.Anything)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Using&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Using&lt;/span&gt; mocks.Playback&lt;/p&gt; &lt;p style="margin: 0px;"&gt;            TestReport.PrintCurrentPage(canvasMock)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Using&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt;&lt;/p&gt; &lt;/div&gt;  &lt;/blockquote&gt;First goes some preparation. Next we have a Using mocks.Record statement -- it's a first part of the Record-Replay pattern, where we first write down what method calls we expect, what arguments should be there, and which results should the methods return. In our case, the first line states that we should call the DrawString method. The arguments are irrelevant here, but without them the code won't be compiled. The second line tells us that the first argument should be equal to our test string, and the second can be anything.&lt;br /&gt;&lt;br /&gt;Last, we have a Playback block where we put our tested method.&lt;br /&gt;&lt;br /&gt;Our test actually verifies that the appropriate call is made to the Canvas object. It doesn't verify that the string is actually printed. This is where Rhino Mocks can't help us. However, we can easily write a separate test (using TypeMock) for it. Since we have two separate objects, we can test them independently. We can do all kinds of tests verifying that DrawString is invoked correctly, and only one test verifying that it actually prints something. When we have other Canvas objects, we'll have to make one test for each object, instead of testing all possible report layouts and data with each canvas. That's what the term &lt;span style="font-style: italic;"&gt;unit testing&lt;/span&gt; is about.&lt;br /&gt;&lt;br /&gt;Another thing that's not tested here is that calling the Print() method actually calls the PrintCurrentPage method. So far, we have our first test to verify it, but this is an indication that this piece has to be refactored as well. I guess I'll be making a separate class ReportPrinter that inherits from PrintDocument and manages the interaction with the actual printing and previewing (it can even be used at design-time in a form), and our Report class will be completely ignorant of these implementation details. However, I'll wait till I implement paging and let my tests drive my design.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-2210796569981239043?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/2210796569981239043/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=2210796569981239043' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/2210796569981239043'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/2210796569981239043'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/08/adventures-in-test-driven-development_10.html' title='Adventures in test-driven development Part 3: Getting Rid Of the Ugly Stuff'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-5386585581441680003</id><published>2007-08-05T22:56:00.000+04:00</published><updated>2007-08-06T21:52:14.218+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Adventures in test-driven development'/><category scheme='http://www.blogger.com/atom/ns#' term='FreshReports'/><title type='text'>Adventures in test-driven development part 2: Getting a Meaningful Result</title><content type='html'>&lt;a href="http://dotfresh.blogspot.com/2007/08/adventures-in-test-driven-development_02.html"&gt;Last time&lt;/a&gt; we forced out component to print a word and satisfy out first test. However, we didn't finish the proper TDD cycle: red-green-refactor. So, how can we refactor our code so that it would become a sample of perfect design?&lt;br /&gt;&lt;br /&gt;I'm tempted to eliminate the ugly Graphics dependency that's making our code hard to test (even with TypeMock). But after reading some posts on Behavior Driven Development, I feel that I should focus on the main part of our component -- the customer who's using it.&lt;br /&gt;&lt;br /&gt;So, I'll start with a user story. Since I'm the author, I'm trying to figure out what would a client want. Something like that:&lt;br /&gt;&lt;br /&gt;1. I want to create simple units (called Elements) that represent a single printed unit, like a string or a line, so that a client could add, remove, and move around these elements at her will.&lt;br /&gt;2. I want to organize these elements into containers (called Sections), so that a client could easily think in terms of data records (corresponding to objects or, God forbid, database rows). So, the sections would allow her to group elements in terms of data (single section corresponding to a single data source object) or presentation (page headers/footers).&lt;br /&gt;3. I want to attach unique IDs to all elements and sections so that the client could easily identify each element, at least within a section.&lt;br /&gt;&lt;br /&gt;There is another problem with my test. I didn't put the text "test" that's being printed. So, the test actually tests that the word "test" is printed &lt;span style="font-style: italic;"&gt;always&lt;/span&gt;. This is clearly not my intent, so I should rewrite it. Remember that it should fail, so just to make sure I change the expected word "test" to "test2".&lt;br /&gt;&lt;br /&gt;I'm going to name my first element class "LabelElement", since its behavior is close to that of a label. I'm going to add a Sections property to my Report class to hold the list of sections. Same with the Elements property for the Section class. Both properties are going to of be respective generic Dictionary types. It seems like I'm making a lot of design decisions even before writing the test, but I need that to make it compile.&lt;br /&gt;&lt;br /&gt;So, my new test code is&lt;br /&gt;&lt;blockquote&gt; &lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset204\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red163\green21\blue21;\red0\green128\blue0;}??\fs20     &lt;test(),&gt; \cf3 Sub\cf0  PrintSimpleText()\par ??\tab \tab \cf3 Dim\cf0  graphicsMock = MockManager.Mock(\cf3 Of\cf0  Drawing.Graphics)(Constructor.Mocked)\par ??        graphicsMock.ExpectCall(\cf4 "DrawString"\cf0 ).Args(\cf4 "test2"\cf0 , Check.IsAny, Check.IsAny, Check.IsAny, Check.IsAny)\par ??        \cf3 Dim\cf0  SystemFontsMock = TypeMock.MockManager.Mock(\cf3 GetType\cf0 (System.Drawing.SystemFonts))\par ??        SystemFontsMock.ExpectGetAlways(\cf4 "DefaultFont"\cf0 , \cf3 New\cf0  System.Drawing.Font(\cf4 "Verdana"\cf0 , 8))\par ??        \cf3 Dim\cf0  TestReport = \cf3 New\cf0  Report\par ??        \cf3 Dim\cf0  TestSection \cf3 As\cf0  \cf3 New\cf0  Core.Section\par ??\tab \tab TestReport.Sections.Add(\cf4 ""\cf0 , TestSection) \cf5 'we'll use the first argument for the ID, let's just have an empty string here for now\par ??\cf0         \cf3 Dim\cf0  TestElement \cf3 As\cf0  \cf3 New\cf0  Elements.LabelElement\par ??        TestSection.Elements.Add(\cf4 ""\cf0 , TestElement)\par ??        TestElement.Text = \cf4 "test2"\par ??\cf0         TestReport.PrintController = \cf3 New\cf0  Drawing.Printing.PreviewPrintController\par ??        TestReport.Print()\par ??\tab \cf3 End\cf0  \cf3 Sub} --&gt; &lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;    &amp;lt;Test(), VerifyMocks()&amp;gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt; PrintSimpleText()&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Dim&lt;/span&gt; graphicsMock = MockManager.Mock(&lt;span style="color:blue;"&gt;Of&lt;/span&gt; Drawing.Graphics)(Constructor.Mocked)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        graphicsMock.ExpectCall(&lt;span style="color: rgb(163, 21, 21);"&gt;"DrawString"&lt;/span&gt;).Args(&lt;span style="color: rgb(163, 21, 21);"&gt;"test2"&lt;/span&gt;, Check.IsAny, Check.IsAny, Check.IsAny, Check.IsAny)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Dim&lt;/span&gt; SystemFontsMock = TypeMock.MockManager.Mock(&lt;span style="color:blue;"&gt;GetType&lt;/span&gt;(System.Drawing.SystemFonts))&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        SystemFontsMock.ExpectGetAlways(&lt;span style="color: rgb(163, 21, 21);"&gt;"DefaultFont"&lt;/span&gt;, &lt;span style="color:blue;"&gt;New&lt;/span&gt; System.Drawing.Font(&lt;span style="color: rgb(163, 21, 21);"&gt;"Verdana"&lt;/span&gt;, 8))&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Dim&lt;/span&gt; TestReport = &lt;span style="color:blue;"&gt;New&lt;/span&gt; Report&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Dim&lt;/span&gt; TestSection &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;New&lt;/span&gt; Core.Section&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        TestReport.Sections.Add(&lt;span style="color: rgb(163, 21, 21);"&gt;""&lt;/span&gt;, TestSection) &lt;span style="color:green;"&gt;'we'll use the first argument for the ID, let's just have an empty string here for now&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Dim&lt;/span&gt; TestElement &lt;span style="color:blue;"&gt;As&lt;/span&gt; &lt;span style="color:blue;"&gt;New&lt;/span&gt; Elements.LabelElement&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        TestSection.Elements.Add(&lt;span style="color: rgb(163, 21, 21);"&gt;""&lt;/span&gt;, TestElement)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        TestElement.Text = &lt;span style="color: rgb(163, 21, 21);"&gt;"test2"&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        TestReport.PrintController = &lt;span style="color:blue;"&gt;New&lt;/span&gt; Drawing.Printing.PreviewPrintController&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        TestReport.Print()&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt;&lt;/p&gt; &lt;/div&gt;  &lt;/blockquote&gt;Of course, my test fails. It prints "test" instead of "test2". So, for the Green phase I just shamelessly change the hardcoded value to "test2". Then  I get to the Refactor stage, and the code becomes something like this:&lt;br /&gt;&lt;blockquote&gt;&lt;/blockquote&gt; &lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof65001\uc1 \deff0{\fonttbl{\f0\fnil\fcharset204\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue0;\red255\green255\blue255;\red0\green0\blue255;\red163\green21\blue21;}??\fs20     \cf3 Protected\cf0  \cf3 Overrides\cf0  \cf3 Sub\cf0  OnPrintPage(\cf3 ByVal\cf0  e \cf3 As\cf0  System.Drawing.Printing.PrintPageEventArgs)\par ??        \cf3 For\cf0  \cf3 Each\cf0  section \cf3 In\cf0  \cf3 Me\cf0 .Sections.Values\par ??            \cf3 For\cf0  \cf3 Each\cf0  element \cf3 In\cf0  section.Elements.Values\par ??                e.Graphics.DrawString(\cf3 CType\cf0 (element, Elements.LabelElement).Text, \cf3 New\cf0  Drawing.Font(\cf4 "Verdana"\cf0 , 8.0, Drawing.FontStyle.Regular), Drawing.Brushes.Black, 0, 0)\par ??            \cf3 Next\par ??\cf0         \cf3 Next\par ??\cf0     \cf3 End\cf0  \cf3 Sub\par ??} --&gt; &lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;&lt;/span&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;Protected&lt;/span&gt; &lt;span style="color:blue;"&gt;Overrides&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt; OnPrintPage(&lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; e &lt;span style="color:blue;"&gt;As&lt;/span&gt; System.Drawing.Printing.PrintPageEventArgs)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;For&lt;/span&gt; &lt;span style="color:blue;"&gt;Each&lt;/span&gt; section &lt;span style="color:blue;"&gt;In&lt;/span&gt; &lt;span style="color:blue;"&gt;Me&lt;/span&gt;.Sections.Values&lt;/p&gt; &lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;For&lt;/span&gt; &lt;span style="color:blue;"&gt;Each&lt;/span&gt; element &lt;span style="color:blue;"&gt;In&lt;/span&gt; section.Elements.Values&lt;/p&gt; &lt;p style="margin: 0px;"&gt;                e.Graphics.DrawString(&lt;span style="color:blue;"&gt;CType&lt;/span&gt;(element, Elements.LabelElement).Text, &lt;span style="color:blue;"&gt;New&lt;/span&gt; Drawing.Font(&lt;span style="color: rgb(163, 21, 21);"&gt;"Verdana"&lt;/span&gt;, 8.0, Drawing.FontStyle.Regular), Drawing.Brushes.Black, 0, 0)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;Next&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Next&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;/div&gt;You can see that we actually achieved more than we intended. We can print several elements now -- all elements that are added to the Report. While we shouldn't add more than one feature at a time usually, this one came almost as a side effect -- I should have printed only the first element of the first section, but it turned out that the code is simpler this way.&lt;br /&gt;&lt;br /&gt;Next time we are going to make a huge refactoring, since it's going to make our test-driven life a lot easier.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-5386585581441680003?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/5386585581441680003/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=5386585581441680003' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/5386585581441680003'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/5386585581441680003'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/08/adventures-in-test-driven-development_05.html' title='Adventures in test-driven development part 2: Getting a Meaningful Result'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-7765677686791924493</id><published>2007-08-05T19:13:00.000+04:00</published><updated>2007-08-05T22:45:19.329+04:00</updated><title type='text'>On Good Frameworks forcing Good Things upon us</title><content type='html'>Every now and then I read people say things like "testability forces me to think about good design", or, "This framework is good/bad because it does/doesn't enforce good design practices". Although I usually try my best to respect other people's views, such things literally drive me mad.&lt;br /&gt;&lt;br /&gt;OK, I admit it's personal. I hate being enforced since my childhood. But I'll try to be objective (as if sentient beings could be objective) and put a couple of reasons behind my emotions.&lt;br /&gt;&lt;br /&gt;The whole forcing thing is about awareness. If you are a kid you shouldn't play with fire. That's an enforcement that can save a life. If you are aware of the situation and the consequences of your actions, you need freedom to act effectively. Perhaps you are too self-confident, perhaps you don't know the consequences although you think you do. But you take your chance and perhaps learn something from your failure.&lt;br /&gt;&lt;br /&gt;My favourite example is about crossing a street. If you are not very confident, you watch the street lights. Green, you go. But it's not the street light that hits you, it's the car. So, a more confident person would watch for a running car (which might hit you even if you cross with a green light). Now, imagine if I'm &lt;span style="font-style: italic;"&gt;forced&lt;/span&gt; to cross the street when the green light is on. When some drunk driver drives right on me, I can't stop even if I see him coming, because, you know, I'm forced to move.&lt;br /&gt;&lt;br /&gt;Same with frameworks. If I'm forced to do a HelloWorld in a "right" way, all with MVP and interfaces and dependency injections, is it a good framework? Do I have to reinvent a MessageBox so that my open source mocking framework is satisfied?&lt;br /&gt;&lt;br /&gt;If there's a good pattern, a framework should encourage, not enforce it. You can make a shortcut of sorts, make it simple. And I'm not saying that the authors of such frameworks deliberately block other ("bad") ways of doing things. But presenting some "enforcement" as a feature is like being proud about something that you can't do (as opposite to "can but don't want to").&lt;br /&gt;&lt;br /&gt;Back to "testability forces me to think about good design" -- do you really have to be &lt;span style="font-style: italic;"&gt;enforced&lt;/span&gt; to think about good design?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-7765677686791924493?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/7765677686791924493/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=7765677686791924493' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/7765677686791924493'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/7765677686791924493'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/08/on-good-frameworks-forcing-good-things.html' title='On Good Frameworks forcing Good Things upon us'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-7200498587843665576</id><published>2007-08-02T16:33:00.000+04:00</published><updated>2007-11-10T22:27:29.544+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Adventures in test-driven development'/><category scheme='http://www.blogger.com/atom/ns#' term='Inka'/><category scheme='http://www.blogger.com/atom/ns#' term='FreshReports'/><title type='text'>Adventures in test-driven development Part 1, first mistake</title><content type='html'>Now that I'm starting to write my first test, I discover that I have already thought well about my future design. I made some key decisions as well. For example, I decided to decouple from the Graphics class. I also decided not to inherit from the PrintDocument class (a direct consequence of my first decision). Instead, I decided to provide an interface, let's call it ICanvas, and redirect all calls to Graphics somehow. This would allow me to avoid testability issues with Graphics (even if I mock it with TypeMock, internally it depends on other objects, so I have to dig in and specifically mock a couple of calls), and also it would allow me to substitute it for other outputs later, so that in theory I'll be able to print to PDF, Word, HTML etc., and the developers could add other outputs.&lt;br /&gt;&lt;br /&gt;So far, everything looks so wise. Until I try to write my first test. It's supposed to be pretty straightforward: just print the word "test". However, when I try to write it, I discover that I even don't know my API! I don't have my ICanvas interface, much less its implementation, I don't have a Print method, and I don't know how to glue these things together.&lt;br /&gt;&lt;br /&gt;So, although I already knew that I shouldn't design upfront, somehow I got into this trap again. I've been lucky that I haven't written much code before realizing that.&lt;br /&gt;&lt;br /&gt;Now I'm going to do it by the book. Just find the simplest way to print a word and do just that. The really simplest way, it turns out, is to inherit from the PrintDocument class and override the OnPrintPage method. Then use the Graphics object to print stuff. For the moment, I have to forget all the elegant objects I invented, and follow the ugly (but quick) path. I even hardcode the word "test" in my code!&lt;br /&gt;&lt;br /&gt;But before I do, I should write the test. Mocking Graphics isn't the simplest thing in the world, but with a little bit of &lt;a href="http://www.aisto.com/roeder/DotNet/"&gt;Reflector&lt;/a&gt; I produce the following piece of code:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Imports TypeMock&lt;br /&gt;&lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt; &lt;span style="color:blue;"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&amp;lt;TestFixture&amp;gt;&lt;/span&gt;Public&lt;/span&gt; &lt;span style="color:blue;"&gt;Class&lt;/span&gt; Tests&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&amp;lt;&lt;/span&gt;&lt;/span&gt;Test, VerifyMocks&lt;span style="color:blue;"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color:blue;"&gt;Sub&lt;/span&gt; PrintSimpleText()&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Dim&lt;/span&gt; graphicsMock = MockManager.Mock(&lt;span style="color:blue;"&gt;Of&lt;/span&gt; Drawing.Graphics)(Constructor.Mocked)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        graphicsMock.ExpectCall(&lt;span style="color: rgb(163, 21, 21);"&gt;"DrawString"&lt;/span&gt;).Args(&lt;span style="color: rgb(163, 21, 21);"&gt;"test"&lt;/span&gt;, Check.IsAny, Check.IsAny,  Check.IsAny, Check.IsAny)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;Dim&lt;/span&gt; SystemFontsMock = TypeMock.MockManager.Mock(&lt;span style="color:blue;"&gt;GetType&lt;/span&gt;(System.Drawing.SystemFonts))&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        SystemFontsMock.ExpectGetAlways(&lt;span style="color: rgb(163, 21, 21);"&gt;"DefaultFont"&lt;/span&gt;, &lt;span style="color:blue;"&gt;New&lt;/span&gt; System.Drawing.Font(&lt;span style="color: rgb(163, 21, 21);"&gt;"Verdana"&lt;/span&gt;, 8))&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(51, 51, 255);"&gt;Dim&lt;/span&gt; TestReport = &lt;span style="color:blue;"&gt;New&lt;/span&gt; Report&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        TestReport.PrintController = &lt;span style="color:blue;"&gt;New&lt;/span&gt; Drawing.Printing.PreviewPrintController&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        TestReport.Print()&lt;/p&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Class&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;&lt;/blockquote&gt;A few comments here for those who's not familiar with TypeMock. It creates a Mock object that "waits" till a real object of this type is created, and then "hooks" on it and lets us watch/catch/stub/fake method and property calls to this object. This contrasts to the other frameworks and also manual mocking, where you have to manually create an object which replaces the "real" object. Notice that we are mocking a Graphics object which is created somewhere deep in the System.Drawing.Printing namespace. Since the Microsoft's design is (as always) utterly untestable, we can't feed our own mock object, so our only option is trick the code with the help of TypeMock. So, first we create a mock for Graphics, then we tell it that we expect a call to the DrawString method, and that the first argument should be "test", and the rest can be anything. Same with the SystemFonts object, but we also tell it that it should return a specific value.&lt;br /&gt;&lt;br /&gt;Now, my production code would be:&lt;br /&gt;&lt;blockquote&gt; &lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1251\uc1 \deff0{\fonttbl{\f0\fnil\fcharset204\fprq1 Consolas;}}{\colortbl;??\red0\green0\blue255;\red255\green255\blue255;\red0\green0\blue0;\red163\green21\blue21;}??\fs20 \cf1 Public\cf0  \cf1 Class\cf0  Report\par ??\tab \cf1 Inherits\cf0  PrintDocument\par ??\par ??\tab \cf1 Protected\cf0  \cf1 Overrides\cf0  \cf1 Sub\cf0  OnPrintPage(\cf1 ByVal\cf0  e \cf1 As\cf0  System.Drawing.Printing.PrintPageEventArgs)\par ??\tab \tab e.Graphics.DrawString(\cf4 "test"\cf0 , \cf1 New\cf0  Drawing.Font(\cf4 "Verdana"\cf0 , 8.0, Drawing.FontStyle.Regular), Drawing.Brushes.Black, 0, 0)\par ??\tab \cf1 End\cf0  \cf1 Sub\par ??\par ??End\cf0  \cf1 Class} --&gt; &lt;div    style="background: white none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Consolas;font-size:10pt;color:black;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;Public&lt;/span&gt; &lt;span style="color:blue;"&gt;Class&lt;/span&gt; Report&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;Inherits&lt;/span&gt; PrintDocument&lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;Protected&lt;/span&gt; &lt;span style="color:blue;"&gt;Overrides&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt; OnPrintPage(&lt;span style="color:blue;"&gt;ByVal&lt;/span&gt; e &lt;span style="color:blue;"&gt;As&lt;/span&gt; System.Drawing.Printing.PrintPageEventArgs)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;        e.Graphics.DrawString(&lt;span style="color: rgb(163, 21, 21);"&gt;"test"&lt;/span&gt;, &lt;span style="color:blue;"&gt;New&lt;/span&gt; Drawing.Font(&lt;span style="color: rgb(163, 21, 21);"&gt;"Verdana"&lt;/span&gt;, 8.0, Drawing.FontStyle.Regular), Drawing.Brushes.Black, 0, 0)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Sub&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;End&lt;/span&gt; &lt;span style="color:blue;"&gt;Class&lt;/span&gt;&lt;/p&gt; &lt;/div&gt;  &lt;/blockquote&gt;I've got a green, I'm happy for today, and I'm particularly ecstatic about having the word "test" hardcoded in my production code.&lt;br /&gt;&lt;br /&gt;What I'm not happy about is that ever since I upgraded to TypeMock version4, my Zanebug GUI won't run with the TypeMock runner. So, I had to switch back to NUnit. I don't know about their engines, but I feel quite uncomfortable with the NUnit GUI. OK, it's personal.&lt;br /&gt;&lt;br /&gt;What's next? The next useful feature seems to be the ability to print any text we want, not just the word "test". This is going to be the topic of the next post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-7200498587843665576?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/7200498587843665576/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=7200498587843665576' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/7200498587843665576'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/7200498587843665576'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/08/adventures-in-test-driven-development_02.html' title='Adventures in test-driven development Part 1, first mistake'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-459687899262360325</id><published>2007-08-02T13:51:00.000+04:00</published><updated>2007-11-10T22:27:29.545+03:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Adventures in test-driven development'/><category scheme='http://www.blogger.com/atom/ns#' term='Inka'/><category scheme='http://www.blogger.com/atom/ns#' term='FreshReports'/><title type='text'>Adventures in test-driven development, Introduction</title><content type='html'>Being a novice to TDD, I decided to start some sort of a diary about re-making of FreshReports using things I learned recently about the TDD process. Hopefully it'll help somebody to get started.&lt;br /&gt;&lt;br /&gt;My toolbox:&lt;br /&gt;Visual Basic 2008 Express Edition (I'm going to miss the TestDriven.Net add-in a lot!)&lt;br /&gt;Adaptev's Unit testing framework and &lt;a href="http://www.adapdev.com/zanebug/"&gt;Zanebug&lt;/a&gt; (I don't know why I prefer it over NUnit)&lt;br /&gt;&lt;a href="http://www.typemock.com/"&gt;TypeMock&lt;/a&gt; -- it saves a lot of testing efforts&lt;br /&gt;&lt;a href="http://www.ayende.com/Wiki/%28S%282vv4sqfxhx0wh055f2iuht55%29%29/Default.aspx?Page=Rhino+Mocks+Documentation"&gt;RhinoMocks&lt;/a&gt; -- I was told that it "enforces good design", so, although &lt;a href="http://dotfresh.blogspot.com/2007/08/on-good-frameworks-forcing-good-things.html"&gt;I don't like being enforced&lt;/a&gt;, I decided to try it and see the design it enforced.&lt;br /&gt;&lt;br /&gt;Now, let's start!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-459687899262360325?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/459687899262360325/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=459687899262360325' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/459687899262360325'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/459687899262360325'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/08/adventures-in-test-driven-development.html' title='Adventures in test-driven development, Introduction'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-5423358184393845455</id><published>2007-07-28T15:52:00.000+04:00</published><updated>2007-07-28T16:01:25.172+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Amazing stuff'/><title type='text'>Electric sheep and collective computer dreams</title><content type='html'>Just installed me a new screensaver -- &lt;a href="http://www.electricsheep.org/index.cgi?&amp;amp;menu=about"&gt;the electric sheep&lt;/a&gt;. This is not just the most beautiful screensaver I've ever seen. It's a sort of genetic mutation engine. The screensaver is governed by a bunch of parameters ("genes"), which is a common thing. However, here these are not predefined. Numerous combinations are downloaded from the server (or maybe other clients), new combinations are generated by random mutations and uploaded again. You can vote for a combination and thus increase the chance that this specie survives. Thus, the Darwin law dictates that only the most beautiful sheep survive.&lt;br /&gt;&lt;br /&gt;The sheep do resemble my computer's dreams indeed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-5423358184393845455?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/5423358184393845455/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=5423358184393845455' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/5423358184393845455'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/5423358184393845455'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/07/electric-sheep-and-collective-computer.html' title='Electric sheep and collective computer dreams'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-4347305715323895477</id><published>2007-07-26T01:43:00.000+04:00</published><updated>2007-07-26T15:57:29.593+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming practices'/><title type='text'>Spaghetti on Rails</title><content type='html'>Yesterday I was totally enraged by the comments to &lt;a href="http://www.ayende.com/Blog/archive/2007/07/23/The-Correct-Separation-Of-Concerns.aspx"&gt;this&lt;/a&gt; post. It was so bad I couldn't sleep until I got out of my bed and wrote a comment. Shame on me.&lt;br /&gt;&lt;br /&gt;Anyway. People recently talk a lot about this Monorail thing, and how it encourages separation of concerns, testability, and maintainability of your code. I've been sort of curious, but not enough to dig into examples. So, judging from this post and the code example somebody provided, turns out all they can do is the PHP style spaghetti code.&lt;br /&gt;&lt;br /&gt;But the most amazing thing is that how much effort these guys put into arguing that 1: This is the best method since it's putting presentation and presentation logic together; 2: Microsoft is bad (again) because they invented the DataGrid (and presumably forcing us to use it everywhere); and 3: "we can do it with less lines of code". &lt;span id="apnlCommentsWrapper$RBS_Holder"&gt;&lt;span id="apnlCommentsWrapper" ajaxcall="async"&gt;&lt;br /&gt;Chill, guys, peace and all that.&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-4347305715323895477?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.ayende.com/Blog/archive/2007/07/23/The-Correct-Separation-Of-Concerns.aspx' title='Spaghetti on Rails'/><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/4347305715323895477/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=4347305715323895477' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/4347305715323895477'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/4347305715323895477'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/07/spaghetti-on-rails.html' title='Spaghetti on Rails'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-7670462714195725958</id><published>2007-07-15T16:38:00.000+04:00</published><updated>2007-08-02T00:00:04.481+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Dormidontus'/><category scheme='http://www.blogger.com/atom/ns#' term='Programming practices'/><category scheme='http://www.blogger.com/atom/ns#' term='FreshReports'/><title type='text'>My first attempts at "proper" TDD</title><content type='html'>Although I've used it several times in the past, my first serious attempt was with &lt;a href="https://sourceforge.net/projects/freshreports/"&gt;FreshReports&lt;/a&gt;. That is, I wasn't testing it manually at all.&lt;br /&gt;&lt;br /&gt;FreshReports is a printing component (a framework wannabe). It uses xml files as the source for design and in-memory objects (in contrast to the majority of such components that use database rows) for the data.&lt;br /&gt;&lt;br /&gt;Naturally, I quickly figured out some basic design, wrote a trivial xml file and started to write tests. In addition, I've been inheriting from System.Drawing.Printing.PrintDocument, and used the hardcoded System.Drawing.Graphics object. Just like all tutorials on printing suggested.&lt;br /&gt;&lt;br /&gt;Like any amateur, I thought I was doing unit testing, but in fact I was doing integration tests. I thought I was doing test-first, but in fact I designed something first and tried to fix my bugs with testing. Well, I was doing just fine. I stumbled upon TypeMock, and this wonderful tool allowed me to do a lot of testing without all these IoCs and SoCs people talk about. I said I was doing just fine because, although I could spend an hour or two in the debugger trying to figure out what's going on (or lately, after I read in some blog post that I shouldn't be in the debugger, I started to log way too much to the console and also started writing tests for my private variables), I've been doing it all the time before. I just didn't know there could be a better way.&lt;br /&gt;&lt;br /&gt;At least I learned what a mock is. Because before that I thought it was too complicated for me.&lt;br /&gt;&lt;br /&gt;My second attempt was with Dormidontus. I've learned a lot since then, and I have heard that unit testing is about testing small isolated pieces. Armed with TypeMock, I could mock everything my methods call (even the class I've been testing). So I decided to move with small steps. I figured, for example, that my main workflow consists of three steps. So, I happily mocked three method calls (because I already figured the classes responsible for these steps), then wrote the main method and got a green. Now, each method call could be naturally broken into smaller steps, so I mocked these smaller steps, repeated the calls in the production code, got a green again.&lt;br /&gt;&lt;br /&gt;In short, most of my tests (until I got to the lowest level) contained no asserts, but just mocked calls to other objects. I guess this is what you call interaction-based tests. All went rather smooth, however, I felt that something is wrong. First, my test code duplicated my production code. There was no way to write my production code other than it was dictated by my tests. So, in a way my design &lt;span style="font-weight: bold;"&gt;was &lt;/span&gt;driven by my tests, but at the same time I knew my design before I even started to write a test. Second (a direct consequence), it was impossible to refactor without breaking the tests. Given these two, I felt that my tests are pretty useless, except for the fact that I didn't have to debug my application.&lt;br /&gt;&lt;br /&gt;I then posted a &lt;a href="http://tech.groups.yahoo.com/group/testdrivendevelopment/message/24854"&gt;question &lt;/a&gt;to the testdriven yahoo group regarding testing my high level methods that don't do anything except for calling other lower-level methods. After I received a couple of very clarifying answers, I realized my mistake. Instead of trying to provide some business value as soon as possible, I was focused on my oh-so-elegant design.&lt;br /&gt;&lt;br /&gt;I still believe that TypeMock is terrific. It is a pure magic. For example, back to FreshReports, no matter how you abstract and wrap the Graphics object, eventually you should test your wrapper, or adapter, or proxy. You just can't do it without TypeMock.&lt;br /&gt;&lt;br /&gt;Some people dislike TypeMock for it does not &lt;span style="font-style: italic;"&gt;force &lt;/span&gt;you to apply "good" practices. Not only I disagree, it drives me mad. I strongly believe that grown-ups should not be forced. But that's a good idea for another blog post. Now I admit that with regards to TDD I'm far from being a grown-up, so perhaps being forced (or I'd say, led) could be a good thing for me until I'm more confident with these things. However, I'm still thankful since TypeMock gave me a soft start with mocking, and also gave me these lessons.&lt;br /&gt;&lt;br /&gt;With Dormidontus, I managed to switch to the right path right in the middle of the project (yes, I even managed to force myself to delete a good part of the existing code). As for FreshReports, with some hesitation I decided to build it again from scratch. I've got the second beta of Orcas Express (too lazy to download and too scared to install the full version). The first beta refused to work with TypeMock, so I decided that it's a sign and I should try &lt;a href="http://www.ayende.com/Wiki/%28S%282vv4sqfxhx0wh055f2iuht55%29%29/Default.aspx?Page=Rhino+Mocks+Documentation"&gt;RhinoMocks&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Now I'm fighting through my first test.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-7670462714195725958?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/7670462714195725958/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=7670462714195725958' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/7670462714195725958'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/7670462714195725958'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/07/my-first-attempts-at-proper-tdd.html' title='My first attempts at &quot;proper&quot; TDD'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-7057586006526143572</id><published>2007-07-11T15:11:00.000+04:00</published><updated>2007-07-27T15:44:07.771+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming practices'/><title type='text'>Custom exceptions in custom components</title><content type='html'>Just published my first article at CodeProject.&lt;br /&gt;&lt;br /&gt;At the end they suggested I wrote some conclusion, so I got into a philosophical mood and wrote:&lt;br /&gt;&lt;br /&gt;&lt;span name="intelliTxt" id="intelliTXT"&gt;&lt;span style="font-style: italic; color: rgb(51, 51, 51);"&gt;I strongly believe that for every programming pattern out there -- be it      GoF, Microsoft, or your own, there should be a corresponding pattern of      exception handling and/or raising, or at least the exceptions should be made      an essential part of the pattern. After all, exceptions are classes, so many      existing patterns could be applied to them. Perhaps some day we'll hear      about Exception factories, Exception Strategies, and Exception Observers?&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is interesting, I do read a lot about design practices and patterns lately, and exceptions seem totally out of sight. Why? It's almost like not mentioning the devil..&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-7057586006526143572?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.codeproject.com/dotnet/CustomExceptions.asp' title='Custom exceptions in custom components'/><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/7057586006526143572/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=7057586006526143572' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/7057586006526143572'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/7057586006526143572'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/07/custom-exceptions-in-custom-components.html' title='Custom exceptions in custom components'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-307910657748015240</id><published>2007-06-28T23:34:00.000+04:00</published><updated>2007-06-29T00:04:24.569+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming practices'/><title type='text'>Build your own CAB series</title><content type='html'>Just finished reading the series on WinForms programming patterns by &lt;a href="http://codebetter.com/blogs/jeremy.miller/default.aspx"&gt;Jeremy D. Miller&lt;/a&gt;. Although I've been reading a lot of stuff on "how-to-do-it" recently, these posts really stand out. First, they are a big fun to read. Sometimes Jeremy explains his ideas with the help of four musketeers applying these patterns while fighting with their enemies. But even back to the coding, Jeremy's language is clear and simple. And second, and here goes my respect, he doesn't make it a dogma. He nevers says "you should do it this way coz that's the right way doing this". He says, in these situations I usually do it this way, and it helps me because of this and that. But yes, you can also do it another way if you want, but beware of this and that.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-307910657748015240?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://codebetter.com/blogs/jeremy.miller/archive/2007/06/26/build-your-own-cab-part-10-unit-testing-the-ui-with-nunitforms.aspx' title='Build your own CAB series'/><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/307910657748015240/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=307910657748015240' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/307910657748015240'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/307910657748015240'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/06/build-your-own-cab-series.html' title='Build your own CAB series'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-3823633408952555575</id><published>2007-06-24T23:17:00.000+04:00</published><updated>2007-06-25T00:08:07.248+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='FreshReports'/><title type='text'>FreshReports intro</title><content type='html'>I began to plan for FreshReports when I tried in vain searching for an open source printing framework. I, of course, used Crystal Reports a lot, but when I switched from Datasets to ORM (I'm using &lt;a href="http://neo.codehaus.org/"&gt;Neo&lt;/a&gt;), I was wondering if it is possible to print data coming from the object-oriented dimension.&lt;br /&gt;&lt;br /&gt;Actually, Crystal can do it, but in a very awkward way. Since the engine is relational-oriented, the business object printing ability is a nice add-on rather that a main idea, so you treat your objects as somewhat crippled data rows, with all consequences.&lt;br /&gt;&lt;br /&gt;Some other frameworks are presumably better with that, but I realized that all of them (well, all I have seen) are trying to be a sort of MS Access reports for .Net. All are trying to get past the business layer straight to the database. All are presenting the same section structure: you have your main data source, sort of a table, and you group it by some field, just like an SQL query. And none are open source.&lt;br /&gt;&lt;br /&gt;FreshReports is a totally different idea. Let's see it one by one.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;It's open source. I wrote in in VB.Net with a little bit of LINQ (from the May CTP). Why VB not C#? Because I know it better (I still think that C# would work better here). I do plan to make a commercial editor, but for now there's a vary simple standalone editor that just allows you to edit the source manually and preview it with a predefined data source.&lt;/li&gt;&lt;li&gt;It's extensible. You can add your own elements, aggregates, even sections. After I add layout rules and adapters, you'll be able to customize them, too.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;You have a simple xml format for the layout. So, in fact, you can program your own editor, or you can have it autogenerated.&lt;/li&gt;&lt;li&gt;You have no predefined layout. You can have sections inside sections, or sections after sections.&lt;/li&gt;&lt;li&gt;You can have any object structure. Your data source doesn't have to implement any interface, even IEnumerable.&lt;/li&gt;&lt;li&gt;You can have any number of independent (or interdependent) data sources. Each section can pick an external data source, or a property of the containing data item.&lt;/li&gt;&lt;li&gt;It's testable. From the beginning, I've been developing it in a TDD fashion (however, as I was a novice, I actually did integration tests, and only recently I started to write unit tests, but I understood a lot in the process). And I do plan to add  a testing framework later. All testing is done with &lt;a href="http://www.typemock.com/"&gt;TypeMock&lt;/a&gt;, and I'd like to thank the guys again for the great tool. Without it, it would be impossible to test the calls to the Graphics object which is in the core of all printing.&lt;/li&gt;&lt;/ul&gt;So, the first uploaded alpha version is, sort of, functional, and I even uploaded a small demo. I do hope that you try it and let me know.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-3823633408952555575?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='https://sourceforge.net/projects/freshreports' title='FreshReports intro'/><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/3823633408952555575/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=3823633408952555575' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/3823633408952555575'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/3823633408952555575'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/06/freshreports-intro.html' title='FreshReports intro'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-2833482750429281766</id><published>2007-06-23T23:22:00.000+04:00</published><updated>2007-06-24T00:11:58.128+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='FreshReports'/><title type='text'>FreshReports Alpha is released</title><content type='html'>I have finally uploaded a more or less functional copy of FreshReports to SourceForge. You can find it &lt;a href="https://sourceforge.net/projects/freshreports/"&gt;here&lt;/a&gt;. Now I'm gonna take a break, make a couple of reports with it, and start spreading a word.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-2833482750429281766?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='https://sourceforge.net/projects/freshreports/' title='FreshReports Alpha is released'/><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/2833482750429281766/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=2833482750429281766' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/2833482750429281766'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/2833482750429281766'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/06/freshreports-alpha-is-released.html' title='FreshReports Alpha is released'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8514833315479218736.post-1076342783661479840</id><published>2007-06-17T15:06:00.000+04:00</published><updated>2007-06-17T17:24:37.762+04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Programming practices'/><title type='text'>When good programming practices are just too good</title><content type='html'>Recently I saw an article on CodeProject (the article itself is very good, so I'd rather not post the link here) that had a great explanation of things like MVC, flexible design patterns, dependency injection, programming with interfaces etc.&lt;br /&gt;&lt;br /&gt;What struck me in this article is the ridiculous amount of code required to implement simple things. The author explained everything using a WinForm application as an example. So, the dependency injection was implemented not just for the form, but for a button as well! The author designed an interface for the Click event, and an extra class that implemented this interface and forwarded the call to the underlying button.&lt;br /&gt;&lt;br /&gt;Now, I see it as an excellent example of good programming practices -- everything is very clear. But at the same time, it is an example of what happens when a good practice it taken to an extreme. Take a look at this snippet:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;pre&gt;Private Sub OkButton_Click(...) Handles OkButton.Click&lt;br /&gt;  DoIt()&lt;br /&gt;End Sub&lt;/pre&gt;&lt;/span&gt;&lt;br /&gt;Now,  a "good programmer" would design an interface that provides the Click event, then design a class (say, GoodButton) that implements this interface and  use it as a  button on your form. Every single method or property that you need with a button you should put into the interface and then implement in your control, propagating them to your underlying button. In a way, you have "triplication" of your code here, and you write a lot of code that actually doesn't do anything, except for making your program "well designed" and use "proven practices". Why? Because this way "you have no hardcoded dependency on your Button class". Doesn't it sound ridiculous? And think of it, you now has a class GoodButton that just got a hardcoded dependency, and you have your form that has a hardcoded dependency on your GoodButton. Unless, of course, you put the class name in your config and load it dynamically. This way you just have to change "Button" in your config without recompiling the application.&lt;br /&gt;&lt;br /&gt;Sounds familiar?&lt;br /&gt;&lt;br /&gt;Next, you, of course, is going to test this code. You want to test that each time the button is clicked, the method DoIt is called. In order to do it you, perhaps, will make it public (which is clearly against the best practices), have some mock tests etc. But think again -- do you really want to test this 1-liner? How many lines of test code do you want to write, how much time to dedicate to fix bugs in your test code? Do you really think you are going to refactor it at some time? If yes, just put a comment: "NOT TESTED: REFACTOR WITH CARE" next to it, and you'll feel fine. Use NUnitForms to test your GUI, use TypeMock to test your hardcoded dependencies, and use interface-first design where you feel you need flexibility. In other words, use "thought driven design".&lt;br /&gt;&lt;br /&gt;We all love rules -- with them, you don't have to think much, you just apply what the smart guys think is the best. However, lately we younger generation begin rebel and declare these rules as "elitist crap". This happens in response to posts like &lt;a href="http://www.oobaloo.co.uk/articles/2007/6/6/visual-studio-regions-are-evil"&gt;this&lt;/a&gt;, when convenient tools are slammed down just because they don't force "good practices" on us. You can guess that the least thing I want is that something enforces me to do that somebody else thinks is "good". As a result, after I spend too much time on implementing some practice that I don't need, next time I prefer to forget about it. Same thing with testing -- after spending too much time on 100% testable projects, I discovered that I tend to skip testing totally, which proved to be very wrong decision.&lt;br /&gt;&lt;br /&gt;So, my idea is -- follow the big guys' ideas, but don't take them as rules, rather as advices. Implement them in say 90% of your application, and carefully weight all benefits each time. This is especially true in places where the code is autogenerated (it's already flexible enough: it takes little effort to replace a dependency, and you can trust it and use without testing). Your business layer is a good place for these practices. Hell, you might even want to change your ORM tool at some point!&lt;br /&gt;&lt;br /&gt;To summarise the whole Thought-Driven-Development-versus-Big-Guys issue:&lt;br /&gt;- Always think about the benefits of the proposed pattern. Don't get content with words like "flexible" and "eliminates dependency", even more with "proven". Think about what "flexible" means in your case, and what is "inflexible" if you do it straight, and why it is bad to be "inflexible" here. Estimate how much do you have to change if you need that flexibility later.&lt;br /&gt;- Always think about the costs. How much to you need to code just to make it flexible or testable. Note that you don't have to make it testable with TypeMock, for example, but that's considered a "bad" tool among purists, because it doesn't "enforce" us (meaning it liberates us a lot, actually).&lt;br /&gt;- If you discover that thу proposed practice makes your design unnecessarily complicated, unclear, adds too much nonfunctional code, or in any other way distracts you from your main purpose, write a blog entry about it, or comment somebody's article on good patterns, in order to provoke thinking and stop people from blindly following the rules.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/8514833315479218736-1076342783661479840?l=dotfresh.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://dotfresh.blogspot.com/feeds/1076342783661479840/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=8514833315479218736&amp;postID=1076342783661479840' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/1076342783661479840'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/8514833315479218736/posts/default/1076342783661479840'/><link rel='alternate' type='text/html' href='http://dotfresh.blogspot.com/2007/06/when-good-programming-practices-are.html' title='When good programming practices are just too good'/><author><name>ulu</name><uri>http://www.blogger.com/profile/09205790793910716812</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_4nvXZdHcdeo/S6kP3HdYYyI/AAAAAAAAAAM/7WODVHqXVRA/S220/ulu-sad.jpg'/></author><thr:total>2</thr:total></entry></feed>
