<?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-14511296</id><updated>2012-01-28T19:28:00.541+01:00</updated><category term='logging unit testing tdd'/><category term='unit testing'/><category term='design'/><category term='tdd'/><category term='c# functional programming'/><category term='tdd agile sudoku'/><category term='15min ioc'/><category term='c# design'/><category term='architecture'/><category term='agile'/><category term='agile process rant'/><category term='c# f# functional programming'/><title type='text'>thought-tracker</title><subtitle type='html'>A Collaborative Reading</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default?start-index=101&amp;max-results=100'/><author><name>moxica</name><uri>http://www.blogger.com/profile/10084204479295620888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>175</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-14511296.post-6576978912184942639</id><published>2010-03-15T12:59:00.004+01:00</published><updated>2010-03-15T13:49:25.201+01:00</updated><title type='text'>API Design &amp; Closures</title><content type='html'>In  a recent design discussion, I've noticed that the preferred&lt;span style="font-style: italic;"&gt; java-ish&lt;/span&gt; approach is rather verbose.&lt;br /&gt;&lt;br /&gt;Suppose we want to create an expression tree and evaluated-it:&lt;br /&gt;&lt;br /&gt;solution1:&lt;br /&gt;ExpressionTreeBuilder b = new ExpressionTreeBuilder();&lt;br /&gt;b.newExprY(a,b);&lt;br /&gt;b.newExprX(c,d);&lt;br /&gt;....&lt;br /&gt;ExpressionTree t = b.toTree();&lt;br /&gt;interpreter.eval(t);&lt;br /&gt;&lt;br /&gt;I find this solution rather difficult for '&lt;span style="font-style: italic;"&gt;beginners&lt;/span&gt;', the people who see the API for the 1st time. As a 1st time user of the API, I discover the interpreter as a service, and I start searching for the ExpressionTree to give it to the interpreter. I find the class, but it is immutable. I finally, redirect myself to the ExpressionTreeBuilder and I realize how can I use all the parts properly. IMO the above approach has a detective-trying-to-solve-a-puzzle feeling, exposing too much of the implementation mechanism.&lt;br /&gt;&lt;br /&gt;A much cleaner solution would be:&lt;br /&gt;interpreter.eval { |b|&lt;br /&gt; b.newExprX()&lt;br /&gt; b.newExprY()&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;This solution has a single point of entry and the user is directed to the correct API usage. The intermediate build/transform steps are hidden. It reminds me of &lt;a href="http://scala.sygneca.com/patterns/loan"&gt;scala loan pattern&lt;/a&gt;, or &lt;a href="http://www.xml.com/lpt/a/1637"&gt;ruby html builder&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-6576978912184942639?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/6576978912184942639/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=6576978912184942639' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/6576978912184942639'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/6576978912184942639'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2010/03/api-design-closures.html' title='API Design &amp; Closures'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-4966263219584529853</id><published>2010-02-16T09:41:00.002+01:00</published><updated>2010-02-16T10:12:44.744+01:00</updated><title type='text'>Java language EOL</title><content type='html'>via &lt;a href="http://www.infoq.com/news/2010/01/ThoughtWorks-Technology-Radar"&gt;InfoQ&lt;/a&gt;, link to the original &lt;a href="http://www1.vtrenz.net/imarkownerfiles/ownerassets/1013/Technology%20Radar%20Jan%202010.pdf"&gt;ThoughtWorks paper&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;The authors mention the fact that Java has been slow in adopting new  features lately, the initiative being taken by other languages built on  JVM, “languages such as Groovy, JRuby, Scala and Clojure.” They expect  enterprises to “begin to assess the suitability of reducing the amount  of Java-specific code developed in their enterprise applications in  favor of these newer languages.” Because of that, the authors suggest  assessing the end of Java as a programming language.&lt;/blockquote&gt;This boils down to &lt;a href="http://gafter.blogspot.com/"&gt;closures.&lt;/a&gt; If you start a new project, you could start with a project which allows you to do &lt;a href="http://www.scala-lang.org/node/4960"&gt;much&lt;/a&gt; &lt;a href="http://dev.bizo.com/2010/01/scala-supports-non-local-returns.html"&gt;more&lt;/a&gt; then just java. Related presentation: &lt;a href="http://www.infoq.com/presentations/gafter-jvm-closures"&gt;Language Parity: Closures &amp;amp; JVM&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-4966263219584529853?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/4966263219584529853/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=4966263219584529853' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/4966263219584529853'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/4966263219584529853'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2010/02/java-language-eol.html' title='Java language EOL'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-35859502277722753</id><published>2009-08-17T11:08:00.008+02:00</published><updated>2009-08-21T16:08:25.964+02:00</updated><title type='text'>Lambda, Linq, Dynamic Proxies</title><content type='html'>In the current project I've introduced some closure/function definitions: functions, actions. The usual stuff. (for reference look at the &lt;a href="http://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_7_5_final/src/library/scala"&gt;Scala API&lt;/a&gt;, or the google collections, or the Linq Func, or the &lt;a href="http://functionaljava.googlecode.com/svn/artifacts/2.20/javadoc/fj/package-summary.html"&gt;functional java&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;One problem with the current state of &lt;a href="http://gafter.blogspot.com/2007/01/definition-of-closures.html"&gt;closures&lt;/a&gt; in java is that, even though &lt;a href="http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg03277.html?"&gt;objects are closures&lt;/a&gt;, and they can be realized with &lt;a href="http://www.cuberick.com/2009/08/anonymous-inner-classes-poor-mans.html"&gt;anonymous classes&lt;/a&gt; (that's how scala compiler does it), we still have an interface impedance: my function definitions (interfaces) don't match google one's which don't match scala's, which don't match functional javas. So we'll have to write adapters (scala &lt;a href="http://www.scala-lang.org/node/114"&gt;reduces&lt;/a&gt; the adapter overhead).&lt;br /&gt;The other problem is that writing closures with anon-classes is a pain: probably that's why &lt;a href="http://gee.cs.oswego.edu/dl/papers/fj.pdf"&gt;Doug Lea&lt;/a&gt; is &lt;a href="http://blog.objectmentor.com/articles/2009/06/05/bay-area-scala-enthusiasts-base-meeting-whats-new-in-scala-2-8"&gt;looking&lt;/a&gt; into &lt;a href="http://www.softwaresecretweapons.com/jspwiki/doug-lea-is-a-grandfather-of-all-scala-actors"&gt;scala&lt;/a&gt;. In my project's context we basically/mostly have operations on collections, a sort of&lt;br /&gt;&lt;a href="http://blogs.warwick.ac.uk/chrismay/entry/writing_functional_java/"&gt;google collections dsl&lt;/a&gt;. The only 'ugly' part is the function definition: how the predicates/transformers are defined.&lt;br /&gt;&lt;br /&gt;It remindes me of &lt;a href="http://github.com/szeiger/scala-query/tree/master"&gt;Scala Query&lt;/a&gt; &amp;amp; &lt;a href="http://szeiger.de/blog/2008/07/27/formal-language-processing-in-scala-part-1/"&gt;Formal Language Processing in Scala&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I thought of the idea of creating proxies in order to define a function: e.g.&lt;br /&gt;Funcs.on(A.class).getB().create()  will create a proxy, will record the method call, and will create a function, which could be called on A objects. I didn't implement that because it seemed such an overkill to create a proxy in order to have a closure.&lt;br /&gt;But now I see that it has been implemented in &lt;a href="http://code.google.com/p/lambdaj/"&gt;lambdaj&lt;/a&gt; (query collections), and for jpa in &lt;a href="http://code.google.com/p/liquidform/"&gt;liquidform&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;What I've missed is that through dynamic proxies we might provide enough information to build queries  a la &lt;a href="http://delicious.com/andrei.pamula/linq%20java"&gt;LINQ&lt;/a&gt;. (i.e. the information which the c#/vb.net compiler provides on parsing the query,&lt;br /&gt;could be built, manually, by means of dynamic proxies, in java).&lt;br /&gt;---&lt;br /&gt;Update: Looking at &lt;a href="http://delicious.com/andrei.pamula/linq%20java"&gt;Linq/query for java&lt;/a&gt; frameworks:&lt;br /&gt;- one does byte code analysis in order to generate the query expression&lt;br /&gt;- one does dynamic proxy&lt;br /&gt;- one uses APT to generate query expressions from entities (something which people &lt;a href="http://blog.hibernate.org/Bloggers/Java6CompilerPluginsAndTypesafeCriteriaQueries"&gt;wished for jpa 2.0&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;Overall I fear/see that the syntax used to build a query-expression-tree might get rather clunky. Maybe in this area Scala could shine.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-35859502277722753?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/35859502277722753/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=35859502277722753' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/35859502277722753'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/35859502277722753'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2009/08/lambda-linq-dynamic-proxies.html' title='Lambda, Linq, Dynamic Proxies'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-4051145101990108540</id><published>2009-08-05T15:15:00.003+02:00</published><updated>2009-08-05T15:35:04.812+02:00</updated><title type='text'>Rx Framework</title><content type='html'>A new addition to the .Net platform, the Rx framework, aka 'reactive programming', aka 'linq to events'.&lt;br /&gt;&lt;br /&gt;Here is the &lt;a href="http://themechanicalbride.blogspot.com/2009/04/rx-framework-asynchronous-programming.html"&gt;lang.net presentation&lt;/a&gt;, the &lt;a href="http://channel9.msdn.com/shows/Going+Deep/Expert-to-Expert-Brian-Beckman-and-Erik-Meijer-Inside-the-NET-Reactive-Framework-Rx/"&gt;theoretical discussion/explanation/proof&lt;/a&gt; about the relation between the &lt;a href="http://en.wikipedia.org/wiki/Iterator_pattern"&gt;Iterator&lt;/a&gt; &amp;amp; &lt;a href="http://en.wikipedia.org/wiki/Observer_pattern"&gt;Observer&lt;/a&gt; pattern, and another &lt;a href="http://themechanicalbride.blogspot.com/2009/07/introducing-rx-linq-to-events.html"&gt;very good explanation&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The .Net approach is very elegant and reminded me of &lt;a href="http://publicobject.com/glazedlists/"&gt;Glazed Lists&lt;/a&gt; and of &lt;a href="http://tomasp.net/blog/reactive-i-fsevents.aspx"&gt;F# Reactive Programming.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Other thought associations were to &lt;a href="http://www.infoq.com/articles/pickering-fsharp-async"&gt;F# async workflows&lt;/a&gt;, and ruby gui frameworks: &lt;a href="http://leadthinking.com/191-bowline-a-ruby-gui-framework"&gt;bowline&lt;/a&gt; based on &lt;a href="http://www.appcelerator.com/products/titanium-desktop/"&gt;Titanium&lt;/a&gt;, and &lt;a href="http://kenai.com/projects/monkeybars/pages/Home"&gt;MonkeyBars&lt;/a&gt; based on swing.&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/14511296-4051145101990108540?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/4051145101990108540/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=4051145101990108540' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/4051145101990108540'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/4051145101990108540'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2009/08/rx-framework.html' title='Rx Framework'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-7133502595890770054</id><published>2009-08-04T10:11:00.007+02:00</published><updated>2009-08-04T10:38:43.893+02:00</updated><title type='text'>Variations on the visitor pattern</title><content type='html'>In the current project I've written so far at least 20 class hierarchies (+ their visitors) representing &lt;a href="http://en.wikipedia.org/wiki/Algebraic_data_type"&gt;ADT&lt;/a&gt;s.&lt;br /&gt;&lt;br /&gt;&lt;span&gt;The common scenario is that we have some data which is created by one module and consumed by others. Since the data is shared by 2+ modules, most operations on it require several services from several modules. &lt;/span&gt;&lt;br /&gt;&lt;span&gt;So we're out of luck with the &lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Interpreter_pattern"&gt;Interpreter Pattern&lt;/a&gt;&lt;span&gt;, we use the &lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Visitor_pattern"&gt;Visitor Pattern&lt;/a&gt;&lt;span&gt;/&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Double_dispatch"&gt;Double Dispatch&lt;/a&gt;&lt;span&gt;:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;abstract class Expression {&lt;/span&gt;&lt;br /&gt;&lt;span&gt;....static class Number extends Expression {&lt;/span&gt;&lt;br /&gt;&lt;span&gt;    ........public final int n;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;........Number(int n) { this.n = n; }&lt;/span&gt;&lt;br /&gt;&lt;span&gt;    ....}&lt;/span&gt;&lt;br /&gt;&lt;span&gt;    ....static class Plus extends Expression {&lt;/span&gt;&lt;br /&gt;&lt;span&gt;....&lt;/span&gt;&lt;span&gt;....&lt;/span&gt;&lt;span&gt;// since the data is immutable, there makes no sense to create getters&lt;/span&gt;&lt;br /&gt;&lt;span&gt;....&lt;/span&gt;&lt;span&gt;....&lt;/span&gt;&lt;span&gt;public final Expression left;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;....&lt;/span&gt;&lt;span&gt;....&lt;/span&gt;&lt;span&gt;        public final Expression right;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;....&lt;/span&gt;&lt;span&gt;....&lt;/span&gt;&lt;span&gt;Plus(left, right) { this.left = left; this.right = right; }&lt;/span&gt;&lt;br /&gt;&lt;span&gt;....&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;....&lt;/span&gt;&lt;span&gt;// toString, equals, hashCode are implemented with apache commons-lang, based on reflection up to the Expression class&lt;/span&gt;&lt;br /&gt;&lt;span&gt;....&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;The classic Visitor pattern says:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;interface Visitor {&lt;/span&gt;&lt;br /&gt;&lt;span&gt;....&lt;/span&gt;&lt;span&gt;void visit(Number n);&lt;/span&gt;&lt;br /&gt;&lt;span&gt;....&lt;/span&gt;&lt;span&gt;void visit(Plus plus);&lt;/span&gt;&lt;br /&gt;&lt;span&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;and&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;abstract void Expression#accept(Visitor v);&lt;/span&gt;&lt;br /&gt;&lt;span&gt;....&lt;/span&gt;&lt;span&gt;void Number#accept(Visitor v) { v.visit(this); }&lt;/span&gt;&lt;br /&gt;&lt;span&gt;....&lt;/span&gt;&lt;span&gt;void Plus#accept(Visitor v) { v.visit(this); }&lt;/span&gt;&lt;br /&gt;&lt;span&gt;// noticed the copy-paste !? (imagine doing that 40+ times...)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;In this example the visitor is a stateful closure which encapsulates a computation its initial data and its final (accumulated) result.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;The problem which might arise is how do we handle adding more data type (i.e. classes) to our hierarchy. See the &lt;/span&gt;&lt;a href="http://delicious.com/andrei.pamula/expression+problem"&gt;Expression Problem&lt;/a&gt;&lt;span&gt;, &lt;/span&gt;&lt;a href="http://wiki.apidesign.org/wiki/Case_Study_of_Writing_the_Extensible_Visitor_Pattern"&gt;Extensible Visitor&lt;/a&gt;&lt;span&gt;/&lt;/span&gt;&lt;a href="http://books.google.com/books?id=DXYZZVlWOAkC&amp;amp;printsec=frontcover&amp;amp;dq=practical+api+design#v=onepage&amp;amp;q=&amp;amp;f=false"&gt;book&lt;/a&gt;&lt;span&gt; (more on &lt;/span&gt;&lt;a href="http://lmgtfy.com/?q=Extensible%20Visitor"&gt;google&lt;/a&gt;&lt;span&gt; ;). &lt;/span&gt;&lt;br /&gt;&lt;span&gt;The proposed solution is to drill a hole in the type safety, in order to make old code compatible with new code:&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;interface Visitor {&lt;/span&gt;&lt;br /&gt;&lt;span&gt;....&lt;/span&gt;&lt;span&gt;void visit(Number n);&lt;/span&gt;&lt;br /&gt;&lt;span&gt;....&lt;/span&gt;&lt;span&gt;void visit(Plus plus);&lt;/span&gt;&lt;br /&gt;&lt;span&gt;....&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;oid otherwise(Expression x);&lt;/span&gt;&lt;br /&gt;&lt;span&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;Now we want to make the visitor stateless, maybe some visitors could be injectable services, eg: ExpressionPrinter, ExpressionEvaluator etc. In this scenario we want to extract the initial data &amp;amp; the result from the visitor:&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;interface Visitor[A,R] {&lt;/span&gt;&lt;br /&gt;&lt;span&gt;....&lt;/span&gt;&lt;span&gt;R visit(Number n, A args);&lt;/span&gt;&lt;br /&gt;&lt;span&gt;....&lt;/span&gt;&lt;span&gt;R visit(Plus plus, A args);&lt;/span&gt;&lt;br /&gt;&lt;span&gt;....&lt;/span&gt;&lt;span&gt;R otherwise(Expression x, A args);&lt;/span&gt;&lt;br /&gt;&lt;span&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;we also need to change the signature of the Expression#accept&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;abstract [A,R] R Expression#accept(Visitor v, A args);&lt;/span&gt;&lt;br /&gt;&lt;span&gt;....&lt;/span&gt;&lt;span&gt;[A,R] R Number#accept(Visitor v, A args) { v.visit(this, args); }&lt;/span&gt;&lt;br /&gt;&lt;span&gt;....&lt;/span&gt;&lt;span&gt;[A,R] R Plus#accept(Visitor v, A args) { v.visit(this, args); }&lt;/span&gt;&lt;br /&gt;&lt;span&gt;// noticed the copy-paste !? (imagine doing that 40+ times...)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;In this scenarion we can pass the initial data as args , the Expression will pass that to the visitor, which computes the final result R. &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;Another variation is when the visitor returns an element of the type which he visited. For that we need to modify the Expression:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;interface Expression {&lt;/span&gt;&lt;br /&gt;&lt;span&gt;....&lt;/span&gt;&lt;span&gt;E accept(Visitor v, A args);&lt;/span&gt;&lt;br /&gt;&lt;span&gt;....&lt;/span&gt;&lt;span&gt;static class Number implements Expression { ... }&lt;/span&gt;&lt;br /&gt;&lt;span&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;In this case we might use the A args in order to accumulate other results than the specified E type (we use the A as an accumulator).&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;If we want to really keep things clean and separate input from output, we could return on accept a tuple[R, E], but that's not needed in 90% of the cases.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;Compare that with &lt;a href="http://www.scala-lang.org/node/120"&gt;pattern matching&lt;/a&gt; on &lt;/span&gt;&lt;a href="http://www.scala-lang.org/node/107"&gt;case-classes&lt;/a&gt;&lt;span&gt;:&lt;/span&gt;&lt;br /&gt;&lt;span&gt;* no need for toString, equals, hashCode since they are generated by the compiler&lt;/span&gt;&lt;br /&gt;&lt;span&gt;* no need for visitors due to pattern matching&lt;/span&gt;&lt;br /&gt;&lt;span&gt;** no issues with statefull visitors&lt;/span&gt;&lt;br /&gt;&lt;span&gt;* no need for manual written ctors since they are written by the compiler,&lt;/span&gt;&lt;br /&gt;&lt;span&gt;* we get cca 50% less code to maintain.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span&gt;Now scale that to 20+ class hierarchies...&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-7133502595890770054?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/7133502595890770054/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=7133502595890770054' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/7133502595890770054'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/7133502595890770054'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2009/08/variations-on-visitor-pattern.html' title='Variations on the visitor pattern'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-8406489985469462873</id><published>2009-07-20T11:01:00.009+02:00</published><updated>2009-07-29T10:10:17.804+02:00</updated><title type='text'>Why Scala</title><content type='html'>I wanted to write a post 'Why &lt;a href="http://www.scala-lang.org/"&gt;Scala&lt;/a&gt; is such a nice/great language', but after I've seen the Martin Odersky presentations at &lt;a href="http://video.google.com/videoplay?docid=553859542692229789"&gt;google&lt;/a&gt;, and at &lt;a href="http://delicious.com/andrei.pamula/scala+presentation+fosdem+2009"&gt;FOSDEM 2009&lt;/a&gt;, Bonas Joner at QCon 2009 &lt;span style="text-decoration: underline;"&gt;'&lt;/span&gt;&lt;a href="http://www.slideshare.net/jboner/pragmatic-real-world-scala-45-min-presentation"&gt;Pragmatic Real-World Scala&lt;/a&gt;)', Evan Weaver with '&lt;a href="http://blog.evanweaver.com/articles/2009/03/13/qcon-presentation/"&gt;Improving Running Components at Twitter&lt;/a&gt;'  and the James Strachan's (of groovy fame) &lt;a href="http://macstrac.blogspot.com/2009/04/scala-as-long-term-replacement-for.html"&gt;post&lt;/a&gt;, an impressive &lt;a href="http://markthispage.blogspot.com/2009/06/more-than-100-sites-to-study-scala.html"&gt;collection of learning Scala resources&lt;/a&gt;, I had the impression that there is nothing more to be said (that hasn't be said before).&lt;br /&gt;&lt;br /&gt;There is even an &lt;a href="http://www.scala-lang.org/node/104"&gt;online&lt;/a&gt; and &lt;a href="http://www.scala-lang.org/docu/files/ScalaTour.pdf"&gt;offline&lt;/a&gt; ScalaTour.&lt;br /&gt;&lt;br /&gt;Nevertheless, we could/should mention&lt;br /&gt;&lt;br /&gt;Java-Basics:&lt;br /&gt;&lt;br /&gt;* seamless java integration&lt;br /&gt;* &lt;a href="http://www.scala-lang.org/node/91"&gt;IDE support&lt;/a&gt;, &lt;a href="http://stackoverflow.com/questions/972006/whats-the-best-scala-build-system"&gt;build support&lt;/a&gt; (maven, ant, sbt, buildr)&lt;br /&gt;* &lt;a href="http://stackoverflow.com/questions/953998/code-coverage-tools-for-scala"&gt;java code coverage&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;OO-Basics:&lt;br /&gt;* objects all-way-down (see &lt;a href="http://www.scala-lang.org/docu/files/ScalaOverview.pdf"&gt;ScalaOverview&lt;/a&gt;) (the Smalltalk way)&lt;br /&gt;** primitives are &lt;a href="http://www.drmaciver.com/2008/06/scala-arrays/"&gt;efficiently&lt;/a&gt; wrapped &amp;amp; handled by the compiler&lt;br /&gt;* closures/functions are objects &lt;a href="http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg03277.html?"&gt;too&lt;/a&gt;&lt;br /&gt;* multiple trait inheritance (e.g. &lt;a href="http://scala.sygneca.com/patterns/utility-belt"&gt;utility-belt&lt;/a&gt;, &lt;a href="http://johlrogge.wordpress.com/2009/06/27/loggingtools-in-scala/"&gt;logging&lt;/a&gt;, ...)&lt;br /&gt;&lt;br /&gt;Fun-Stuff:&lt;br /&gt;* &lt;a href="http://lampwww.epfl.ch/%7Eemir/written/MatchingObjectsWithPatterns-TR.pdf"&gt;extensible&lt;/a&gt; &lt;a href="http://www.scala-lang.org/node/120"&gt;pattern matching&lt;/a&gt; (i.e. switch on steroids on objects)&lt;br /&gt;* functional idioms allowed&lt;br /&gt;* &lt;a href="http://www.scala-lang.org/node/127"&gt;type inference&lt;/a&gt; (&lt;a href="http://delicious.com/andrei.pamula/hindley+milner"&gt;Hindley-Milner&lt;/a&gt;)&lt;br /&gt;* &lt;a href="http://scala-blogs.org/2008/10/manifests-reified-types.html"&gt;reified generics&lt;/a&gt;&lt;br /&gt;* &lt;a href="http://delicious.com/andrei.pamula/scala+type+classes"&gt;type classes&lt;/a&gt;&lt;br /&gt;* elegant solution to the &lt;a href="http://delicious.com/andrei.pamula/expression+problem"&gt;Expression Problem&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-8406489985469462873?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/8406489985469462873/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=8406489985469462873' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/8406489985469462873'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/8406489985469462873'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2009/07/why-scala.html' title='Why Scala'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-6072631232945177357</id><published>2009-07-13T14:03:00.004+02:00</published><updated>2009-07-13T14:14:36.653+02:00</updated><title type='text'>Moved Code Snippets to Mercurial</title><content type='html'>I've just moved the tip of the svn trunk to &lt;a href="http://mercurial.selenic.com/wiki/"&gt;mercurial&lt;/a&gt;.&lt;br /&gt;In order to make a push without a password you'll need to modify the .hgrc (specify your google code &lt;username&gt;username, password &lt;password&gt;:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;[paths]&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;span style="font-weight: bold;"&gt;thought-tracker&lt;/span&gt; = https://&lt;username&gt;&lt;span style="font-weight: bold;"&gt;username&lt;/span&gt;:&lt;span style="font-weight: bold;"&gt;password&lt;/span&gt;&lt;password&gt;@thought-tracker.googlecode.com/hg/&lt;/password&gt;&lt;/username&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In order to get it:&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;hg clone https://thought-tracker.googlecode.com/hg &lt;local_folder&gt;&lt;/local_folder&gt;&lt;/span&gt;&lt;span style="font-family: courier new; font-weight: bold;"&gt;local_folder&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In order to push/publish it (after a local &lt;span style="font-family:courier new;"&gt;hg ci -Am"some msg"&lt;/span&gt;):&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;hg push &lt;span style="font-weight: bold;"&gt;thought-tracker&lt;/span&gt;&lt;/span&gt;&lt;/password&gt;&lt;/username&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-6072631232945177357?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/6072631232945177357/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=6072631232945177357' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/6072631232945177357'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/6072631232945177357'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2009/07/moved-code-snippets-to-mercurial.html' title='Moved Code Snippets to Mercurial'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-1663782515300577229</id><published>2009-07-09T09:35:00.003+02:00</published><updated>2009-07-09T10:23:52.213+02:00</updated><title type='text'>DVCS(hg) vs SVN workflows</title><content type='html'>Suppose we work in an international company, remote sites, not so good connection between those sites.&lt;br /&gt;We have the following scenarios:&lt;br /&gt;&lt;br /&gt;1. We have to do a rather big refactoring, which will take several weeks.&lt;br /&gt;- With svn: we create a 'feature branch' where we'll do the refactoring. We update daily from trunk, we push to trunk regularly/at the end. The feature branch is allowed to be CI-red. (Due to an svn issue merging back-and-forth became a problem for svn-merge-tracking, and we had to do a tree-diff on 2 local sandboxes)&lt;br /&gt;- With hg: you just create a clone-branch, you work on it, you can merge with&lt;-&gt;from trunk regularly,&lt;br /&gt;whithout any merging problems.&lt;br /&gt;- Guerilla tactics: shadow the svn trunk/branch with some hg repositories and to the merges with hg (no tree-diff), at the end push the changes to svn&lt;br /&gt;&lt;br /&gt;2. Junior (remote) developer needs help fixing a unit-test.&lt;br /&gt;- With svn: do a branch, svn switch to it, push the code with the broken tests, fix them, merge back to trunk.&lt;br /&gt;- With webex: do a remote session an explain the fix&lt;br /&gt;- With hg: just pull the changes, make a fix, push them back to the remote developer. (hint: hg is more network-friendly then svn)&lt;br /&gt;&lt;br /&gt;3. An interface between 2 components is changed radically. Both the user &amp;amp; the implementation must be changed.&lt;br /&gt;- With svn: do a branch, do all the changes, merge to trunk&lt;br /&gt;- With hg: change the interface in a cloned repository, then share this repository between the user &amp;amp; implementer. They can work in parallel, the last one finishing pulls the changes from the other one and does the integration.&lt;br /&gt;&lt;br /&gt;4. Junior developer, friday@17.00, before a 3 week holiday, wants to commit his _weekly_ changes. He cannot create a local ci build within 1 hour so he doesn't commit anything.&lt;br /&gt;- He shouldn't integrate friday@17.00. (but he did)&lt;br /&gt;- With svn: create a branch, svn switch, push your changes to the server&lt;br /&gt;- With hg: a colleague could pull the changes an do the integration + push the changes, without the need to go through the server.&lt;br /&gt;&lt;br /&gt;5. Always keep the code green.&lt;br /&gt;- With svn: run the CI on the pre-commit hook (TeamCity does it). The code get's in the repository only if the build is green&lt;br /&gt;- With hg: maintain 2 repositories: in the 1st one we push the changes, which are peeked by the CI, validate, and on success pushed to another repository. (or just do a rollback; much easier with hg)&lt;br /&gt;&lt;br /&gt;A lot of the hg power comes from the fact that is changeset-based (unlike &lt;a href="http://subversion.tigris.org/faq.html#changesets"&gt;svn&lt;/a&gt;) and merges are really easy. Another big plus point goes to the distributed nature of hg: it enables more flexible workflows; in a centralized vcs all the communication is done through the server.&lt;br /&gt;&lt;br /&gt;links: &lt;a href="http://delicious.com/andrei.pamula/hg"&gt;hg&lt;/a&gt;, &lt;a href="http://delicious.com/andrei.pamula/git"&gt;git&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-1663782515300577229?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/1663782515300577229/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=1663782515300577229' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/1663782515300577229'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/1663782515300577229'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2009/07/dvcshg-vs-svn-workflows.html' title='DVCS(hg) vs SVN workflows'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-3363901565062092800</id><published>2009-05-07T15:13:00.000+02:00</published><updated>2009-05-07T15:14:26.083+02:00</updated><title type='text'>15 Min. Null</title><content type='html'>&lt;div style="width:425px;text-align:left" id="__ss_1399852"&gt;&lt;a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/andrei.pamula/15-minutes-null?type=presentation" title="15 Minutes Null"&gt;15 Minutes Null&lt;/a&gt;&lt;object style="margin:0px" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=15minnull-090507081231-phpapp02&amp;amp;stripped_title=15-minutes-null"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowScriptAccess" value="always"&gt;&lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=15minnull-090507081231-phpapp02&amp;amp;stripped_title=15-minutes-null" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;"&gt;View more &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/andrei.pamula"&gt;andrei.pamula&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-3363901565062092800?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/3363901565062092800/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=3363901565062092800' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/3363901565062092800'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/3363901565062092800'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2009/05/15-min-null.html' title='15 Min. Null'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-1328625166343956388</id><published>2009-05-04T10:15:00.002+02:00</published><updated>2009-05-04T10:17:54.715+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='15min ioc'/><title type='text'>15 Min. IoC</title><content type='html'>From my series, '15 minutes Lessons Learned', a short introduction to Inversion of Control&lt;br /&gt;&lt;br /&gt;&lt;div style="width:425px;text-align:left" id="__ss_1381790"&gt;&lt;a style="font:14px Helvetica,Arial,Sans-serif;display:block;margin:12px 0 3px 0;text-decoration:underline;" href="http://www.slideshare.net/andrei.pamula/15-min-ioc?type=powerpoint" title="15 Min IoC"&gt;15 Min IoC&lt;/a&gt;&lt;object style="margin:0px" width="425" height="355"&gt;&lt;param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=15minioc-090504031321-phpapp02&amp;amp;stripped_title=15-min-ioc"&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;param name="allowScriptAccess" value="always"&gt;&lt;embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=15minioc-090504031321-phpapp02&amp;amp;stripped_title=15-min-ioc" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;"&gt;View more &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/"&gt;presentations&lt;/a&gt; from &lt;a style="text-decoration:underline;" href="http://www.slideshare.net/andrei.pamula"&gt;andrei.pamula&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-1328625166343956388?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/1328625166343956388/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=1328625166343956388' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/1328625166343956388'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/1328625166343956388'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2009/05/15-min-ioc.html' title='15 Min. IoC'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-4404805571345494033</id><published>2009-02-23T13:35:00.002+01:00</published><updated>2009-02-23T13:41:46.936+01:00</updated><title type='text'>Programming Abstractions</title><content type='html'>Great post by Brian Hurt: &lt;a href="http://enfranchisedmind.com/blog/2009/02/22/programming-doesnt-suck-or-at-least-it-shouldnt/"&gt;Programming Doesn't Suck! Or At Least It Shouldn't&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Abstraction helps up the percentage of interesting code vr.s boring grunt work code, by minimizing the amount of boring grunt work code. If you can turn five lines of code, replicated ten thousand times, into one line of code, replicated ten thousand times, you’ve just turned a 50 KLOC project into a 10KLOC project, doable at least 5 times faster (and probably more like 25 times faster). Get the crap work out of the way fast, so you can get on to the more interesting stuff.&lt;/p&gt; &lt;p&gt;I’m not even talking about leaving your language of choice, I’m talking about thinking outside the box, or even just &lt;em&gt;thinking&lt;/em&gt;. But learning new languages is an advantage in making programming not suck, because if nothing else, it gives you new tools for your tool box, new ways to consider abstracting the code. And some languages &lt;em&gt;are&lt;/em&gt; better than others, and the more you know, the more likely you are to know a good one. And if you don’t know the better language, you can’t use it.&lt;/p&gt;&lt;p&gt;My initial response to the DailyWTF post was that it was another classic example of the starving child in Africa syndrome. You’ve seen the pictures. A child in some hell-hole of a third world, generally Africa but parts of Asia and South America qualify as well. The child is hungry, maybe starving, disease ridden, bug infested, and destined for a life that was nasty, brutish, and short. But they’re smiling away, happy as can be, simply because they don’t know any better. Everyone they’ve ever known, seen, or even heard of has been in exactly the same boat they are. That’s just what life is like. I often times think that many programmers are just like that staving child. They put up with, indeed don’t even see anything wrong with, having to write half a dozen lines of code just to set some UI properties, because they’ve never known any better. Bug ridden, virus invested, bloated, slow, impossible to maintain, that’s just what programming is.&lt;/p&gt; &lt;p&gt;The second post is convincing me that the situation is much, much worse than that. That it’s not just ignorance is the problem. It’s not just that many programmers don’t know any better, it’s that many programmers don’t &lt;em&gt;want&lt;/em&gt; to know any better, and are looking for an excuse, any excuse, to stay ignorant. It’s as if that starving child doesn’t want food, and would reject food if offered.&lt;/p&gt; &lt;p&gt;The reason that post is causing to me think this is because I’ve heard this argument before. All of them. See, I lived through the last great paradigm shift, when the industry moved from Procedural to Object Oriented- and heard the dying remnants of the one before that, from unstructured to procedural programming. I’ve heard all these arguments, or should I say excuses, before- from people trying to avoid learning C++ and Java.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Slightly related: Erik Meijer @ JAOO2008: '&lt;a href="http://jaoo.decenturl.com/brisbane-2008-file-path-jaoo"&gt;Why Functional Programming (Still) Matters&lt;/a&gt;'&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-4404805571345494033?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/4404805571345494033/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=4404805571345494033' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/4404805571345494033'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/4404805571345494033'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2009/02/programming-abstractions.html' title='Programming Abstractions'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-5819362018668532133</id><published>2009-02-06T09:34:00.002+01:00</published><updated>2009-02-06T09:41:09.031+01:00</updated><title type='text'>Failure, take two</title><content type='html'>Regarding the Agile/Scrum &lt;a href="http://thought-tracker.blogspot.com/2009/01/failure.html"&gt;failure&lt;/a&gt;, it has been a lot of &lt;a href="http://www.infoq.com/news/2009/02/whole-enchilada-and-context"&gt;buzz&lt;/a&gt; in the community:&lt;br /&gt;&lt;br /&gt;James Shore - &lt;a href="http://jamesshore.com/Blog/The-Decline-and-Fall-of-Agile.html"&gt;The Decline and Fall of Agile&lt;/a&gt;&lt;br /&gt;Martin Fowler - &lt;a href="http://martinfowler.com/bliki/FlaccidScrum.html"&gt;Flaccid Scrum&lt;/a&gt;&lt;br /&gt;Ron Jeffries - &lt;a href="http://xprogramming.com/blog/2009/01/30/context-my-foot/"&gt;Context My Foot&lt;/a&gt;&lt;br /&gt;&lt;blockquote&gt;Want to succeed at software? Then it can’t be business as usual. &lt;/blockquote&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-5819362018668532133?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/5819362018668532133/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=5819362018668532133' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/5819362018668532133'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/5819362018668532133'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2009/02/failure-take-two.html' title='Failure, take two'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-5042068195762755204</id><published>2009-01-28T09:33:00.002+01:00</published><updated>2009-01-28T09:36:24.373+01:00</updated><title type='text'>pet project idea</title><content type='html'>Implement a 'bean-mapper' a la &lt;a href="http://dozer.sourceforge.net/documentation/gettingstarted.html"&gt;Dozer&lt;/a&gt;, but instead of using the xml files, use dynamic proxies, a la &lt;a href="http://code.google.com/p/liquidform/"&gt;LiquidForm&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-5042068195762755204?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/5042068195762755204/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=5042068195762755204' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/5042068195762755204'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/5042068195762755204'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2009/01/pet-project-idea.html' title='pet project idea'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-8249220961688098767</id><published>2009-01-27T11:44:00.003+01:00</published><updated>2009-01-28T09:49:48.830+01:00</updated><title type='text'>Failure</title><content type='html'>Failure&lt;br /&gt;&lt;br /&gt;"&lt;a style="font-style: italic;" href="http://www.kevinfitzmaurice.com/cope_failure_not_learning.htm"&gt;The only failure is the failure to learn from failure&lt;/a&gt;" -- Kevin Everett FitzMaurice&lt;br /&gt;&lt;br /&gt;A friend of mine notice that in a big company, which recently decided to embrace agile and use Scrum, the Scrum practices are applied in a mechanical way. Actually he called it a 'theater', and he said that the '&lt;a href="http://agilemanifesto.org/principles.html"&gt;agile principles&lt;/a&gt;' are important. A colleague had a similar observation, that Scrum is applied in an american-indian-ceremony kind-of way, expecting that the results will fall out of the sky.&lt;br /&gt;&lt;br /&gt;Maybe this is related to the '&lt;a href="http://c2.com/cgi/wiki?ShuHaRi"&gt;Shu Ha Ri&lt;/a&gt;' &lt;a href="http://www.aikidofaq.com/essays/tin/shuhari.html"&gt;training cycle&lt;/a&gt;, &lt;a href="http://c2.com/cgi/wiki?ShuHaRi"&gt;which&lt;/a&gt;:&lt;br /&gt;&lt;a style="font-style: italic;" href="http://c2.com/cgi/wiki?TheThreeExtremos"&gt;&lt;/a&gt;&lt;blockquote&gt;&lt;a style="font-style: italic;" href="http://c2.com/cgi/wiki?TheThreeExtremos"&gt;TheThreeExtremos&lt;/a&gt;&lt;span style="font-style: italic;"&gt; lately seem to be recommending a &lt;/span&gt;&lt;a style="font-style: italic;" href="http://c2.com/cgi/wiki?ShuHaRi"&gt;ShuHaRi&lt;/a&gt;&lt;span style="font-style: italic;"&gt; approach to XP: First, follow &lt;/span&gt;&lt;em style="font-style: italic;"&gt;all&lt;/em&gt;&lt;span style="font-style: italic;"&gt; the practices. Then, realize &lt;/span&gt;&lt;a style="font-style: italic;" href="http://c2.com/cgi/wiki?TheyreJustRules"&gt;TheyreJustRules&lt;/a&gt;&lt;span style="font-style: italic;"&gt;, and change them (i.e. break some of the original rules). Finally, you don't need to think about the rules anymore. -- &lt;/span&gt;&lt;a style="font-style: italic;" href="http://c2.com/cgi/wiki?GeorgePaci"&gt;GeorgePaci&lt;/a&gt;&lt;/blockquote&gt;&lt;br /&gt;But in day-to-day business, it is just sloppiness. People don't understand that they are on a &lt;span style="font-weight: bold;"&gt;learning journey&lt;/span&gt;, they don't understand why are they following the practices/rules. Some don't want to learn, they just one to get the job done and go home. Many people are just happy with &lt;a href="http://www.pragprog.com/titles/prj/ship-it"&gt;Ship-It&lt;/a&gt;.  We've done, it, we are happy, let's go home. No retrospection, no how-can-we-do-it-better-next-time, no &lt;a href="http://en.wikipedia.org/wiki/5_Whys"&gt;5-whys&lt;/a&gt;. There is no striving towards elegance, to do things better. No passion, no motivation. Probably that's why retrospective are the first to be dropped/disregarded.&lt;br /&gt;&lt;br /&gt;Does this mean that Agile/(Scrum?) is a &lt;a href="http://www.infoq.com/presentations/agile-quality-canary-coalmine"&gt;culture-thing&lt;/a&gt;? How can we change a 'not-my-problem' culture? How can we stop &lt;a href="http://www.pragprog.com/the-pragmatic-programmer/extracts/software-entropy"&gt;sinking in a pool of problems&lt;/a&gt;? How can we &lt;a href="http://www.artima.com/intv/fixit.html"&gt;start carrying&lt;/a&gt;?&lt;br /&gt;&lt;br /&gt;ps. via &lt;a href="http://delicious.com/raganwald"&gt;rangawald's delicious&lt;/a&gt;, I found &lt;a href="http://www.defmacro.org/ramblings/taming-perfectionism.html"&gt;Taming Perfectionism&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-8249220961688098767?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/8249220961688098767/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=8249220961688098767' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/8249220961688098767'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/8249220961688098767'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2009/01/failure.html' title='Failure'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-1793631159817404499</id><published>2009-01-16T13:12:00.002+01:00</published><updated>2009-01-16T13:15:20.328+01:00</updated><title type='text'>The Membrane</title><content type='html'>Suppose we have 4 coupled/chained objects: A, B, C, D, accessible through the properties A.B.C.D, and the objects have the following properties:&lt;br /&gt;&lt;br /&gt;A: B, A1, A2&lt;br /&gt;B: C, B1, B2, B3&lt;br /&gt;C: D, C1, C2&lt;br /&gt;D: D1, D2, D3&lt;br /&gt;&lt;br /&gt;Usually within a certain area/component, we don't need all that object tree, but just a projection/subset of it: eg. IView { A1, B1, C1, D1. }&lt;br /&gt;In practice, the problem is that most of the people will use/scatter these properties all over their code, leading to maintenance monsters:&lt;br /&gt;- navigation is all over the place, violating the '&lt;a href="http://en.wikipedia.org/wiki/Law_of_Demeter"&gt;Law of Demeter&lt;/a&gt;'.&lt;br /&gt;- &lt;a href="http://jayflowers.com/WordPress/?p=78"&gt;Testing&lt;/a&gt; is getting a &lt;a href="http://misko.hevery.com/2008/07/18/breaking-the-law-of-demeter-is-like-looking-for-a-needle-in-the-haystack/"&gt;lot&lt;/a&gt; more difficult: in order to test a user of  IView you need to instatiate A, B, C, D, these might have good constructors which force you to instatiate other X objects, etc.&lt;br /&gt;- The amount of code using &lt;a href="http://martinfowler.com/articles/mocksArentStubs.html"&gt;chained objects/train wrecks&lt;/a&gt; will crush future refactorings: if you'll want to reverse the navigation from B.C to C.B, you'll have to change all the usage points, the same goes for changing a data type.&lt;br /&gt;&lt;br /&gt;Possible solutions:&lt;br /&gt;a. Define the projection as required by that component/use case, eg IView { A1, B1, C1, D1 } (properties, or getter/setter, etc.)&lt;br /&gt;- Define a repository service IRepository.get(...) -&gt; IView&lt;br /&gt;- Work against &lt;span style="font-weight: bold;"&gt;your abstraction&lt;/span&gt; IRepository/IView&lt;br /&gt;&lt;br /&gt;The IView/IRepository could build through:&lt;br /&gt;- DTOs mapping (a la &lt;a href="http://dozer.sourceforge.net/"&gt;dozer&lt;/a&gt; &amp;amp; &lt;a href="http://dozer-annotate.sourceforge.net/"&gt;co&lt;/a&gt;.)&lt;br /&gt;- wrap &amp;amp; lazy fetch:&lt;br /&gt;View {&lt;br /&gt;  ctor(A a) { _a = a; }&lt;br /&gt;  A1 { _a.A1 }&lt;br /&gt;  B1 { _a.B.B1}&lt;br /&gt; C1  { _a.B.C.C1 }&lt;br /&gt; D1  { _a.B.C.D1 }&lt;br /&gt;}&lt;br /&gt;(&lt;span style="font-style: italic;"&gt;a pretty slick solution might be build with LINQ expressions&lt;/span&gt;)&lt;br /&gt;In this way we have isolated our component from external changes, we are depending only on our IRepository/IView, future refactorings will afect only that area.&lt;br /&gt;The IRepository/IView abstractions represent the membrane to the external world. (&lt;a href="http://rkse.blogspot.com/"&gt;Ralf&lt;/a&gt; refers to the pattern as 'external adapter', probably refering to Alistair Cockburn's &lt;a href="http://alistair.cockburn.us/Hexagonal+architecture"&gt;'Hexagonal Architecture' paper&lt;/a&gt;, I prefer the Alan Kay's &lt;a href="http://video.google.com/videoplay?docid=-2950949730059754521"&gt;metaphor&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;b. Instead of defining the projection IView we could add the &lt;a href="http://www.pragprog.com/articles/tell-dont-ask"&gt;required operations&lt;/a&gt; on A. This has the benefit of aggregating/reusing common operations on A (usually a &lt;a href="http://www.lostechies.com/blogs/jimmy_bogard/archive/2008/05/20/entities-value-objects-aggregates-and-roots.aspx"&gt;root entity&lt;/a&gt;).&lt;br /&gt;In some cases it might lead to the polution of A: all the properties/operations beneath the A will emerge into A, transforming the tree into a list. Class A will become too big, containing its data, and n+ operations (C# has region-folding, smalltalk has protocols for organizing big classes)&lt;br /&gt;&lt;br /&gt;Final thoughts:&lt;br /&gt;- it is not about DDD/Tell don't Ask vs EJB/DTOs vs XXX, but is about isolation/visibility.&lt;br /&gt;- (Unit) Testing asap helps a lot identifying architecture/design smells.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-1793631159817404499?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/1793631159817404499/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=1793631159817404499' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/1793631159817404499'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/1793631159817404499'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2009/01/membrane.html' title='The Membrane'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-373843408312871325</id><published>2009-01-09T10:04:00.002+01:00</published><updated>2009-01-09T10:07:56.312+01:00</updated><title type='text'>toString or not toString</title><content type='html'>suppose we have an Id class, which used as a 'pointer' to some persistent entities.&lt;br /&gt;&lt;br /&gt;abstract class Id&lt;t&gt; {&lt;br /&gt;   T _raw;&lt;br /&gt;   Id(T raw) { _raw = raw; }&lt;br /&gt;   @Overrride void toString() { return _raw.toString(); }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;And the Object#toString() documentation says:&lt;br /&gt;   /**&lt;br /&gt;    * Returns a string representation of the object. In general, the&lt;br /&gt;    * #toString method returns a string that&lt;br /&gt;    * "textually represents" this object. The result should&lt;br /&gt;    * be a concise but informative representation that is easy for a&lt;br /&gt;    * person to read.&lt;br /&gt;    * It is recommended that all subclasses override this method.&lt;br /&gt;    *&lt;br /&gt;    * The #toString method for class Object&lt;br /&gt;    * returns a string consisting of the name of the class of which the&lt;br /&gt;    * object is an instance, the at-sign character `@', and&lt;br /&gt;    * the unsigned hexadecimal representation of the hash code of the&lt;br /&gt;    * object. In other words, this method returns a string equal to the&lt;br /&gt;    * value of:&lt;br /&gt;    * getClass().getName() + '@' + Integer.toHexString(hashCode())&lt;br /&gt;    **/&lt;br /&gt;&lt;br /&gt;What is the problem?&lt;br /&gt;&lt;br /&gt;* we heavily use these Ids in a *lot* of places&lt;br /&gt;* id.toString() is used both for Id -&gt; String conversion, as a part of our design and as textual representation for debugging/logging&lt;br /&gt;* to subclasses AID&lt;string&gt; and BID&lt;string&gt; will have the same textual representation, making future debugging/logging more confusing then necessary&lt;br /&gt;* if we enrich the Id with more data (eg. a timestamp, or entity version, etc.) we can no longer not add this extra data to its textual representation (eg. logging), since toString() is also used for conversion&lt;br /&gt;** it is very hard to find all the usages of the toString method, since every IDE (and the compiler too) considers this method belonging to the Object and not to the abstraction Id (that's why the @Override is there)&lt;br /&gt;*** if we would have worked in a TDD kind-of  way, we probably would have started with an interface, IUniqueId, to which we probably would have added a method asString()&lt;br /&gt;&lt;br /&gt;concluding advice: when you model your own domain language/design, be careful what you override.&lt;br /&gt;&lt;br /&gt;&lt;/string&gt;&lt;/string&gt;&lt;/t&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-373843408312871325?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/373843408312871325/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=373843408312871325' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/373843408312871325'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/373843408312871325'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2009/01/tostring-or-not-tostring.html' title='toString or not toString'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-9150291368069680466</id><published>2008-11-27T12:48:00.002+01:00</published><updated>2008-11-27T12:58:04.112+01:00</updated><title type='text'>Pragmatic Compromise</title><content type='html'>Have you noticed that all the guys who are advocating a compromise code quality  vs.  speed,&lt;br /&gt;are not the guys who are going to maintain that code? Have you noticed that these guys bully you into delivering features fast, and later they come complaining ' &lt;span style="font-style: italic;"&gt;Why is the quality so poor?&lt;/span&gt; '.&lt;br /&gt;Even if quality is not seen as &lt;a href="http://www.infoq.com/presentations/agile-quality-canary-coalmine"&gt;corporate asset&lt;/a&gt;, make it a part of your professional ethics.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-9150291368069680466?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/9150291368069680466/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=9150291368069680466' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/9150291368069680466'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/9150291368069680466'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2008/11/pragmatic-compromise.html' title='Pragmatic Compromise'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-3206167513244684024</id><published>2008-11-11T09:55:00.004+01:00</published><updated>2009-01-18T18:48:25.061+01:00</updated><title type='text'>DynamicQuery</title><content type='html'>Has anybody tried to do an EJB DynamicQuery implementation a la &lt;a href="http://grails.org/GORM"&gt;groovy&lt;/a&gt;, using a &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/reflect/Proxy.html"&gt;DynamicProxy&lt;/a&gt; ?&lt;br /&gt;(post inspired by &lt;a href="http://code.google.com/p/proxymatic/wiki/AutoBoundary"&gt;AutoBoundary proxymatic&lt;/a&gt;)&lt;br /&gt;Apparently yes: check-out the &lt;a href="http://code.google.com/p/liquidform/"&gt;LiquidForm&lt;/a&gt;.&lt;br /&gt;There are some other &lt;a href="http://delicious.com/andrei.pamula/jpa+linq"&gt;alternatives&lt;/a&gt;, but java is not &lt;a href="http://blogs.msdn.com/charlie/archive/2006/10/05/Links-to-LINQ.aspx"&gt;there&lt;/a&gt; &lt;a href="http://developer.db4o.com/blogs/carl/archive/2008/05/02/linq-for-java.aspx"&gt;yet&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-3206167513244684024?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/3206167513244684024/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=3206167513244684024' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/3206167513244684024'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/3206167513244684024'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2008/11/autoquery.html' title='DynamicQuery'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-3517306685612457781</id><published>2008-11-10T09:50:00.002+01:00</published><updated>2008-11-10T09:58:07.300+01:00</updated><title type='text'>Scrum Log</title><content type='html'>After reading/watching an impressive amount of presentations from Henrik Kniberg: &lt;a href="http://www.parleys.com/display/PARLEYS/Home#slide=1;title=10%20ways%20to%20screw%20up%20with%20Scrum%20%26%20XP;talk=19267619"&gt;parleys&lt;/a&gt;, &lt;a href="http://www.crisp.se/henrik.kniberg/presentations/agile2008/10-ways-to-screw-up-with-scrum-and-xp.pdf"&gt;slides&lt;/a&gt;, &lt;a href="http://www.crisp.se/henrik.kniberg/presentations/agile2008/Technical-Debt-how-not-to-ignore-it.pdf"&gt;technical-debt&lt;/a&gt;, &lt;a href="http://www.crisp.se/henrik.kniberg/presentations/agile2008/Bootstrapping-Scrum-and-XP-in-a-crisis.pdf"&gt;bootstraping scrum and xp in a crisis&lt;/a&gt;, &lt;a href="http://blog.crisp.se/henrikkniberg/2008/02/01/1201823760000.html"&gt;scrum checklist&lt;/a&gt;, and &lt;a href="http://delicious.com/andrei.pamula/scrum"&gt;more&lt;/a&gt;, I've decided to keep a personal iteration log.&lt;br /&gt;It's amazing how much  clarity you get at the end of an iteration: the retrospective.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-3517306685612457781?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/3517306685612457781/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=3517306685612457781' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/3517306685612457781'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/3517306685612457781'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2008/11/scrum-log.html' title='Scrum Log'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-550909419764493844</id><published>2008-11-03T10:45:00.001+01:00</published><updated>2008-11-03T10:47:19.062+01:00</updated><title type='text'>Dark Syntax Highlight</title><content type='html'>(in RGB)&lt;br /&gt;Brackets: 128,255,0&lt;br /&gt;Keywords: 217,167,15&lt;br /&gt;Comments: 0,185,0&lt;br /&gt;Tasks,ToDos: 0,255,0&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-550909419764493844?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/550909419764493844/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=550909419764493844' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/550909419764493844'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/550909419764493844'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2008/11/dark-syntax-highlight.html' title='Dark Syntax Highlight'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-5669731063919979814</id><published>2008-10-23T15:01:00.003+02:00</published><updated>2008-10-23T15:21:35.404+02:00</updated><title type='text'>API Usability</title><content type='html'>The success of an API/component largely depends on its usability: is it easy to create, is it easy to handle, is it easy to wire?  Is it easy to make a mistake? Are some contracts unclear ?&lt;br /&gt;&lt;br /&gt;The first feedback we get from (unit-)tests. Unfortunately a lot of people don't do that.&lt;br /&gt;Another point is that the tests (partially) lie about how the component is used: they represent how the author assumes the component will be used. Feedback from customers and refactorings should follow...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-5669731063919979814?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/5669731063919979814/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=5669731063919979814' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/5669731063919979814'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/5669731063919979814'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2008/10/api-usability.html' title='API Usability'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-5224772890623818062</id><published>2008-10-22T16:41:00.002+02:00</published><updated>2008-10-22T17:38:43.151+02:00</updated><title type='text'>Filter support for PropertyConfigurator</title><content type='html'>The PropertyConfigurator class in log4j does not support filters and few other advanced configuration options. There was a need to add logging filters to a legacy Java app, but modifying the application code to use DomConfigurator was out question. The alternate approach was to directly add filter support to the PropertyConfigurator class in log4j.&lt;br /&gt;&lt;br /&gt;Filters are chained to an appender in a specified order.  However, the runtime representation of a .properties files is basically a hashtable, and there is no ordering defined on the keys of a plain hashmap. Any implicit ordering of the lines in the properties file is lost when it is parsed. To overcome this, filters are identified by unique IDs, and filters are added to the appender in the lexicographic order of the IDs.&lt;br /&gt;&lt;br /&gt;Keeping the notations used by the log4j source code, filters are configured as follows:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family: courier new;"&gt;log4j.appender.appenderName.filter.ID=fully.qualified.name.of.filter.class&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;log4j.appender.appenderName.filter.ID.option1=value1&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;log4j.appender.appenderName.filter.ID.optionN=valueN&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You can download the patch directly from the log4j &lt;a href="https://issues.apache.org/bugzilla/show_bug.cgi?id=46049"&gt;bug tracker&lt;/a&gt;. It can be applied to the current HEAD of the 1.2 branch, more exactly to 1.2.15.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-5224772890623818062?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/5224772890623818062/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=5224772890623818062' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/5224772890623818062'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/5224772890623818062'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2008/10/filter-support-for-propertyconfigurator.html' title='Filter support for PropertyConfigurator'/><author><name>moxica</name><uri>http://www.blogger.com/profile/10084204479295620888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-7676870485241016690</id><published>2008-10-10T09:52:00.001+02:00</published><updated>2008-10-10T09:54:18.550+02:00</updated><title type='text'>Coder</title><content type='html'>Written code is a cost, since it has to be maintained. Less code, less maintenance.&lt;br /&gt;Maybe we should call developers 'anti-coders'.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-7676870485241016690?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/7676870485241016690/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=7676870485241016690' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/7676870485241016690'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/7676870485241016690'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2008/10/coder.html' title='Coder'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-1014745457373662558</id><published>2008-08-19T12:45:00.003+02:00</published><updated>2008-08-19T13:03:08.254+02:00</updated><title type='text'>Option/Maybe monad is a generic NullObject</title><content type='html'>I've just reviewed the  &lt;a href="http://thought-tracker.blogspot.com/2006/06/nullobject-visitor.html"&gt;NullObject and Visitor&lt;/a&gt; post. It is so similar with the &lt;a href="http://blog.tmorris.net/scalaoption-cheat-sheet/"&gt;Option/Maybe&lt;/a&gt; monad.&lt;br /&gt;ps. Thought's on Validation: Scala/liftweb has an nice &lt;a href="http://github.com/dpp/liftweb/tree/master/lift/src/main/scala/net/liftweb/util/Can.scala"&gt;Can&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-1014745457373662558?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/1014745457373662558/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=1014745457373662558' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/1014745457373662558'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/1014745457373662558'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2008/08/optionmaybe-monad-is-generic-nullobject.html' title='Option/Maybe monad is a generic NullObject'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-8584104225893952754</id><published>2008-08-11T18:33:00.006+02:00</published><updated>2008-10-17T15:13:14.290+02:00</updated><title type='text'>Scala Marketing Challenge</title><content type='html'>&lt;a href="http://suereth.blogspot.com/2008/07/scala-marketing-challenge.html"&gt;Josh Suereth&lt;/a&gt; would like to &lt;a href="http://suereth.blogspot.com/2008/07/scala-marketing-challenge_29.html"&gt;improve&lt;/a&gt; the Scala's marketing strategy.&lt;br /&gt;This is a tough sell. If we &lt;a href="http://research.microsoft.com/%7Eemeijer/Papers/es012-meijer.pdf"&gt;look&lt;/a&gt; at the &lt;a href="http://www.coburnventures.com/About_CHANGE/The_Change_Function.html"&gt;Change Function&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;ChangeFunction = F(PerceivedCrisis/PerceivedPainOfAdoption).&lt;br /&gt;&lt;br /&gt;(btw. read Erik Meijer's paper: '&lt;span class="ft0"&gt;&lt;a href="http://research.microsoft.com/%7EEMeijer/Papers/ICFP06.pdf"&gt;Confessions of a Used Programming Language Salesman&lt;/a&gt;', it's really, really &lt;span style="font-weight: bold;"&gt;good.&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;So we'll have to ask ourselves what problem is Scala trying to solve, and how much it'll cost. IMHO, Scala is trying to make programming easier. It partially addresses the &lt;a href="http://lambda-the-ultimate.org/node/458"&gt;concurrency problem&lt;/a&gt;, but it is not its main-focus, I would say is the ScalaActors are a good side-effect of Scala's good  (language + library) design.&lt;br /&gt;&lt;br /&gt;What we'll have to pay in order to make the 'switch': the syntax is slightly different. Functions are 1st level citizens. (but functions/closure are &lt;a href="http://java.net/pub/pq/196"&gt;scary&lt;/a&gt;). Operator overload is also scary (funny enough, method overload is not scary: we are afraid of symbols but we are not afraid of words). Then we have for a good generic support we have '&lt;a href="http://lambda-the-ultimate.org/node/2579"&gt;Generics of a Higher Type&lt;/a&gt;', type &lt;a href="http://en.wikipedia.org/wiki/Covariance_and_contravariance_%28computer_science%29"&gt;covariance/contra-variance&lt;/a&gt;. Pretty scary... &lt;a href="http://flickr.com/photos/14461746@N02/2594088214/"&gt;booh&lt;/a&gt;! Did I say that IDE support is not yet at java's level?&lt;br /&gt;&lt;br /&gt;On the other side we have a huge number of java developers. They are satisfied. Not really happy, not really sad. Ok, java is not that great, but it has been like this for years, why change? To be more effective? Probably to sell that to a manager you'll need 5 independent studies to show that scala is better then java and you'll need at least one big company to push the language. ('if they use it, we could use it too')&lt;br /&gt;&lt;br /&gt;Regarding concurrency: a lot of java developers have problems to right correct code, so probably concurrency is the least of their problems. Other developers we'll say 'we have java.util.concurrency'.&lt;br /&gt;If you look at the package you'll see they offer concurrency &lt;span style="font-weight: bold;"&gt;primitives&lt;/span&gt;, and to write shared-state concurrent programs is very &lt;a href="http://www.javaconcurrencyinpractice.com/"&gt;hard&lt;/a&gt;. You'll have to think a lot &lt;a href="http://lamp.epfl.ch/%7Ephaller/actors.html"&gt;more&lt;/a&gt; about object isolation and the threading context.&lt;br /&gt;&lt;br /&gt;In conclusion:&lt;br /&gt;- UserPerceivedCrisis: small&lt;br /&gt;- PerceivePainOfAdoption: big&lt;br /&gt;ChangeFunction -tends-to-&gt; small.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.edge.org/3rd_culture/lanier06/lanier06_index.html"&gt;sorry&lt;/a&gt;, scala...&lt;br /&gt;&lt;br /&gt;&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/14511296-8584104225893952754?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/8584104225893952754/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=8584104225893952754' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/8584104225893952754'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/8584104225893952754'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2008/08/scala-marketing-challenge.html' title='Scala Marketing Challenge'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-4811643836764259046</id><published>2008-08-08T19:43:00.004+02:00</published><updated>2008-08-08T20:12:28.635+02:00</updated><title type='text'>Poka-yoke API Design</title><content type='html'>&lt;a href="http://www.techpresentations.org/How_to_Design_a_Good_API_and_Why_it_Matters"&gt;API&lt;/a&gt; &lt;a href="http://www.infoq.com/presentations/effective-api-design"&gt;Design &lt;/a&gt;should be &lt;a href="http://en.wikipedia.org/wiki/Poka-yoke"&gt;Poka-yoke&lt;/a&gt;.&lt;br /&gt;And if we look what &lt;a href="http://en.wikipedia.org/wiki/Zen"&gt;zen&lt;/a&gt; aesthetic &lt;a href="http://youtube.com/watch?v=DZ2vtQCESpk"&gt;means&lt;/a&gt; to people, a good design is &lt;span style="font-weight: bold;"&gt;zen&lt;/span&gt;: clean, simple, minimalistic.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-4811643836764259046?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/4811643836764259046/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=4811643836764259046' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/4811643836764259046'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/4811643836764259046'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2008/08/poka-yoke-api-design.html' title='Poka-yoke API Design'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-4064059388689371958</id><published>2008-07-31T23:39:00.001+02:00</published><updated>2008-07-31T23:41:22.325+02:00</updated><title type='text'>hg vs git, pull+merge vs rebase</title><content type='html'>&lt;a href="http://pastebin.com/f621152ca"&gt;@pastebin&lt;/a&gt;&lt;br /&gt;&lt;blockquote&gt;GIT encourages rebasing, which leads to rebasing of your public and other people's&lt;br /&gt;code. This is bad.&lt;br /&gt;&lt;br /&gt;Mercurial, which hashes a changeset's place in history as well as it's&lt;br /&gt;content, discourages rebasing. Rebasing happens in private with mq patch queues.&lt;br /&gt;Public trees are merged. This is good.&lt;br /&gt;&lt;br /&gt;Either style is possible with both tools. The difference is the default emphasis.&lt;br /&gt;&lt;br /&gt;Defaults matter.&lt;br /&gt;&lt;br /&gt;Linus Torvalds on rebasing:&lt;br /&gt;&lt;br /&gt;* http://kerneltrap.org/Linux/Git_Management&lt;br /&gt;* http://lwn.net/Articles/291302/&lt;br /&gt;* http://lwn.net/Articles/291303/&lt;br /&gt;* http://lwn.net/Articles/291304/&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Matt Mackall on synchronizing (pull + merge, don't push, don't rebase):&lt;br /&gt;&lt;br /&gt;* http://www.selenic.com/pipermail/mercurial/2008-July/020116.html&lt;br /&gt;* http://www.selenic.com/pipermail/mercurial/2008-July/020131.html&lt;/blockquote&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/14511296-4064059388689371958?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/4064059388689371958/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=4064059388689371958' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/4064059388689371958'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/4064059388689371958'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2008/07/hg-vs-git-pullmerge-vs-rebase.html' title='hg vs git, pull+merge vs rebase'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-3609196669207998368</id><published>2008-07-30T13:20:00.001+02:00</published><updated>2008-07-30T13:20:44.656+02:00</updated><title type='text'>Scala Roman Numbers</title><content type='html'>&lt;a href="http://fprogramming.org/paste/viewpaste.php?id=362"&gt;kata&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-3609196669207998368?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/3609196669207998368/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=3609196669207998368' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/3609196669207998368'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/3609196669207998368'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2008/07/scala-roman-numbers.html' title='Scala Roman Numbers'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-2539064325565859416</id><published>2008-07-24T16:36:00.002+02:00</published><updated>2008-07-24T16:49:17.002+02:00</updated><title type='text'>Scala Exercises</title><content type='html'>I have &lt;a href="http://fprogramming.org/paste/viewpaste.php?id=347"&gt;completed&lt;/a&gt; Tonny Morris &lt;a href="http://blog.tmorris.net/scala-exercises-for-beginners/"&gt;Scala exercises&lt;/a&gt;. (maybe I'll put them on the svn as well, or maybe mercurial ?)...&lt;br /&gt;Anyway some observations:&lt;br /&gt;- it felt like doing the '&lt;a href="http://www.google.com/search?q=Little%20Schemer"&gt;Little Schemer&lt;/a&gt;' in Scala.&lt;br /&gt;- after doing 3-4 exercises, you feel the need to use/implement fold_left/fold_right.&lt;br /&gt;- maximum is buggy: what's the maximum on an empty list? (the maximum found must be contained in the list;reasoning related to '&lt;a href="http://apocalisp.wordpress.com/2008/05/03/null-vs-pure-reason/"&gt;Noumenal Null&lt;/a&gt;'). I believe that this exercise is a 'tricky question' and instead of throwing an exception, or returning Nothing or Int.NaN, probably the signature should be changed to : &lt;span style="font-family: courier new;"&gt;maximum(x: List[Int]) : Option[Int]&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;- In the List's implementation of map/filter/... they use instead of pattern matching &lt;span style="font-family: courier new;"&gt;if x.isEmpty ... else ( do_something(x.head, x.tail)&lt;/span&gt;. Probably it's faster than pattern decomposition.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-2539064325565859416?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/2539064325565859416/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=2539064325565859416' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/2539064325565859416'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/2539064325565859416'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2008/07/scala-exercises.html' title='Scala Exercises'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-7937596234572820840</id><published>2008-06-12T20:22:00.002+02:00</published><updated>2008-06-12T20:28:19.076+02:00</updated><title type='text'>Lack of Fit</title><content type='html'>Over the J. Paul Morrison's &lt;a href="http://www.jpaulmorrison.com/fbp/morrison_2005.htm"&gt;article&lt;/a&gt; I found the following quotation:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt; In the early part of his book "Notes on the Synthesis of Form", Alexander describes the concept of "fit".  He makes the point that, as humans, we find it very hard to detect "fit", but are well-adapted to detecting "lack of fit".   Think of trying to decide if the edge of a piece of wood is straight: the natural thing to do is to put it against a straight surface and see if any gaps show in between.  As we try to improve things by reducing the misfit factors, we soon discover that these factors tend to be interrelated: fixing one may exacerbate another, so there is a continuous process of compromise between a number of less than ideal solutions. Intuitively, the less interrelated the misfit items are, the easier it will be to reach a state of acceptable fit. This means that our only hope of reducing misfit factors is if these factors occur in clusters such that the connections between clusters are relatively loose.  In application development, this works best if the infrastructure software components also define boundaries between misfit factors.&lt;/blockquote&gt;&lt;br /&gt;maybe that's why I'm so critical....&lt;br /&gt;btw. I've started reading J. Paul Morrison's &lt;a href="http://www.jpaulmorrison.com/fbp/"&gt;book&lt;/a&gt;. I like it, I recommend it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-7937596234572820840?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/7937596234572820840/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=7937596234572820840' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/7937596234572820840'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/7937596234572820840'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2008/06/lack-of-fit.html' title='Lack of Fit'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-4475606826975822591</id><published>2008-05-22T19:34:00.005+02:00</published><updated>2008-05-22T21:45:36.787+02:00</updated><title type='text'>LanguageFear</title><content type='html'>I've just read Martin Fowler's article &lt;a href="http://martinfowler.com/bliki/ParserFear.html"&gt;ParserFear&lt;/a&gt;. So, &lt;span style="font-weight: bold;"&gt;Why Not a Parser&lt;/span&gt; for a DSL?&lt;br /&gt;Martin didn't quite specified why we need a DSL:&lt;br /&gt; - Is it for business people to &lt;a href="http://rspec.info/"&gt;specify&lt;/a&gt; their requirements?&lt;br /&gt; - Is it just '&lt;a href="http://www.infoq.com/articles/internal-dsls-java"&gt;readable&lt;/a&gt;' code, for programmers ?&lt;br /&gt;I assume that in both cases we are trying to solve a customer's problem, by building an easy to maintain.&lt;br /&gt;&lt;br /&gt;Let's say we use XML. &lt;a href="http://debasishg.blogspot.com/2007/05/xml-not-for-human-consumption.html"&gt;Well&lt;/a&gt; &lt;a href="http://blogs.tedneward.com/2005/08/22/When+Do+You+Use+XML+Again.aspx"&gt;that&lt;/a&gt; &lt;a href="http://codebetter.com/blogs/jeremy.miller/archive/2007/06/17/a-train-of-thought-june-17-2007-edition.aspx"&gt;is&lt;/a&gt; a &lt;a href="http://typo.objectmentor.com/articles/2007/05/17/the-hidiocy-of-xml-languages"&gt;bad&lt;/a&gt; idea, and Martin &lt;a href="http://martinfowler.com/bliki/MovingAwayFromXslt.html"&gt;knows&lt;/a&gt; it: &lt;a href="http://dirtsimple.org/2004/12/python-is-not-java.html"&gt;XML is not the answer.  It is not even the question&lt;/a&gt;. And to write XML is a difficult thing to sell, to a business-man.&lt;br /&gt;&lt;br /&gt;Let's say that we go the ANTLR way. Which means from &lt;a href="http://www.robert-tolksdorf.de/vmlanguages.html"&gt;all&lt;/a&gt; &lt;a href="http://dotnetpowered.com/languages.aspx"&gt;the&lt;/a&gt; &lt;a href="http://en.wikipedia.org/wiki/Alphabetical_list_of_programming_languages"&gt;languages&lt;/a&gt; which are out there, none fits our needs, so we have to build our own. Ok, let's say we've build one. But now we need for our users an editor. We might need good error messages, syntax highlight, the possibility to reuse blocks of code from our programming language. Later we will need to extend our language, without hurting the users. And on the other side, the code generated will be difficult to maintain or to build abstractions on it. That's because code generation is just a raw, automatic, copy-paste machine: it doesn't build any higher-order abstractions. And the direction seems to be wrong: instead of helping our customer, we are baby-sitting our language/editor/infrastructure.&lt;br /&gt;&lt;br /&gt;Or we go with &lt;a href="http://martinfowler.com/dslwip/Intro.html"&gt;embedded DSLs&lt;/a&gt;: &lt;a href="http://martinfowler.com/articles/rake.html"&gt;some&lt;/a&gt; &lt;a href="http://gbracha.blogspot.com/2007/01/parser-combinators.html"&gt;languages&lt;/a&gt; &lt;a href="http://www.quanttec.com/fparsec/index.html"&gt;are&lt;/a&gt; &lt;a href="http://ulf.wiger.net/weblog/2008/02/29/simon-peyton-jones-composing-contracts-an-adventure-in-financial-engineering/"&gt;better&lt;/a&gt; &lt;a href="http://ulf.wiger.net/fp_seminar/Options-Ericsson-Feb08.pdf"&gt;then&lt;/a&gt; &lt;a href="http://martinfowler.com/bliki/ExpressionBuilder.html"&gt;others&lt;/a&gt;. &lt;a href="http://groovy.codehaus.org/"&gt;And&lt;/a&gt; &lt;a href="http://jruby.codehaus.org/"&gt;some&lt;/a&gt; &lt;a href="http://www.scala-lang.org/"&gt;languages&lt;/a&gt; can be easily integrated with others. Some have heavier syntax making more difficult to create a clean DSL, some are more &lt;a href="http://www.ruby-lang.org/en/"&gt;lightweight&lt;/a&gt;, making a perfect match for &lt;a href="http://onsmalltalk.com/programming/smalltalk/domain-specific-languages-ruby-a-sign-post-on-the-road-to-smalltalk/"&gt;DSLs&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Or we can go with a &lt;a href="http://en.wikiquote.org/wiki/Lisp_programming_language"&gt;'building material', a 'programmable programming language'&lt;/a&gt;, or &lt;a href="http://www.robert-tolksdorf.de/vmlanguages.html#lispandco"&gt;something &lt;/a&gt;similar.&lt;br /&gt;&lt;br /&gt;Why do people fear of learning of a new language, but they invest uncountable hours in building sand-castles. Even Martin &lt;a href="http://martinfowler.com/bliki/OneLanguage.html"&gt;agrees&lt;/a&gt;: be a &lt;a href="http://www.infoq.com/news/2007/08/multi-lingual-programming"&gt;polyglot&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-4475606826975822591?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/4475606826975822591/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=4475606826975822591' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/4475606826975822591'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/4475606826975822591'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2008/05/languagefear.html' title='LanguageFear'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-4556379632452002578</id><published>2008-05-02T17:30:00.001+02:00</published><updated>2008-05-02T17:35:33.003+02:00</updated><title type='text'>Validation Combinators, a F# prototype</title><content type='html'>Suppose we have the following situation: we have a bag/set of named objects which have to be validated. These objects are primitives, let's say strings, for our sample.&lt;br /&gt;Some strings can be validated as 'standalone' some need to be validate against each other. This validation doesn't belong to the domain for several reasons.&lt;br /&gt;Regrettably, the &lt;a href="http://del.icio.us/andrei.pamula/validation"&gt;existing frameworks&lt;/a&gt; don't suite our needs.&lt;br /&gt;&lt;br /&gt;Trying to decompose the problem, we need:&lt;br /&gt;- a way to get object out of the bag, by name&lt;br /&gt;- a validation method/function which can validate one or more objects&lt;br /&gt;- if  the validation fails, we want to collect a 'failed validation message'&lt;br /&gt;- we want to compose these validations: and, or, not, xor, etc...&lt;br /&gt;&lt;br /&gt;Let's put that in code:&lt;br /&gt;&lt;comment title=" {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Bitstream Vera Sans Mono;}}{\colortbl;??\red255\green255\blue255;\red0\green0\blue0;\red255\green128\blue0;}??\fs18 \cf1\cb2\highlight2 #light\par ??\cf3 open\cf1  System\par ??\cf3 open\cf1  System.Collections.Generic\par ??\cf3 open\cf1  System.Text\par ??\par ??\cf3 type\cf1  get_by_name = String \cf3 -&amp;gt;\cf1  String\par ??\cf3 type\cf1  accumulate_message = String \cf3 -&amp;gt;\cf1  unit\par ??\cf3 type\cf1  validator = get_by_name \cf3 -&amp;gt;\cf1  accumulate_message \cf3 -&amp;gt;\cf1  bool\par ??} " xmlns="http://disruptive-innovations.com/zoo/nvu"&gt;&lt;img src="chrome://editor/content/images/tag-comment.gif" /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Bitstream Vera Sans Mono;}}{\colortbl;??\red255\green255\blue255;\red0\green0\blue0;\red255\green128\blue0;}??\fs18 \cf1\cb2\highlight2 #light\par ??\cf3 open\cf1  System\par ??\cf3 open\cf1  System.Collections.Generic\par ??\cf3 open\cf1  System.Text\par ??\par ??\cf3 type\cf1  get_by_name = String \cf3 -&gt;\cf1  String\par ??\cf3 type\cf1  accumulate_message = String \cf3 -&gt;\cf1  unit\par ??\cf3 type\cf1  validator = get_by_name \cf3 -&gt;\cf1  accumulate_message \cf3 -&gt;\cf1  bool\par ??} --&gt;&lt;/comment&gt; &lt;div    style="background: black none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Courier New;font-size:10pt;color:white;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    1&lt;/span&gt; #light&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    2&lt;/span&gt; &lt;span style="color: rgb(255, 128, 0);"&gt;open&lt;/span&gt; System&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    3&lt;/span&gt; &lt;span style="color: rgb(255, 128, 0);"&gt;open&lt;/span&gt; System.Collections.Generic&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    4&lt;/span&gt; &lt;span style="color: rgb(255, 128, 0);"&gt;open&lt;/span&gt; System.Text&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    5&lt;/span&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    6&lt;/span&gt; &lt;span style="color: rgb(255, 128, 0);"&gt;type&lt;/span&gt; get_by_name = String &lt;span style="color: rgb(255, 128, 0);"&gt;-&gt;&lt;/span&gt; String&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    7&lt;/span&gt; &lt;span style="color: rgb(255, 128, 0);"&gt;type&lt;/span&gt; accumulate_message = String &lt;span style="color: rgb(255, 128, 0);"&gt;-&gt;&lt;/span&gt; unit&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    8&lt;/span&gt; &lt;span style="color: rgb(255, 128, 0);"&gt;type&lt;/span&gt; validator = get_by_name &lt;span style="color: rgb(255, 128, 0);"&gt;-&gt;&lt;/span&gt; accumulate_message &lt;span style="color: rgb(255, 128, 0);"&gt;-&gt;&lt;/span&gt; bool&lt;/p&gt; &lt;/div&gt; We use F# light syntax, and open some .Net namespaces, define the required function types: I really like this kind of  'aliasing': give name to a type, since being based on type inference, is not obtrusive.It is not like a java/c# Interface, where the interface must be implemented. In our case, if we have another function with a signature matching our type, we can use that function as the required type. (we could say is a type-safe &lt;a href="http://c2.com/cgi/wiki?DuckTyping"&gt;duck-typing&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;comment title=" {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Bitstream Vera Sans Mono;}}{\colortbl;??\red255\green128\blue0;\red0\green0\blue0;\red255\green255\blue255;}??\fs18 \cf1\cb2\highlight2 let\cf3  _and_ (x : validator) (y : validator) = (\cf1 fun\cf3  (get_value_from_bag : get_by_name) (accumulate_validation_message : accumulate_message) \cf1 -&amp;gt;\cf3  \par ??       \cf1 let\cf3  ok_x = \cf1 lazy\cf3  x get_value_from_bag accumulate_validation_message\par ??       \cf1 let\cf3  ok_y = \cf1 lazy\cf3  y get_value_from_bag accumulate_validation_message\par ??       Lazy.force ok_x &amp;amp;&amp;amp; Lazy.force ok_y)\par ??        \par ??\cf1 let\cf3  _or_ (x : validator) (y : validator) = (\cf1 fun\cf3  (get_value_from_bag : get_by_name) (accumulate_validation_message : accumulate_message) \cf1 -&amp;gt;\cf3  \par ??       \cf1 let\cf3  ok_x = \cf1 lazy\cf3  x get_value_from_bag accumulate_validation_message\par ??       \cf1 let\cf3  ok_y = \cf1 lazy\cf3  y get_value_from_bag accumulate_validation_message\par ??       Lazy.force ok_x || Lazy.force ok_y)\par ??\par ??\cf1 let\cf3  _not_ (x : validator) = (\cf1 fun\cf3  (get_value_from_bag : get_by_name) (accumulate_validation_message : accumulate_message) \cf1 -&amp;gt;\cf3  \par ??       \cf1 let\cf3  ok_x = x get_value_from_bag accumulate_validation_message\par ??       not ok_x)\par ??\par ??\cf1 let\cf3  _xor_ (x : validator) (y : validator) = ((_not_ x) |&amp;gt; _and_ y ) |&amp;gt; _or_ (y |&amp;gt; _and_ (_not_ x) ) \par ??} " xmlns="http://disruptive-innovations.com/zoo/nvu"&gt;&lt;img src="chrome://editor/content/images/tag-comment.gif" /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Bitstream Vera Sans Mono;}}{\colortbl;??\red255\green128\blue0;\red0\green0\blue0;\red255\green255\blue255;}??\fs18 \cf1\cb2\highlight2 let\cf3  _and_ (x : validator) (y : validator) = (\cf1 fun\cf3  (get_value_from_bag : get_by_name) (accumulate_validation_message : accumulate_message) \cf1 -&gt;\cf3  \par ??       \cf1 let\cf3  ok_x = \cf1 lazy\cf3  x get_value_from_bag accumulate_validation_message\par ??       \cf1 let\cf3  ok_y = \cf1 lazy\cf3  y get_value_from_bag accumulate_validation_message\par ??       Lazy.force ok_x &amp;amp;&amp;amp; Lazy.force ok_y)\par ??        \par ??\cf1 let\cf3  _or_ (x : validator) (y : validator) = (\cf1 fun\cf3  (get_value_from_bag : get_by_name) (accumulate_validation_message : accumulate_message) \cf1 -&gt;\cf3  \par ??       \cf1 let\cf3  ok_x = \cf1 lazy\cf3  x get_value_from_bag accumulate_validation_message\par ??       \cf1 let\cf3  ok_y = \cf1 lazy\cf3  y get_value_from_bag accumulate_validation_message\par ??       Lazy.force ok_x || Lazy.force ok_y)\par ??\par ??\cf1 let\cf3  _not_ (x : validator) = (\cf1 fun\cf3  (get_value_from_bag : get_by_name) (accumulate_validation_message : accumulate_message) \cf1 -&gt;\cf3  \par ??       \cf1 let\cf3  ok_x = x get_value_from_bag accumulate_validation_message\par ??       not ok_x)\par ??\par ??\cf1 let\cf3  _xor_ (x : validator) (y : validator) = ((_not_ x) |&gt; _and_ y ) |&gt; _or_ (y |&gt; _and_ (_not_ x) ) \par ??} --&gt;&lt;/comment&gt; &lt;div    style="background: black none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Courier New;font-size:10pt;color:white;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   10&lt;/span&gt; &lt;span style="color: rgb(255, 128, 0);"&gt;let&lt;/span&gt; _and_ (x : validator) (y : validator) = (&lt;span style="color: rgb(255, 128, 0);"&gt;fun&lt;/span&gt; (get_value_from_bag : get_by_name) (accumulate_validation_message : accumulate_message) &lt;span style="color: rgb(255, 128, 0);"&gt;-&gt;&lt;/span&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   11&lt;/span&gt;        &lt;span style="color: rgb(255, 128, 0);"&gt;let&lt;/span&gt; ok_x = &lt;span style="color: rgb(255, 128, 0);"&gt;lazy&lt;/span&gt; x get_value_from_bag accumulate_validation_message&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   12&lt;/span&gt;        &lt;span style="color: rgb(255, 128, 0);"&gt;let&lt;/span&gt; ok_y = &lt;span style="color: rgb(255, 128, 0);"&gt;lazy&lt;/span&gt; y get_value_from_bag accumulate_validation_message&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   13&lt;/span&gt;        Lazy.force ok_x &amp;amp;&amp;amp; Lazy.force ok_y)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   14&lt;/span&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   15&lt;/span&gt; &lt;span style="color: rgb(255, 128, 0);"&gt;let&lt;/span&gt; _or_ (x : validator) (y : validator) = (&lt;span style="color: rgb(255, 128, 0);"&gt;fun&lt;/span&gt; (get_value_from_bag : get_by_name) (accumulate_validation_message : accumulate_message) &lt;span style="color: rgb(255, 128, 0);"&gt;-&gt;&lt;/span&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   16&lt;/span&gt;        &lt;span style="color: rgb(255, 128, 0);"&gt;let&lt;/span&gt; ok_x = &lt;span style="color: rgb(255, 128, 0);"&gt;lazy&lt;/span&gt; x get_value_from_bag accumulate_validation_message&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   17&lt;/span&gt;        &lt;span style="color: rgb(255, 128, 0);"&gt;let&lt;/span&gt; ok_y = &lt;span style="color: rgb(255, 128, 0);"&gt;lazy&lt;/span&gt; y get_value_from_bag accumulate_validation_message&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   18&lt;/span&gt;        Lazy.force ok_x || Lazy.force ok_y)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   19&lt;/span&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   20&lt;/span&gt; &lt;span style="color: rgb(255, 128, 0);"&gt;let&lt;/span&gt; _not_ (x : validator) = (&lt;span style="color: rgb(255, 128, 0);"&gt;fun&lt;/span&gt; (get_value_from_bag : get_by_name) (accumulate_validation_message : accumulate_message) &lt;span style="color: rgb(255, 128, 0);"&gt;-&gt;&lt;/span&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   21&lt;/span&gt;        &lt;span style="color: rgb(255, 128, 0);"&gt;let&lt;/span&gt; ok_x = x get_value_from_bag accumulate_validation_message&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   22&lt;/span&gt;        not ok_x)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   23&lt;/span&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   24&lt;/span&gt; &lt;span style="color: rgb(255, 128, 0);"&gt;let&lt;/span&gt; _xor_ (x : validator) (y : validator) = ((_not_ x) |&gt; _and_ y ) |&gt; _or_ (y |&gt; _and_ (_not_ x) ) &lt;/p&gt; &lt;/div&gt; Having defined what a validator is, we have defined functions to combined them: and, or, xor. In order to simulate the behavior (a and b -&gt; b is evaluated only if a is false), we cache the result of a validator in&lt;br /&gt;a &lt;a href="http://blogs.msdn.com/jomo_fisher/archive/2007/09/27/adventures-in-f-lazy-like-a-fox.aspx"&gt;lazy&lt;/a&gt; value: the value is computed only once, delayed, on demand. In the xor combinator we have used another DSL-friendly feature: &lt;a href="http://www.c-sharpcorner.com/UploadFile/rmcochran/fsharptypes03212008225543PM/fsharptypes.aspx"&gt;partial-function application&lt;/a&gt;: ie. if  we have a function f(x, y) -&gt; z we could write this as: y |&gt; f  x.&lt;br /&gt;&lt;br /&gt;Ok, let's see how it works. We define a validator:&lt;br /&gt;&lt;comment title=" {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Bitstream Vera Sans Mono;}}{\colortbl;??\red255\green128\blue0;\red0\green0\blue0;\red255\green255\blue255;\red0\green255\blue0;}??\fs18 \cf1\cb2\highlight2 let\cf3  is_starting_with (start : String) (name : String) = (\cf1 fun\cf3  (get_value_from_bag : get_by_name) (accumulate_validation_message : accumulate_message) \cf1 -&amp;gt;\par ??\cf3     \cf1 let\cf3  value = get_value_from_bag name\par ??    \cf1 let\cf3  ok = value.StartsWith(start)\par ??    \cf1 if\cf3  not ok \cf1 then\cf3  \par ??        \cf1 let\cf3  msg = string.Format(\cf4 &amp;quot;\{0\} '\{1\}' doesn't start with \{2\}&amp;quot;\cf3 , name, value, start)\par ??        accumulate_validation_message msg\par ??    ok)} " xmlns="http://disruptive-innovations.com/zoo/nvu"&gt;&lt;img src="chrome://editor/content/images/tag-comment.gif" /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Bitstream Vera Sans Mono;}}{\colortbl;??\red255\green128\blue0;\red0\green0\blue0;\red255\green255\blue255;\red0\green255\blue0;}??\fs18 \cf1\cb2\highlight2 let\cf3  is_starting_with (start : String) (name : String) = (\cf1 fun\cf3  (get_value_from_bag : get_by_name) (accumulate_validation_message : accumulate_message) \cf1 -&gt;\par ??\cf3     \cf1 let\cf3  value = get_value_from_bag name\par ??    \cf1 let\cf3  ok = value.StartsWith(start)\par ??    \cf1 if\cf3  not ok \cf1 then\cf3  \par ??        \cf1 let\cf3  msg = string.Format(\cf4 "\{0\} '\{1\}' doesn't start with \{2\}"\cf3 , name, value, start)\par ??        accumulate_validation_message msg\par ??    ok)} --&gt;&lt;/comment&gt; &lt;div    style="background: black none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Courier New;font-size:10pt;color:white;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   27&lt;/span&gt; &lt;span style="color: rgb(255, 128, 0);"&gt;let&lt;/span&gt; is_starting_with (start : String) (name : String) = (&lt;span style="color: rgb(255, 128, 0);"&gt;fun&lt;/span&gt; (get_value_from_bag : get_by_name) (accumulate_validation_message : accumulate_message) &lt;span style="color: rgb(255, 128, 0);"&gt;-&gt;&lt;/span&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   28&lt;/span&gt;     &lt;span style="color: rgb(255, 128, 0);"&gt;let&lt;/span&gt; value = get_value_from_bag name&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   29&lt;/span&gt;     &lt;span style="color: rgb(255, 128, 0);"&gt;let&lt;/span&gt; ok = value.StartsWith(start)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   30&lt;/span&gt;     &lt;span style="color: rgb(255, 128, 0);"&gt;if&lt;/span&gt; not ok &lt;span style="color: rgb(255, 128, 0);"&gt;then&lt;/span&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   31&lt;/span&gt;         &lt;span style="color: rgb(255, 128, 0);"&gt;let&lt;/span&gt; msg = string.Format(&lt;span style="color:lime;"&gt;"{0} '{1}' doesn't start with {2}"&lt;/span&gt;, name, value, start)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   32&lt;/span&gt;         accumulate_validation_message msg&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   33&lt;/span&gt;     ok)&lt;/p&gt; &lt;/div&gt;&lt;br /&gt;Lets define a map of name -&gt; values, and a message accumulator:&lt;br /&gt;&lt;comment title=" {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Bitstream Vera Sans Mono;}}{\colortbl;??\red255\green128\blue0;\red0\green0\blue0;\red255\green255\blue255;\red0\green255\blue0;}??\fs18 \cf1\cb2\highlight2 let\cf3  map = \cf1 new\cf3  Dictionary&amp;lt;String,String&amp;gt;()\par ??map.Add(\cf4 &amp;quot;customer&amp;quot;\cf3 ,\cf4 &amp;quot;ali&amp;quot;\cf3 )\par ??map.Add(\cf4 &amp;quot;buyer&amp;quot;\cf3 , \cf4 &amp;quot;baba&amp;quot;\cf3 )\par ??map.Add(\cf4 &amp;quot;vendor&amp;quot;\cf3 , \cf4 &amp;quot;nono&amp;quot;\cf3 )\par ??\par ??\cf1 let\cf3  get_value (key : String) : String = map.Item(key)\par ??\par ??\cf1 let\cf3  acc = \cf1 new\cf3  StringBuilder()\par ??\cf1 let\cf3  accumulate (msg: String) : unit = acc.AppendLine(msg) |&amp;gt; ignore} " xmlns="http://disruptive-innovations.com/zoo/nvu"&gt;&lt;img src="chrome://editor/content/images/tag-comment.gif" /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Bitstream Vera Sans Mono;}}{\colortbl;??\red255\green128\blue0;\red0\green0\blue0;\red255\green255\blue255;\red0\green255\blue0;}??\fs18 \cf1\cb2\highlight2 let\cf3  map = \cf1 new\cf3  Dictionary&lt;string,string&gt;()\par ??map.Add(\cf4 "customer"\cf3 ,\cf4 "ali"\cf3 )\par ??map.Add(\cf4 "buyer"\cf3 , \cf4 "baba"\cf3 )\par ??map.Add(\cf4 "vendor"\cf3 , \cf4 "nono"\cf3 )\par ??\par ??\cf1 let\cf3  get_value (key : String) : String = map.Item(key)\par ??\par ??\cf1 let\cf3  acc = \cf1 new\cf3  StringBuilder()\par ??\cf1 let\cf3  accumulate (msg: String) : unit = acc.AppendLine(msg) |&gt; ignore} --&gt;&lt;/comment&gt; &lt;div    style="background: black none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Courier New;font-size:10pt;color:white;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   36&lt;/span&gt; &lt;span style="color: rgb(255, 128, 0);"&gt;let&lt;/span&gt; map = &lt;span style="color: rgb(255, 128, 0);"&gt;new&lt;/span&gt; Dictionary&lt;string,string&gt;()&lt;/string,string&gt;&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   37&lt;/span&gt; map.Add(&lt;span style="color:lime;"&gt;"customer"&lt;/span&gt;,&lt;span style="color:lime;"&gt;"ali"&lt;/span&gt;)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   38&lt;/span&gt; map.Add(&lt;span style="color:lime;"&gt;"buyer"&lt;/span&gt;, &lt;span style="color:lime;"&gt;"baba"&lt;/span&gt;)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   39&lt;/span&gt; map.Add(&lt;span style="color:lime;"&gt;"vendor"&lt;/span&gt;, &lt;span style="color:lime;"&gt;"nono"&lt;/span&gt;)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   40&lt;/span&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   41&lt;/span&gt; &lt;span style="color: rgb(255, 128, 0);"&gt;let&lt;/span&gt; get_value (key : String) : String = map.Item(key)&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   42&lt;/span&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   43&lt;/span&gt; &lt;span style="color: rgb(255, 128, 0);"&gt;let&lt;/span&gt; acc = &lt;span style="color: rgb(255, 128, 0);"&gt;new&lt;/span&gt; StringBuilder()&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   44&lt;/span&gt; &lt;span style="color: rgb(255, 128, 0);"&gt;let&lt;/span&gt; accumulate (msg: String) : unit = acc.AppendLine(msg) |&gt; ignore&lt;/p&gt; &lt;/div&gt;&lt;br /&gt;Lets create a more complex validator:&lt;br /&gt;&lt;comment title=" {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Bitstream Vera Sans Mono;}}{\colortbl;??\red255\green128\blue0;\red0\green0\blue0;\red255\green255\blue255;\red0\green255\blue0;}??\fs18 \cf1\cb2\highlight2 let\cf3  x = (\cf4 &amp;quot;customer&amp;quot;\cf3  |&amp;gt; is_starting_with \cf4 &amp;quot;a&amp;quot;\cf3 ) |&amp;gt; _and_ (\cf4 &amp;quot;buyer&amp;quot;\cf3  |&amp;gt; is_starting_with  \cf4 &amp;quot;b&amp;quot;\cf3 ) |&amp;gt; _and_ (\cf4 &amp;quot;vendor&amp;quot;\cf3  |&amp;gt; is_starting_with \cf4 &amp;quot;v&amp;quot;\cf3 )\par ??} " xmlns="http://disruptive-innovations.com/zoo/nvu"&gt;&lt;img src="chrome://editor/content/images/tag-comment.gif" /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Bitstream Vera Sans Mono;}}{\colortbl;??\red255\green128\blue0;\red0\green0\blue0;\red255\green255\blue255;\red0\green255\blue0;}??\fs18 \cf1\cb2\highlight2 let\cf3  x = (\cf4 "customer"\cf3  |&gt; is_starting_with \cf4 "a"\cf3 ) |&gt; _and_ (\cf4 "buyer"\cf3  |&gt; is_starting_with  \cf4 "b"\cf3 ) |&gt; _and_ (\cf4 "vendor"\cf3  |&gt; is_starting_with \cf4 "v"\cf3 )\par ??} --&gt;&lt;/comment&gt; &lt;div    style="background: black none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Courier New;font-size:10pt;color:white;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   46&lt;/span&gt; &lt;span style="color: rgb(255, 128, 0);"&gt;let&lt;/span&gt; x = (&lt;span style="color:lime;"&gt;"customer"&lt;/span&gt; |&gt; is_starting_with &lt;span style="color:lime;"&gt;"a"&lt;/span&gt;) |&gt; _and_ (&lt;span style="color:lime;"&gt;"buyer"&lt;/span&gt; |&gt; is_starting_with  &lt;span style="color:lime;"&gt;"b"&lt;/span&gt;) |&gt; _and_ (&lt;span style="color:lime;"&gt;"vendor"&lt;/span&gt; |&gt; is_starting_with &lt;span style="color:lime;"&gt;"v"&lt;/span&gt;)&lt;/p&gt; &lt;/div&gt; That's really readable, isn't it?&lt;br /&gt;&lt;br /&gt;And we can evaluate it:&lt;br /&gt;&lt;comment title=" {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Bitstream Vera Sans Mono;}}{\colortbl;??\red255\green255\blue255;\red0\green0\blue0;\red0\green255\blue0;}??\fs18 \cf1\cb2\highlight2 printfn \cf3 &amp;quot;evaluation: %b messages: %s&amp;quot;\cf1  (x get_value accumulate) (acc.ToString())\par ??\par ??System.Console.ReadKey()\par ??} " xmlns="http://disruptive-innovations.com/zoo/nvu"&gt;&lt;img src="chrome://editor/content/images/tag-comment.gif" /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Bitstream Vera Sans Mono;}}{\colortbl;??\red255\green255\blue255;\red0\green0\blue0;\red0\green255\blue0;}??\fs18 \cf1\cb2\highlight2 printfn \cf3 "evaluation: %b messages: %s"\cf1  (x get_value accumulate) (acc.ToString())\par ??\par ??System.Console.ReadKey()\par ??} --&gt;&lt;/comment&gt; &lt;div    style="background: black none repeat scroll 0% 50%; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;font-family:Courier New;font-size:10pt;color:white;"&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   48&lt;/span&gt; printfn &lt;span style="color:lime;"&gt;"evaluation: %b messages: %s"&lt;/span&gt; (x get_value accumulate) (acc.ToString())&lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   49&lt;/span&gt; &lt;/p&gt; &lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   50&lt;/span&gt; System.Console.ReadKey()&lt;/p&gt; &lt;/div&gt;&lt;br /&gt;ps. Look at a better example in a &lt;a href="http://ulf.wiger.net/fp_seminar/Options-Ericsson-Feb08.pdf"&gt;Good&lt;/a&gt; &lt;a href="http://ulf.wiger.net/weblog/2008/02/29/simon-peyton-jones-composing-contracts-an-adventure-in-financial-engineering/"&gt;Video&lt;/a&gt;: "&lt;a href="http://cadrlife.blogspot.com/2008/03/speaker-spotlight-simon-peyton-jones.html"&gt;Composing Contracts: An Adventure in Financial Engineering&lt;/a&gt;".&lt;br /&gt;pps. &lt;a href="http://code.google.com/p/thought-tracker/source/browse/trunk/fsharp/validation_combinators/validation_combinators.fsx"&gt;here&lt;/a&gt; is the code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-4556379632452002578?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/4556379632452002578/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=4556379632452002578' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/4556379632452002578'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/4556379632452002578'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2008/05/validation-combinators-f-prototype.html' title='Validation Combinators, a F# prototype'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-3481044310984333434</id><published>2008-04-18T11:34:00.002+02:00</published><updated>2008-04-18T11:36:55.468+02:00</updated><title type='text'>they've killed it</title><content type='html'>&lt;a href="http://code.google.com/p/thought-tracker/source/browse/trunk/python/update_dilbert_archive.py"&gt;dilbert.py&lt;/a&gt; and &lt;a href="http://code.google.com/p/thought-tracker/source/browse/trunk/fsharp/fdilbert/fdilbert.fsx"&gt;dilbert.fsx&lt;/a&gt;. &lt;a href="http://reddit.com/r/programming/info/6g6mo/comments/"&gt;they&lt;/a&gt;...&lt;br /&gt;:(&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-3481044310984333434?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/3481044310984333434/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=3481044310984333434' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/3481044310984333434'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/3481044310984333434'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2008/04/theyve-killed-it.html' title='they&apos;ve killed it'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-947072623518029986</id><published>2008-04-10T13:02:00.002+02:00</published><updated>2008-04-10T14:19:59.214+02:00</updated><title type='text'>Maybe, me too</title><content type='html'>After my previous &lt;a href="http://thought-tracker.blogspot.com/2008/03/thoughts-on-validation-patterns.html"&gt;post&lt;/a&gt;, I've found another one &lt;a href="http://www.codecommit.com/blog/scala/the-option-pattern"&gt;blogging&lt;/a&gt; about Option as 'explicit null'.&lt;br /&gt;If you think about, Java/C# always had that Option, is only called Iterable[T]/IEnumerable[T]: either you have one element inside or not.&lt;br /&gt;&lt;br /&gt;So I've done another implementation in &lt;a href="http://code.google.com/p/thought-tracker/source/browse/trunk/java/option/org/thought_tracker/"&gt;java&lt;/a&gt;. In comparison with the 'other' implementation:&lt;br /&gt;- instead of the slower 'instanceof' matching, we use a boolean hasValue()&lt;br /&gt;- almost as in &lt;a href="http://research.microsoft.com/fsharp/manual/FSharp.Core/Microsoft.FSharp.Core.Option.html"&gt;F#&lt;/a&gt;, the Option implements the Iterable&lt;t&gt; interface, allowing the filter/map/reduce operations. (in F# those operations are directly in the Option type)&lt;br /&gt;&lt;br /&gt;ps. A lot of people like the '&lt;a href="http://www.google.com/search?q=scala%20option"&gt;scala Option&lt;/a&gt;' or the '&lt;a href="http://www.google.com/search?hl=en&amp;amp;q=F%23+option&amp;amp;btnG=Search"&gt;F# Option&lt;/a&gt;'.&lt;br /&gt;pps. My favorite 'What is a Monad?' explanations are the Brian Beckman - "Don't fear the Monads" &lt;a href="http://del.icio.us/andrei.pamula/monads"&gt;video&lt;/a&gt;, and the Wes Dyer "The Marvels of Monads" &lt;a href="http://blogs.msdn.com/wesdyer/archive/2008/01/11/the-marvels-of-monads.aspx"&gt;blog-entry&lt;/a&gt;. Here the other &lt;a href="http://del.icio.us/andrei.pamula/monads"&gt;links&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-947072623518029986?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/947072623518029986/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=947072623518029986' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/947072623518029986'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/947072623518029986'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2008/04/maybe-me-too.html' title='Maybe, me too'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-2981589436888429221</id><published>2008-03-31T13:37:00.002+02:00</published><updated>2008-03-31T13:44:53.447+02:00</updated><title type='text'>Thoughts on Validation Patterns</title><content type='html'>During my worked at project X, I've looked for &lt;a href="http://del.icio.us/andrei.pamula/validation"&gt;several validation patterns&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;The use case is: you have a view with several fields, you need to validate them all, collect all the error messages and focus on the 1st erroneous file.&lt;br /&gt;&lt;br /&gt;Since the View represents of a view (projection) over the Domain (Model) the right thing to do is to put the validation in the Model.&lt;br /&gt;&lt;br /&gt;The problem arises from the fact the in an ActiveController-PassiveView (aka &lt;a href="http://del.icio.us/andrei.pamula/mvp"&gt;Model-View-Presenter&lt;/a&gt;)&lt;br /&gt;neither the Model nor the View have access to each other:&lt;br /&gt;&lt;br /&gt;PassiveView &amp;lt;-- Presenter --&amp;gt; Model.&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://in.relation.to/Bloggers/BeanValidationSneakPeekPartI"&gt;latest frameworks&lt;/a&gt; use annotations/validators &amp;amp; reflection to map validations ViewField &amp;lt;-&amp;gt;&lt;br /&gt;ModelField. (it gets hairier if you need to validate accross several fields, or &lt;a href="http://www.martinfowler.com/apsupp/spec.pdf"&gt;several objects&lt;/a&gt;).   &lt;br /&gt;&lt;br /&gt;Project X was a .Net project, and .Net 2.0 has a nice feature: implicit type inference for delegates.&lt;br /&gt;Let me explain: if you define an delegate  &lt;span style="font-family:monospace;"&gt; &lt;br /&gt;public delegate R Func&amp;lt;R, A1&amp;gt;(A1 arg1);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;and a method&lt;br /&gt;    &lt;span style="font-family:monospace;"&gt;void DoSomething&amp;lt;R,A1&amp;gt;(Func&amp;lt;R,A1&amp;gt; converter) {&lt;br /&gt;... }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;then you can pass *&lt;span style="font-weight: bold;"&gt;any&lt;/span&gt;* method which matches the signature of  the delegate to the &lt;span style="font-family:monospace;"&gt;&lt;br /&gt;DoSomething(...) &lt;/span&gt;method.&lt;br /&gt;&lt;span style="font-family:monospace;"&gt; &lt;br /&gt;   public R MyConverter&amp;lt;R,A1&amp;gt;(A1 arg);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;   ...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;   DoSomething(MyConverter) // this is valid&lt;/span&gt;&lt;br /&gt;Basically, starting with .Net 2.0, closures/functions are 1st class citizens in C#, like any other 'normal' objects. (&lt;a href="http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg03277.html?"&gt;closures are objects, afterall&lt;/a&gt;), with some remarks:&lt;br /&gt;&lt;br /&gt;- .Net/C# properties are not methods and cannot be used as such&lt;br /&gt;- in java you have to write a *&lt;span style="font-weight: bold;"&gt;lot&lt;/span&gt;* of anonymous classes, making more difficult to see any benefit. (that's also why an &lt;a href="http://code.google.com/p/thought-tracker/source/browse#"&gt;Enumerating &lt;/a&gt;component is not appealing in java, in C# the compiler &lt;a href="http://blogs.msdn.com/ericlippert/archive/2007/01/10/lambda-expressions-vs-anonymous-methods-part-one.aspx"&gt;writes&lt;/a&gt; the &lt;a href="http://blogs.msdn.com/ericlippert/archive/2007/01/11/lambda-expressions-vs-anonymous-methods-part-two.aspx"&gt;anon&lt;/a&gt;. &lt;a href="http://blogs.msdn.com/ericlippert/archive/2007/01/12/lambda-expressions-vs-anonymous-methods-part-three.aspx"&gt;classes &lt;/a&gt;for you)&lt;br /&gt;&lt;br /&gt;Having said that, we can do a 'manual' binding in Presenter:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;ValidationService.bind(PassiveView.GetField(), Model.ValidateField, PassiveView.SetErrorOnField)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;the function signature of bind would be&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;bind&amp;lt;T&amp;gt;(T candidate, Func&amp;lt;bool, T&amp;gt; validate, Action signalError) {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;   if (! validate(field)) signalError();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;We can do some more variations on the thema, where the ValidateField will also give us a message saying what was wrong with the candidate.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Variation within variation: message in several languages, should the model be responsible for that, maybe should provide the id to an message which will be translate...&lt;br /&gt;&lt;br /&gt;One smell is that, after we have validated the field, by the Model, we pass again the value back to&lt;br /&gt;the model in order to update/create some objects/fields.&lt;br /&gt;&lt;br /&gt;Another discussion we had is that a constructor/factory using exceptions for validating arguments is &lt;a href="http://blogs.msdn.com/ricom/archive/2003/12/19/44697.aspx"&gt;expensive&lt;/a&gt; and it fails too fast, since we want to collect all error messages.&lt;br /&gt;&lt;br /&gt;So we could replace that with a 2-step process:&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;  maybeValidArgs = factory.Validate(args);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;  factory.create(maybeValidArgs);&lt;/span&gt;&lt;br /&gt;but this is too 'manual'.&lt;br /&gt;&lt;br /&gt;Some static typing functional languages have a construct to explicitely define a nullable value. In a c#/java would be:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;interface Option&amp;lt;T&amp;gt; {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;   boolean HasValue();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;   T GetValue();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;class Some&amp;lt;T&amp;gt; {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;   boolean HasValue() -&amp;gt; always true;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;   T GetValue() -&amp;gt; always the value;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;class None&amp;lt;T&amp;gt; {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;   boolean HasValue() -&amp;gt; always false;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;   T GetValue() -&amp;gt; always throws an exception;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Note: In java we have type erasure, so for&lt;span style="font-family:monospace;"&gt; None&amp;lt;?&amp;gt; &lt;/span&gt;we can use a Singleton object.&lt;br /&gt;&lt;br /&gt;Now for validation use case we might:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;interface Option&amp;lt;T&amp;gt; {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    boolean HasValue();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    T GetValue();&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    IEnumerable&amp;lt;String&amp;gt; Errors();&lt;/span&gt;// Danger in using Strings !!! String is a 'primitive/sealed' type, which you cannot extend.&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;class Some&amp;lt;T&amp;gt; {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;   boolean HasValue() -&amp;gt; always true;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;   T GetValue() -&amp;gt; always the value; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;   IEnumerable&amp;lt;String&amp;gt; Errors() -&amp;gt; always Empty;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;class None&amp;lt;T&amp;gt; {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;   boolean HasValue() -&amp;gt; always false;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;   T GetValue() -&amp;gt; always throw; &lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;   IEnumerable&amp;lt;String&amp;gt; Errors() -&amp;gt; always the errors;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Basically &lt;span style="font-family:monospace;"&gt;HasValue() &lt;/span&gt;has the same semantic with &lt;span style="font-family:monospace;"&gt;IsEmpty(Errors())&lt;/span&gt;.&lt;br /&gt;We could change the pull - with a push:&lt;br /&gt;instead of &lt;span style="font-family:monospace;"&gt;IEnumerable&amp;lt;String&amp;gt; Errors()&lt;/span&gt; (pull errors)&lt;br /&gt;we push the errors in a handler&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;DoWithErrors(Action&amp;lt;IEnumerable&amp;lt;String&amp;gt;&amp;gt; errorHandler) -&amp;gt; Some will call the the action, None will do not&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;so we could use it like this:&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;&lt;br /&gt;Option&amp;lt;T&amp;gt; maybe =  factory.TryCreate(args);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;  if (maybe.HasValue()) { ... do something with it }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;  else {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;    maybe.doWithErrors(View.DisplayErrors);&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;  } &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It is not difficult to associate an extra validation action for each arg/candidate field.&lt;br /&gt;&lt;br /&gt;We just add optional args to &lt;span style="font-family:monospace;"&gt;TryCreate(args, params IAction[] actions)&lt;/span&gt;  which we'll define as&lt;br /&gt;mapping &lt;span style="font-family:monospace;"&gt;arg1 -&amp;gt; action1, arg2 -&amp;gt; action2&lt;/span&gt;. (if  we have more args then actions, we don't call any action for them)&lt;br /&gt;&lt;br /&gt;eg.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family:monospace;"&gt;Option&amp;lt;Address&amp;gt; maybe = addressFactory.TryCreate(street_candidate, number_candidate, city_name_candidate, view.SignalErrorStreetName, view.SignalErrorValidateNumberCandidate, view.SignalValidateCityName)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;...probably this will evolve to a 'framework', but at least a safe-type one, not string/reflection-based... And probably the annotation/reflection based are more AOP/crosscutting then this will be.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-2981589436888429221?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/2981589436888429221/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=2981589436888429221' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/2981589436888429221'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/2981589436888429221'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2008/03/thoughts-on-validation-patterns.html' title='Thoughts on Validation Patterns'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-7009145804194681044</id><published>2008-03-27T21:26:00.009+01:00</published><updated>2008-06-11T16:39:36.621+02:00</updated><title type='text'>I don't get Spring</title><content type='html'>Like &lt;a href="http://crazybob.org/"&gt;CrazyBob&lt;/a&gt;, of  &lt;a href="http://code.google.com/p/google-guice/"&gt;guice&lt;/a&gt; &lt;a href="http://www.drdobbs.com/blog/portal/archives/2008/03/jolt_award_winn.html"&gt;fame&lt;/a&gt;, I also &lt;a href="http://crazybob.org/2006/01/i-dont-get-spring.html"&gt;don't get&lt;/a&gt; &lt;a href="http://springframework.org/"&gt;Spring&lt;/a&gt;. &lt;a href="http://hammett.castleproject.org/"&gt;Hammet&lt;/a&gt; &lt;a href="http://www.jroller.com/hammett/entry/castle_project_and_spring_net1"&gt;also doesn't get it&lt;/a&gt;.&lt;br /&gt;I mean what is the whole idea of wiring by xml? To decouple the wiring from the model.&lt;br /&gt;But if you put the wiring.xml in the jar, so that it lands in the &lt;a href="http://maven.apache.org/"&gt;maven&lt;/a&gt; &lt;a href="http://www.jfrog.org/sites/artifactory/1.2/"&gt;repository&lt;/a&gt;, to be used by others then it's not really decoupled.&lt;br /&gt;&lt;br /&gt;Suppose I have 2 services, with their corresponding interfaces&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;class Producer implements IProducer { ... }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;class Consumer implements IConsumer {&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;____Consumer(IProducer producer) { ... }&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;    ____...&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;}&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;what do we put in the xml file ? Basically we repeat the code-lines.&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;[bean id="..." class="Producer][/bean]&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;[bean id="..." class="Consumer"]&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;        ____[constructor-arg ref="..." index="0"/]&lt;br /&gt;[/bean]&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;So not only we write again the required dependency, but we do it in xml so that we don't get&lt;br /&gt;the benefit of refactoring (any changes due to renaming are lost).&lt;br /&gt;I've intentionally left the ids unspecified. What should we put in there? The name of the class or the name of the interface?&lt;br /&gt;- If we put the name of the class, then the Consumer-owner must know which class implements the IProducer interface, so a large part of the benefit of using interfaces is lost.&lt;br /&gt;- If we put the name of the interface, in a declarative way, 'I am an IConsumer and I need an IProducer' then we have really duplicated the constructor line and the class declaration line in XML.&lt;br /&gt;&lt;br /&gt;And now what about setter-injection. When I look at a class, I look at the interface it implements and what services it needs (in the constructor) to fulfill that contract. But Spring &lt;a href="http://static.springframework.org/spring/docs/2.5.x/reference/beans.html"&gt;favors&lt;/a&gt; 'Setter Injection'.&lt;br /&gt;&lt;br /&gt;&lt;div class="sidebar"&gt;&lt;p&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;The Spring team generally advocates the usage of setter         injection, since a large number of constructor arguments can get         unwieldy, especially when some properties are optional. The presence         of setter methods also makes objects of that class amenable to being         re-configured (or re-injected) at some later time (for management via         &lt;a href="http://static.springframework.org/spring/docs/2.5.x/reference/jmx.html" title="Chapter 20. JMX"&gt;JMX MBeans&lt;/a&gt; is a particularly compelling use         case).&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;p&gt;Constructor-injection is favored by some purists though (and         with good reason). Supplying all of an object's dependencies means         that that object is never returned to client (calling) code in a less         than totally initialized state. The flip side is that the object         becomes less amenable to re-configuration (or re-injection).&lt;/p&gt;&lt;p&gt;There is no hard and fast rule here. Use whatever type of DI         makes the most sense for a particular class; sometimes, when dealing         with third party classes to which you do not have the source, the         choice will already have been made for you - a legacy class may not         expose any setter methods, and so constructor injection will be the         only type of DI available to you.&lt;/p&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;What does it mean for me, as a maintainer: I have to visually scan the file for the setters, wrap each of the private fields in a getter, and put in the getter a check for != null.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;What about the argument that a class has too many args in constructor? Isn't that a &lt;a href="http://c2.com/cgi/wiki?CodeSmell"&gt;smell&lt;/a&gt; which you should do something about it? (Well actually there are 2 smells: &lt;a href="http://c2.com/cgi/wiki?TooManyParameters"&gt;TwoMany-&lt;/a&gt;&lt;a href="http://c2.com/cgi/wiki?LongParameterList"&gt;Parameters&lt;/a&gt; and &lt;a href="http://c2.com/cgi/wiki?ExpensiveSetUpSmell"&gt;ExpensiveSetUp&lt;/a&gt;)&lt;/p&gt;&lt;p&gt;What about the argument about 'optional arguments'. Isn't that a &lt;a href="http://www.c2.com/cgi/wiki?search=NullObject"&gt;NullObject&lt;/a&gt; pattern?&lt;br /&gt;So what was the Spring-solution?  Autowiring? No, that came later. The Spring-developers said: we need an IDE to manage all that xml. WTF? Instead of getting rid of all that shit, you get a bigger shovel in order to dig deeper?&lt;/p&gt;&lt;p&gt;Now, the world is a little better. Now we have annotations and auto-wiring. But where are these annotations? Probably, declaratively, in a small component, so that other IoC containers could use these annotations for wiring? ... No, they are in the spring-core !!! (the logic is that if you were that smart/stupid to choose spring, then for sure you don't want to change your mind. And if you change your mind, than you should take every file and manually change the annotation and its import).&lt;/p&gt;I really &lt;span style="font-weight: bold;"&gt;don't get&lt;/span&gt; the "&lt;span style="font-style: italic;"&gt;significant benefits for many projects, increasing development productivity and runtime performance while improving test coverage and application quality&lt;/span&gt;".&lt;br /&gt;&lt;br /&gt;ps. I had an argument about 'writing boiler-plate code isn't really that bad, since there are tools/IDEs to help you to write that'. I still strongly disagree: if 80% of the life of a software project is spend in maintenance, that means that we &lt;span style="font-weight: bold;"&gt;read&lt;/span&gt;/bug-fix code &lt;span style="font-weight: bold;"&gt;much more&lt;/span&gt; &lt;span style="font-weight: bold;"&gt;often&lt;/span&gt; then we write it. We must strive to READ LESS USELESS CODE.&lt;br /&gt;&lt;p&gt;pps. &lt;a href="http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html?page=1"&gt;'getter/setter methods are evil'&lt;/a&gt; &lt;/p&gt;&lt;p&gt;ppps. &lt;a href="http://www.bileblog.org/?p=13"&gt;'xml wiring is for girls'&lt;/a&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;ppps. from '&lt;a href="http://dirtsimple.org/2004/12/python-is-not-java.html"&gt;python is not java&lt;/a&gt;' : '&lt;span style="font-style: italic;"&gt;XML is not the answer.  It is not even the question.  To paraphrase &lt;/span&gt;&lt;a style="font-style: italic;" href="http://fishbowl.pastiche.org/2003/08/18/beware_regular_expressions"&gt;Jamie Zawinski on regular expressions&lt;/a&gt;&lt;span style="font-style: italic;"&gt;, "Some people, when confronted with a problem, think "I know, I'll use XML." Now they have two problems."&lt;/span&gt;'&lt;/p&gt;&lt;p&gt;ppps. A more &lt;a href="http://www.web4j.com/Criticisms_Drawbacks_Pitfalls_Spring_Rails_PHP.jsp"&gt;detailed criticism&lt;/a&gt; on Spring.&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-7009145804194681044?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/7009145804194681044/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=7009145804194681044' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/7009145804194681044'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/7009145804194681044'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2008/03/i-dont-get-spring.html' title='I don&apos;t get Spring'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-7581731877073742961</id><published>2008-03-26T16:55:00.002+01:00</published><updated>2008-03-26T17:19:44.835+01:00</updated><title type='text'>blog marketing</title><content type='html'>I've received a &lt;a href="http://sw-guide.de/webdienste-blogging/wie-starte-ich-ein-blog-und-mache-dieses-bekannt/#4"&gt;link&lt;/a&gt; about how-to make my blog more popular. (thanks Andi ;)&lt;br /&gt;There are good tips in there but I'm not sure I want to go aggressive in 'active marketing':&lt;br /&gt;&lt;ul&gt;&lt;li&gt;it is more important that  my readers  say 'hey this is a cool guy with a good blog' that I say 'I am the greatest'&lt;/li&gt;&lt;li&gt;more time on marketing means less time on something else (this is probably weak, since I'm not a very effective blogger, but I compensate that by being an avid reader)&lt;/li&gt;&lt;li&gt;I would prioritize 'more, better content' higher than 'more aggressive marketing'. (I should really write more)&lt;/li&gt;&lt;li&gt;On the other side is really important to reach people and bring them something. An architect said that the real important think to do is to spread knowledge. Know imagine: instead of sitting here and doing a bad copy of &lt;a href="http://www.bileblog.org/"&gt;bile-blog&lt;/a&gt;, without being even &lt;a href="http://www.bileblog.org/?p=334"&gt;funny&lt;/a&gt;, winning about how java is crap, C# is crap, (btw. C# is better than java, sic!),  I could/should put some interesting stuff in here and move at least a hand of developers to a better programming world. So if I can reach/teach at least 3 people, and every 'student' will reach at most 3 people and so on, maybe w&lt;a href="javascript:void(0)" tabindex="10" onclick="return false;"&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;e can reach the critical mass, and move something.... (...or maybe this was just a naive rant)&lt;/li&gt;&lt;/ul&gt;Making it short: help me make the blog more popular: &lt;a href="http://reddit.com/r/programming/"&gt;reddit&lt;/a&gt;, &lt;a href="http://technorati.com/"&gt;technorati&lt;/a&gt;, &lt;a href="http://www.dzone.com/links/index.html"&gt;dzone&lt;/a&gt; me.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-7581731877073742961?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/7581731877073742961/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=7581731877073742961' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/7581731877073742961'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/7581731877073742961'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2008/03/blog-marketing.html' title='blog marketing'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-4143003300259803077</id><published>2008-03-18T16:51:00.002+01:00</published><updated>2008-03-18T17:09:42.651+01:00</updated><title type='text'>Memoization in Java</title><content type='html'>&lt;a href="http://www.onjava.com/pub/a/onjava/2003/08/20/memoization.html?page=1"&gt;OnJava&lt;/a&gt; in 2003, Tim White gave us generic way to build a memoize in java.&lt;br /&gt;IMHO, Mr. White is trying to use big guns (dynamic proxy, reflection) on a small problem: function composition.&lt;br /&gt;&lt;br /&gt;If we use/declare an interface:&lt;br /&gt;public interface IFunc1&lt;a1,r&gt; {&lt;br /&gt;____R apply(A1 arg1);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;then we can do implement Memoize1 (on 1 argument) as: (I use the Scala notation for generics [,] since blogger cuts out the xml devil quotes \&lt;,\&gt;)&lt;br /&gt;&lt;br /&gt;public class Memoize1[A1, R] implements IFunc1[A1, R] {&lt;br /&gt;____private final IFunc1[A1, R] func;&lt;br /&gt;____private final Map[A1, R] cache;&lt;br /&gt;&lt;br /&gt;____public Memoize1(IFunc1[A1, R] func) {&lt;br /&gt;________this(func,new HashMap[A1, R]());&lt;br /&gt;____}&lt;br /&gt;&lt;br /&gt;____public Memoize1(IFunc1&lt;a1,&gt; func, Map[A1,R] cache) {&lt;br /&gt;________this.func = func;&lt;br /&gt;________this.cache = cache;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public R apply(A1 arg1) {&lt;br /&gt;____R result = cache.get(arg1);&lt;br /&gt;____if (result == null) {&lt;br /&gt;________result = func.apply(arg1);&lt;br /&gt;____cache.put(arg1, result);&lt;br /&gt;____}&lt;br /&gt;____return result;&lt;br /&gt;____}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;That's it. Generic. Composable. Reusable. No &lt;a href="http://www.youtube.com/watch?v=FuK74pquyH4"&gt;schnick-schnack&lt;/a&gt;.&lt;br /&gt;Similar memoizer could be provide for IFunc2, IFunc3...&lt;br /&gt;Notice that the Memoize has the same signature as the function it encapsulates.&lt;br /&gt;&lt;br /&gt;ps. &lt;a href="http://blogs.msdn.com/dsyme/archive/2007/05/31/a-sample-of-the-memoization-pattern-in-f.aspx"&gt;here&lt;/a&gt; is the F# version.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-4143003300259803077?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/4143003300259803077/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=4143003300259803077' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/4143003300259803077'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/4143003300259803077'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2008/03/memoization-in-java.html' title='Memoization in Java'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-3482542151787121293</id><published>2008-02-26T11:20:00.002+01:00</published><updated>2008-02-26T11:25:38.228+01:00</updated><title type='text'>sooo '98</title><content type='html'>from &lt;a href="http://maven.apache.org/plugins/maven-surefire-plugin/examples/inclusion-exclusion.html"&gt;maven-surefire-plugin&lt;/a&gt;:&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;p&gt;By default, the surefire plugin will automatically include all test classes with the following wildcard patterns:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;i&gt;"**/Test*.java"&lt;/i&gt; - includes all of its subdirectory and all java filenames that start with "Test".&lt;/li&gt;&lt;li&gt;&lt;i&gt;"**/*Test.java"&lt;/i&gt; - includes all of its subdirectory and all java filenames that end with "Test".&lt;/li&gt;&lt;li&gt;&lt;i&gt;"**/*TestCase.java"&lt;/i&gt; - includes all of its subdirectory and all java filenames that end with "TestCase".&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;If the test classes does not go with the naming convention, then configure surefire plugin and specify the tests you want to include.&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;ahh, &lt;a href="http://www.eg.bucknell.edu/%7Ecs475/F2000-S2001/hyde/JUnit/README.html"&gt;those&lt;/a&gt; romantic days.&lt;br /&gt;Apparently annotations and specifications are too 'exotic'.&lt;br /&gt;&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/14511296-3482542151787121293?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/3482542151787121293/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=3482542151787121293' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/3482542151787121293'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/3482542151787121293'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2008/02/sooo-98.html' title='sooo &apos;98'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-930698587447357402</id><published>2008-02-21T21:42:00.001+01:00</published><updated>2008-02-21T21:46:28.381+01:00</updated><title type='text'>Code Snippets Project</title><content type='html'>I've published the C#, F# and python snippets in the &lt;a href="http://code.google.com/p/thought-tracker/source/browse/trunk"&gt;code-snippets project&lt;/a&gt;.&lt;br /&gt;Check-out get_dilbert_strips in &lt;a href="http://code.google.com/p/thought-tracker/source/browse/trunk/python/get_dilbert_strips.py"&gt;py&lt;/a&gt; and &lt;a href="http://code.google.com/p/thought-tracker/source/browse/trunk/fsharp/fdilbert.fsx"&gt;F#&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-930698587447357402?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/930698587447357402/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=930698587447357402' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/930698587447357402'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/930698587447357402'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2008/02/code-snippets-project.html' title='Code Snippets Project'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-3635562142612587893</id><published>2008-02-19T15:30:00.004+01:00</published><updated>2008-02-19T16:33:28.538+01:00</updated><title type='text'>Type Inference in F# &amp; Scala (pointers)</title><content type='html'>Here are some just some links about &lt;a href="http://en.wikipedia.org/wiki/Type_inference"&gt;type inference&lt;/a&gt; in F# and Scala.&lt;br /&gt;&lt;br /&gt;1st. from &lt;a href="http://research.microsoft.com/fsharp/manual/quicktour.aspx#QuickTourTypeInference"&gt;F# manual&lt;/a&gt;:&lt;br /&gt;&lt;blockquote&gt;&lt;p&gt;F# is statically typed, but frequently code will not contain many    type annotations.  This is because F# uses &lt;b&gt;type inference&lt;/b&gt; to automatically determine    the types of expressions.  Type inference checks that types   "match up" in obvious ways, i.e., that a function definition is consistent and that the definition of a       function is sufficiently general to match all the ways in which it is used.    Type inference is a global process over an entire source file, or, in the case of    entries to F# Interactive, over the scope of a single entry delimited by '&lt;tt&gt;;;&lt;/tt&gt;'    terminators.&lt;/p&gt;     &lt;p&gt;Type inference automatically &lt;b&gt;generalizes&lt;/b&gt; code to be as generic as possible.    To see the types inferred for the top-level definitions in your program     use the &lt;tt&gt;-i&lt;/tt&gt; compiler switch, or hover your mouse over definitions in a supported interactive    environment such as Visual Studio.&lt;/p&gt;        &lt;p&gt;Calls and accesses to .NET and F# methods and properties (collectively known as &lt;b&gt;members&lt;/b&gt;)   involve a form of type-directed    &lt;a href="http://research.microsoft.com/fsharp/manual/lexyacc.aspx#OverloadResolution"&gt;overload resolution&lt;/a&gt;, resolved based on    left-to-right, outside-to-in analysis of a file, i.e., type information subsequent to    the use of an overloaded member is not taken into account for its resolution.&lt;/p&gt;       &lt;p&gt;In addition, some operators such as &lt;tt&gt;+&lt;/tt&gt;  are &lt;b&gt;overloaded&lt;/b&gt;.  Operator overloading    is resolved over the same scope as type inference, typically an entire file.  Where operator overloading    is not resolved the overloading typically defaults to work over 32-bit integers.&lt;/p&gt;            &lt;p&gt; Code that uses .NET library calls (and in particular libraries which make    heavy use of the dot-notation) will need to be annotated with extra type annotations in order    to assist the type inference process.  The F# type checker will indicate when further    type annotations are needed.&lt;/p&gt;&lt;/blockquote&gt;&lt;br /&gt;(for F# I can also recommend the &lt;a href="http://www.amazon.com/Foundations-F-Experts-Voice-Net/dp/1590597575"&gt;F#&lt;/a&gt; &lt;a href="http://www.amazon.com/Expert-F-Experts-Voice-Net/dp/1590598504"&gt;books&lt;/a&gt;)&lt;br /&gt;&lt;p&gt;2nd &lt;a href="http://www.scala-lang.org/"&gt;Scala&lt;/a&gt;: besides the &lt;a href="http://www.scala-lang.org/intro/inference.html"&gt;type-inference&lt;/a&gt;, has a very nice generic system, with focus on components &amp;amp; scalability, see  '&lt;a href="http://lambda-the-ultimate.org/node/2579"&gt;Generics of a  Higher Kind&lt;/a&gt;', the &lt;a href="http://video.google.com/videoplay?docid=553859542692229789"&gt;google-talk&lt;/a&gt; (slides &lt;a href="http://lampwww.epfl.ch/%7Eodersky/talks/google06.pdf"&gt;here&lt;/a&gt;), and the other &lt;a href="http://www.scala-lang.org/docu/files/"&gt;scala-docs&lt;/a&gt; (for the studious).   (you can feel a &lt;a href="http://blip.tv/file/325646"&gt;flavor &lt;/a&gt;of &lt;a href="http://conferences.oreillynet.com/pub/w/58/presentations.html"&gt;Haskell&lt;/a&gt; in scala (traits, implicits) , bringing the high-order-function &lt;a href="http://lispy.wordpress.com/2007/10/01/boilerplate-code-says-a-lot-about-a-language/"&gt;elegance&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-3635562142612587893?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/3635562142612587893/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=3635562142612587893' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/3635562142612587893'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/3635562142612587893'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2008/02/type-inference-in-f-scala-pointers.html' title='Type Inference in F# &amp; Scala (pointers)'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-7186342882773688991</id><published>2008-01-23T10:13:00.000+01:00</published><updated>2008-01-23T18:50:17.653+01:00</updated><title type='text'>What's the probability of at least two persons among 20 to have the same birthday?</title><content type='html'>&lt;style type="text/css"&gt;&lt;br /&gt;.comment { color: #999999; font-style: italic; }&lt;br /&gt;.pre { color: #000099; }&lt;br /&gt;.string { color: #009900; }&lt;br /&gt;.char { color: #009900; }&lt;br /&gt;.float { color: #996600; }&lt;br /&gt;.int { color: #999900; }&lt;br /&gt;.bool { color: #000000; font-weight: bold; }&lt;br /&gt;.type { color: #FF6633; }&lt;br /&gt;.flow { color: #FF0000; }&lt;br /&gt;.keyword { color: #990000; }&lt;br /&gt;.operator { color: #663300; font-weight: bold; }&lt;br /&gt;&lt;/style&gt;&lt;br /&gt;&lt;br /&gt;I'm an anti-virus engineer. Recently, we've detected a mobile phone worm that spreads by attaching itself to MMSs that it sends to various phone numbers. Our contact at the mobile phone operator harvested about 1000 MMSs. Some MMSs were sent to the same phone numbers.&lt;br /&gt;&lt;br /&gt;The question was: does the worm generate the phone numbers randomly or are the phone numbers hard-coded in its code?&lt;br /&gt;&lt;br /&gt;A related question is: IF the numbers are randomly generated, which is the probability to have several identical numbers among a set of 1000 numbers?&lt;br /&gt;&lt;br /&gt;The variable part in the 11-digit phone numbers consists of 5 digits. We assume that the phone numbers are equally probable.&lt;br /&gt;&lt;br /&gt;There are 10^5 equally probable possible phone numbers. Let us consider each phone number as a letter of alphabet that contains 10^5 letters. There are (10^5)^1000 distinct 1000-letter strings that we can write in this alphabet. (To convince yourself, think that the alphabet is our normal 10-digit decimal system and we want to build a 3-letter string. How many distinct strings can we build? 1000. 000, 001, ..., 009, 010, 011, ..., 019, 020, ..., 999.)&lt;br /&gt;&lt;br /&gt;How many strings do we have such that each string contains only distinct letters? In order to answer, think how to build such a string. You pick the first letter from the 10^5 available. Then you pick the second from the 10^5-1 available, etc. If you remember your combinatorics classes, then you'll recognize the "variations". How many variations of 1000 elements from a set of 10^5 are there? (10^5) * (10^5 - 1) * ... * (10^5 - 999).&lt;br /&gt;&lt;br /&gt;To summarize, we have an alphabet of 10^5 letters, they are equally probable. We have (10^5)^1000 possible 1000-letter strings. These strings are also equally probable. We have (10^5) * (10^5 - 1) * ... * (10^5 - 999) equally probable strings such that each string contains only distinct letters.&lt;br /&gt;&lt;br /&gt;Thus, the probability to pick a randomly build a 1000-letter string that contains only distinct letters (i.e. the probability that all phone numbers among the 1000 harvested phone numbers be different) is&lt;br /&gt;&lt;br /&gt;(10^5 / 10^5) * ((10^5 - 1) / 10^5) * ((10^5 - 2) / 10^5) * ... * ((10^5 - 999) / 10^5) = 0.0066594036&lt;br /&gt;&lt;br /&gt;The probability that at least two numbers are identical among the 1000 numbers is 1 minus the probability computed above, i.e. 0.9933405964.&lt;br /&gt;&lt;br /&gt;As I was not very sure of my reasoning, I wrote a small simulation:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class="pre"&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;#include &amp;lt;stdlib.h&amp;gt;&lt;br /&gt;&lt;br /&gt;#include &amp;lt;strings.h&amp;gt;&lt;br /&gt;#include &amp;lt;unistd.h&amp;gt;&lt;br /&gt;#include &amp;lt;time.h&amp;gt;&lt;br /&gt;#include &amp;lt;errno.h&amp;gt;&lt;br /&gt;#include &amp;lt;signal.h&amp;gt;&lt;br /&gt;&lt;br /&gt;#define DFLT_N 100000&lt;br /&gt;#define DFLT_K 1000&lt;br /&gt;#define DFLT_MAX_ITER 1000000&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="keyword"&gt;&lt;br /&gt;static&lt;/span&gt;&lt;span class="type"&gt; unsigned int&lt;/span&gt; max_iter&lt;span class="operator"&gt;,&lt;/span&gt; iter&lt;span class="operator"&gt;,&lt;/span&gt; equals&lt;span class="operator"&gt;,&lt;/span&gt; N&lt;span class="operator"&gt;,&lt;/span&gt; K&lt;span class="operator"&gt;;&lt;/span&gt;&lt;span class="keyword"&gt;&lt;br /&gt;&lt;br /&gt;static&lt;/span&gt;&lt;span class="type"&gt; unsigned int&lt;/span&gt;&lt;span class="operator"&gt; *&lt;/span&gt;a&lt;span class="operator"&gt;;&lt;/span&gt;&lt;span class="keyword"&gt;&lt;br /&gt;&lt;br /&gt;static&lt;/span&gt;&lt;span class="type"&gt; double&lt;/span&gt;&lt;br /&gt;uniform_distrib&lt;span class="operator"&gt;(&lt;/span&gt;&lt;span class="type"&gt;double&lt;/span&gt; a&lt;span class="operator"&gt;,&lt;/span&gt;&lt;span class="type"&gt; double&lt;/span&gt; b&lt;span class="operator"&gt;) {&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;&lt;br /&gt;  return&lt;/span&gt; a&lt;span class="operator"&gt; + (&lt;/span&gt;b&lt;span class="operator"&gt; -&lt;/span&gt; a&lt;span class="operator"&gt;) * ((&lt;/span&gt;&lt;span class="type"&gt;double&lt;/span&gt;&lt;span class="operator"&gt;)&lt;/span&gt;random&lt;span class="operator"&gt;() / (&lt;/span&gt;&lt;span class="type"&gt;double&lt;/span&gt;&lt;span class="operator"&gt;)&lt;/span&gt;RAND_MAX&lt;span class="operator"&gt;);&lt;br /&gt;}&lt;/span&gt;&lt;span class="keyword"&gt;&lt;br /&gt;&lt;br /&gt;static&lt;/span&gt;&lt;span class="type"&gt; void&lt;/span&gt;&lt;br /&gt;onUSR1&lt;span class="operator"&gt;(&lt;/span&gt;&lt;span class="type"&gt;int&lt;/span&gt; dummy&lt;span class="operator"&gt;) {&lt;/span&gt;&lt;br /&gt;  printf&lt;span class="operator"&gt;(&lt;/span&gt;&lt;span class="string"&gt;"%f\n"&lt;/span&gt;&lt;span class="operator"&gt;, (&lt;/span&gt;&lt;span class="type"&gt;double&lt;/span&gt;&lt;span class="operator"&gt;)&lt;/span&gt;equals&lt;span class="operator"&gt; /&lt;/span&gt; iter&lt;span class="operator"&gt;);&lt;br /&gt;}&lt;/span&gt;&lt;span class="keyword"&gt;&lt;br /&gt;&lt;br /&gt;static&lt;/span&gt;&lt;span class="type"&gt; void&lt;/span&gt;&lt;br /&gt;parse_cmd_line&lt;span class="operator"&gt;(&lt;/span&gt;&lt;span class="type"&gt;int&lt;/span&gt; argc&lt;span class="operator"&gt;,&lt;/span&gt;&lt;span class="type"&gt; char&lt;/span&gt;&lt;span class="operator"&gt; *&lt;/span&gt;argv&lt;span class="operator"&gt;[]) {&lt;/span&gt;&lt;span class="type"&gt;&lt;br /&gt;&lt;br /&gt;  int&lt;/span&gt; c&lt;span class="operator"&gt;;&lt;/span&gt;&lt;span class="type"&gt;&lt;br /&gt;  char&lt;/span&gt;&lt;span class="operator"&gt; *&lt;/span&gt;endp&lt;span class="operator"&gt;;&lt;/span&gt;&lt;span class="keyword"&gt;&lt;br /&gt;  extern&lt;/span&gt;&lt;span class="type"&gt; char&lt;/span&gt;&lt;span class="operator"&gt; *&lt;/span&gt;optarg&lt;span class="operator"&gt;;&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;&lt;br /&gt;  while&lt;/span&gt;&lt;span class="operator"&gt; ((&lt;/span&gt;c&lt;span class="operator"&gt; =&lt;/span&gt; getopt&lt;span class="operator"&gt;(&lt;/span&gt;argc&lt;span class="operator"&gt;,&lt;/span&gt; argv&lt;span class="operator"&gt;,&lt;/span&gt;&lt;span class="string"&gt; "hN:K:i:"&lt;/span&gt;&lt;span class="operator"&gt;)) !=&lt;/span&gt; EOF&lt;span class="operator"&gt;)&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;&lt;br /&gt;    switch&lt;/span&gt;&lt;span class="operator"&gt; (&lt;/span&gt;c&lt;span class="operator"&gt;) {&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;    case&lt;/span&gt;&lt;span class="char"&gt; '?'&lt;/span&gt;&lt;span class="operator"&gt;:&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;      /* error */&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;      break&lt;/span&gt;&lt;span class="operator"&gt;;&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;&lt;br /&gt;    case&lt;/span&gt;&lt;span class="char"&gt; 'h'&lt;/span&gt;&lt;span class="operator"&gt;:&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;      /* help message */&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;      break&lt;/span&gt;&lt;span class="operator"&gt;;&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;    case&lt;/span&gt;&lt;span class="char"&gt; 'N'&lt;/span&gt;&lt;span class="operator"&gt;:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      errno&lt;span class="operator"&gt; =&lt;/span&gt;&lt;span class="int"&gt; 0&lt;/span&gt;&lt;span class="operator"&gt;;&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;      if&lt;/span&gt;&lt;span class="operator"&gt; (&lt;/span&gt;optarg&lt;span class="operator"&gt; ==&lt;/span&gt; NULL&lt;span class="operator"&gt;) {&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;br /&gt; /* error */&lt;/span&gt;&lt;span class="operator"&gt;&lt;br /&gt;      }&lt;/span&gt;&lt;br /&gt;      N&lt;span class="operator"&gt; = (&lt;/span&gt;&lt;span class="type"&gt;unsigned int&lt;/span&gt;&lt;span class="operator"&gt;)&lt;/span&gt;strtoul&lt;span class="operator"&gt;(&lt;/span&gt;optarg&lt;span class="operator"&gt;, &amp;amp;&lt;/span&gt;endp&lt;span class="operator"&gt;,&lt;/span&gt;&lt;span class="int"&gt; 0&lt;/span&gt;&lt;span class="operator"&gt;);&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;&lt;br /&gt;      if&lt;/span&gt;&lt;span class="operator"&gt; (&lt;/span&gt;errno&lt;span class="operator"&gt; !=&lt;/span&gt;&lt;span class="int"&gt; 0&lt;/span&gt;&lt;span class="operator"&gt; || *&lt;/span&gt;endp&lt;span class="operator"&gt; !=&lt;/span&gt;&lt;span class="char"&gt; '\0'&lt;/span&gt;&lt;span class="operator"&gt;) {&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;br /&gt; /* error */&lt;/span&gt;&lt;span class="operator"&gt;&lt;br /&gt;      }&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;      break&lt;/span&gt;&lt;span class="operator"&gt;;&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;    case&lt;/span&gt;&lt;span class="char"&gt; 'K'&lt;/span&gt;&lt;span class="operator"&gt;:&lt;/span&gt;&lt;br /&gt;      errno&lt;span class="operator"&gt; =&lt;/span&gt;&lt;span class="int"&gt; 0&lt;/span&gt;&lt;span class="operator"&gt;;&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;&lt;br /&gt;      if&lt;/span&gt;&lt;span class="operator"&gt; (&lt;/span&gt;optarg&lt;span class="operator"&gt; ==&lt;/span&gt; NULL&lt;span class="operator"&gt;) {&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt; /* error */&lt;/span&gt;&lt;span class="operator"&gt;&lt;br /&gt;      }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      K&lt;span class="operator"&gt; = (&lt;/span&gt;&lt;span class="type"&gt;unsigned int&lt;/span&gt;&lt;span class="operator"&gt;)&lt;/span&gt;strtoul&lt;span class="operator"&gt;(&lt;/span&gt;optarg&lt;span class="operator"&gt;, &amp;amp;&lt;/span&gt;endp&lt;span class="operator"&gt;,&lt;/span&gt;&lt;span class="int"&gt; 0&lt;/span&gt;&lt;span class="operator"&gt;);&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;      if&lt;/span&gt;&lt;span class="operator"&gt; (&lt;/span&gt;errno&lt;span class="operator"&gt; !=&lt;/span&gt;&lt;span class="int"&gt; 0&lt;/span&gt;&lt;span class="operator"&gt; || *&lt;/span&gt;endp&lt;span class="operator"&gt; !=&lt;/span&gt;&lt;span class="char"&gt; '\0'&lt;/span&gt;&lt;span class="operator"&gt;) {&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;br /&gt; /* error */&lt;/span&gt;&lt;span class="operator"&gt;&lt;br /&gt;      }&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;      break&lt;/span&gt;&lt;span class="operator"&gt;;&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;    case&lt;/span&gt;&lt;span class="char"&gt; 'i'&lt;/span&gt;&lt;span class="operator"&gt;:&lt;/span&gt;&lt;br /&gt;      errno&lt;span class="operator"&gt; =&lt;/span&gt;&lt;span class="int"&gt; 0&lt;/span&gt;&lt;span class="operator"&gt;;&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;&lt;br /&gt;      if&lt;/span&gt;&lt;span class="operator"&gt; (&lt;/span&gt;optarg&lt;span class="operator"&gt; ==&lt;/span&gt; NULL&lt;span class="operator"&gt;) {&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt; /* error */&lt;/span&gt;&lt;span class="operator"&gt;&lt;br /&gt;      }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      max_iter&lt;span class="operator"&gt; = (&lt;/span&gt;&lt;span class="type"&gt;unsigned int&lt;/span&gt;&lt;span class="operator"&gt;)&lt;/span&gt;strtoul&lt;span class="operator"&gt;(&lt;/span&gt;optarg&lt;span class="operator"&gt;, &amp;amp;&lt;/span&gt;endp&lt;span class="operator"&gt;,&lt;/span&gt;&lt;span class="int"&gt; 0&lt;/span&gt;&lt;span class="operator"&gt;);&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;      if&lt;/span&gt;&lt;span class="operator"&gt; (&lt;/span&gt;errno&lt;span class="operator"&gt; !=&lt;/span&gt;&lt;span class="int"&gt; 0&lt;/span&gt;&lt;span class="operator"&gt; || *&lt;/span&gt;endp&lt;span class="operator"&gt; !=&lt;/span&gt;&lt;span class="char"&gt; '\0'&lt;/span&gt;&lt;span class="operator"&gt;) {&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;br /&gt; /* error */&lt;/span&gt;&lt;span class="operator"&gt;&lt;br /&gt;      }&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;      break&lt;/span&gt;&lt;span class="operator"&gt;;&lt;br /&gt;    }&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;  if&lt;/span&gt;&lt;span class="operator"&gt; (&lt;/span&gt;N&lt;span class="operator"&gt; ==&lt;/span&gt;&lt;span class="int"&gt; 0&lt;/span&gt;&lt;span class="operator"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    N&lt;span class="operator"&gt; =&lt;/span&gt; DFLT_N&lt;span class="operator"&gt;;&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;  if&lt;/span&gt;&lt;span class="operator"&gt; (&lt;/span&gt;K&lt;span class="operator"&gt; ==&lt;/span&gt;&lt;span class="int"&gt; 0&lt;/span&gt;&lt;span class="operator"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    K&lt;span class="operator"&gt; =&lt;/span&gt; DFLT_K&lt;span class="operator"&gt;;&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;  if&lt;/span&gt;&lt;span class="operator"&gt; (&lt;/span&gt;max_iter&lt;span class="operator"&gt; ==&lt;/span&gt;&lt;span class="int"&gt; 0&lt;/span&gt;&lt;span class="operator"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    max_iter&lt;span class="operator"&gt; =&lt;/span&gt; DFLT_MAX_ITER&lt;span class="operator"&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;span class="type"&gt;&lt;br /&gt;&lt;br /&gt;int&lt;/span&gt;&lt;span class="keyword"&gt;&lt;br /&gt;main&lt;/span&gt;&lt;span class="operator"&gt;(&lt;/span&gt;&lt;span class="type"&gt;int&lt;/span&gt; argc&lt;span class="operator"&gt;,&lt;/span&gt;&lt;span class="type"&gt; char&lt;/span&gt;&lt;span class="operator"&gt; *&lt;/span&gt;argv&lt;span class="operator"&gt;[]) {&lt;/span&gt;&lt;span class="type"&gt;&lt;br /&gt;&lt;br /&gt;  unsigned int&lt;/span&gt; i&lt;span class="operator"&gt;,&lt;/span&gt; picked&lt;span class="operator"&gt;;&lt;/span&gt;&lt;span class="keyword"&gt;&lt;br /&gt;  struct&lt;/span&gt; sigaction act&lt;span class="operator"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  parse_cmd_line&lt;span class="operator"&gt;(&lt;/span&gt;argc&lt;span class="operator"&gt;,&lt;/span&gt; argv&lt;span class="operator"&gt;);&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  srandom&lt;span class="operator"&gt;(&lt;/span&gt;time&lt;span class="operator"&gt;(&lt;/span&gt;NULL&lt;span class="operator"&gt;));&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;&lt;br /&gt;  if&lt;/span&gt;&lt;span class="operator"&gt; ((&lt;/span&gt;a&lt;span class="operator"&gt; =&lt;/span&gt; malloc&lt;span class="operator"&gt;(&lt;/span&gt;N&lt;span class="operator"&gt; *&lt;/span&gt;&lt;span class="keyword"&gt; sizeof&lt;/span&gt;&lt;span class="operator"&gt;(&lt;/span&gt;&lt;span class="type"&gt;unsigned int&lt;/span&gt;&lt;span class="operator"&gt;))) ==&lt;/span&gt; NULL&lt;span class="operator"&gt;) {&lt;/span&gt;&lt;span class="comment"&gt;&lt;br /&gt;&lt;br /&gt;    /* error */&lt;/span&gt;&lt;span class="operator"&gt;&lt;br /&gt;  }&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  act&lt;span class="operator"&gt;.&lt;/span&gt;sa_handler&lt;span class="operator"&gt; =&lt;/span&gt; onUSR1&lt;span class="operator"&gt;;&lt;/span&gt;&lt;br /&gt;  act&lt;span class="operator"&gt;.&lt;/span&gt;sa_flags&lt;span class="operator"&gt; =&lt;/span&gt; 0&lt;span class="operator"&gt;;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;  sigemptyset&lt;span class="operator"&gt;(&amp;amp;&lt;/span&gt;act&lt;span class="operator"&gt;.&lt;/span&gt;sa_mask&lt;span class="operator"&gt;);&lt;/span&gt;&lt;br /&gt;  sigaction&lt;span class="operator"&gt;(&lt;/span&gt;SIGUSR1&lt;span class="operator"&gt;, &amp;amp;&lt;/span&gt;act&lt;span class="operator"&gt;,&lt;/span&gt; NULL&lt;span class="operator"&gt;);&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;&lt;br /&gt;  for&lt;/span&gt;&lt;span class="operator"&gt; (&lt;/span&gt;iter&lt;span class="operator"&gt; =&lt;/span&gt;&lt;span class="int"&gt; 0&lt;/span&gt;&lt;span class="operator"&gt;;&lt;/span&gt; iter&lt;span class="operator"&gt; &amp;lt;&lt;/span&gt; max_iter&lt;span class="operator"&gt;; ++&lt;/span&gt;iter&lt;span class="operator"&gt;) {&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;    bzero&lt;span class="operator"&gt;(&lt;/span&gt;a&lt;span class="operator"&gt;,&lt;/span&gt; N&lt;span class="operator"&gt; *&lt;/span&gt;&lt;span class="keyword"&gt; sizeof&lt;/span&gt;&lt;span class="operator"&gt;(&lt;/span&gt;&lt;span class="type"&gt;unsigned int&lt;/span&gt;&lt;span class="operator"&gt;));&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;    for&lt;/span&gt;&lt;span class="operator"&gt; (&lt;/span&gt;i&lt;span class="operator"&gt; =&lt;/span&gt;&lt;span class="int"&gt; 0&lt;/span&gt;&lt;span class="operator"&gt;;&lt;/span&gt; i&lt;span class="operator"&gt; &amp;lt;&lt;/span&gt; K&lt;span class="operator"&gt;; ++&lt;/span&gt;i&lt;span class="operator"&gt;) {&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;      picked&lt;span class="operator"&gt; = (&lt;/span&gt;&lt;span class="type"&gt;unsigned int&lt;/span&gt;&lt;span class="operator"&gt;)&lt;/span&gt;uniform_distrib&lt;span class="operator"&gt;(&lt;/span&gt;&lt;span class="float"&gt;0.0&lt;/span&gt;&lt;span class="operator"&gt;, (&lt;/span&gt;&lt;span class="type"&gt;double&lt;/span&gt;&lt;span class="operator"&gt;)&lt;/span&gt;N&lt;span class="operator"&gt;);&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;      if&lt;/span&gt;&lt;span class="operator"&gt; (&lt;/span&gt;a&lt;span class="operator"&gt;[&lt;/span&gt;picked&lt;span class="operator"&gt;] ==&lt;/span&gt;&lt;span class="int"&gt; 1&lt;/span&gt;&lt;span class="operator"&gt;) {&lt;br /&gt; ++&lt;/span&gt;equals&lt;span class="operator"&gt;;&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;&lt;br /&gt; break&lt;/span&gt;&lt;span class="operator"&gt;;&lt;br /&gt;      }&lt;/span&gt;&lt;br /&gt;      a&lt;span class="operator"&gt;[&lt;/span&gt;picked&lt;span class="operator"&gt;] =&lt;/span&gt;&lt;span class="int"&gt; 1&lt;/span&gt;&lt;span class="operator"&gt;;&lt;br /&gt;    }&lt;br /&gt;  }&lt;/span&gt;&lt;br /&gt;    &lt;br /&gt;  onUSR1&lt;span class="operator"&gt;(&lt;/span&gt;SIGUSR1&lt;span class="operator"&gt;);&lt;/span&gt;&lt;span class="flow"&gt;&lt;br /&gt;&lt;br /&gt;  return&lt;/span&gt;&lt;span class="int"&gt; 0&lt;/span&gt;&lt;span class="operator"&gt;;&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;It can be used to answer the question in the title. The simulation says 0.411308. The "theory" says 0.4114383836.&lt;br /&gt;&lt;br /&gt;If we were to be pedantic, the fact that we make some observations coherent with the predictions of a model does not imply that the model is indeed true, especially when we can easily imagine other models that make the same predictions. Thus, we called three distinct phone numbers out of the 1000 harvested. Two of them were not allocated. But this second method looks like the ultimate solution to &lt;a href="http://parris.josh.com.au/humour/grabbag/BuildingHeight.shtml"&gt;measuring the height of a building with a barometer&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-7186342882773688991?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/7186342882773688991/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=7186342882773688991' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/7186342882773688991'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/7186342882773688991'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2008/01/whats-probability-of-at-least-two.html' title='What&apos;s the probability of at least two persons among 20 to have the same birthday?'/><author><name>srn</name><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-8515522832040336011</id><published>2007-08-31T18:56:00.000+02:00</published><updated>2007-08-31T19:36:12.955+02:00</updated><title type='text'>F# Algorithm Sample</title><content type='html'>But here is a "short description" of a problem:&lt;br /&gt;Both the computer and the user have a row of units, each unit has a value. The rows are aligned face to face (like in a 2xn chess table). Each unit fights the unit in front of it. The unit with the biggest value wins. If 2 units have the same value, the computer wins. If the user knows how the computer will position its units in the row, how can the user position his units in order to minimize his loses. Write a program which computes this win/loss score. (some test data is provided).&lt;br /&gt;&lt;br /&gt;And here is my sample:&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:Courier New;font-size:8pt;color:black;"&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    1&lt;/span&gt; &lt;span style="color:blue;"&gt;let&lt;/span&gt; &lt;span style="color:blue;"&gt;rec&lt;/span&gt; without_max ascending_sorted_list = &lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    2&lt;/span&gt;     &lt;span style="color:blue;"&gt;match&lt;/span&gt; ascending_sorted_list &lt;span style="color:blue;"&gt;with&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    3&lt;/span&gt;         | [] &lt;span style="color:blue;"&gt;-&amp;gt;&lt;/span&gt; []&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    4&lt;/span&gt;         | x::[] &lt;span style="color:blue;"&gt;-&amp;gt;&lt;/span&gt; []&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    5&lt;/span&gt;         | x::y::xs &lt;span style="color:blue;"&gt;-&amp;gt;&lt;/span&gt; x::without_max(y::xs) &lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    6&lt;/span&gt; &lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    7&lt;/span&gt; &lt;span style="color:blue;"&gt;let&lt;/span&gt; &lt;span style="color:blue;"&gt;rec&lt;/span&gt; acc (me:list&amp;lt;int&amp;gt;, computer:list&amp;lt;int&amp;gt;, saved:int) =&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    8&lt;/span&gt;     &lt;span style="color:blue;"&gt;match&lt;/span&gt; me, computer &lt;span style="color:blue;"&gt;with&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    9&lt;/span&gt;     | x::xs, y::ys &lt;span style="color:blue;"&gt;-&amp;gt;&lt;/span&gt; &lt;span style="color:blue;"&gt;if&lt;/span&gt; x &amp;lt;= y &lt;span style="color:blue;"&gt;then&lt;/span&gt; acc(xs, without_max(computer), saved)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   10&lt;/span&gt;                       &lt;span style="color:blue;"&gt;else&lt;/span&gt; acc(xs, ys, saved+x)&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   11&lt;/span&gt;     | [], [] &lt;span style="color:blue;"&gt;-&amp;gt;&lt;/span&gt; saved&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   12&lt;/span&gt;     | _ &lt;span style="color:blue;"&gt;-&amp;gt;&lt;/span&gt; failwith &lt;span style="color:maroon;"&gt;"unequal arrays"&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   13&lt;/span&gt; &lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   14&lt;/span&gt; &lt;span style="color:blue;"&gt;let&lt;/span&gt; save_creatures (me:list&amp;lt;int&amp;gt;) (computer:list&amp;lt;int&amp;gt;) =&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   15&lt;/span&gt;     &lt;span style="color:blue;"&gt;let&lt;/span&gt; ascending_sort = List.sort(&lt;span style="color:blue;"&gt;fun&lt;/span&gt; (x:int) (y:int) &lt;span style="color:blue;"&gt;-&amp;gt;&lt;/span&gt; x.CompareTo y) &lt;span style="color:blue;"&gt;in&lt;/span&gt; &lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   16&lt;/span&gt;     acc(ascending_sort(me), ascending_sort(computer), 0) &lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   17&lt;/span&gt; &lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   18&lt;/span&gt; &lt;span style="color:blue;"&gt;let&lt;/span&gt; _ = &lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   19&lt;/span&gt;     &lt;span style="color:blue;"&gt;let&lt;/span&gt; a = save_creatures [5;15;100;1;5] [5;15;100;1;5] &lt;span style="color:blue;"&gt;in&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   20&lt;/span&gt;     &lt;span style="color:blue;"&gt;let&lt;/span&gt; b = save_creatures [15;15;15;15;15] [15;15;15;15;15] &lt;span style="color:blue;"&gt;in&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   21&lt;/span&gt;     &lt;span style="color:blue;"&gt;let&lt;/span&gt; c = save_creatures [1;3;5;7;9;11;13;15;17;19] [2;4;6;8;10;12;14;16;18;20] &lt;span style="color:blue;"&gt;in&lt;/span&gt; &lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   22&lt;/span&gt;     &lt;span style="color:blue;"&gt;let&lt;/span&gt; d = save_creatures [2;3;4;5;6;7;8;9;10;11] [10;9;8;7;6;5;4;3;2;1] &lt;span style="color:blue;"&gt;in&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   23&lt;/span&gt;     print_int a; print_int b; print_int c; print_int d&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;I had fun ;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-8515522832040336011?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/8515522832040336011/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=8515522832040336011' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/8515522832040336011'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/8515522832040336011'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2007/08/f-topcoder-sample.html' title='F# Algorithm Sample'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-578742009824016020</id><published>2007-08-08T17:45:00.000+02:00</published><updated>2007-08-08T18:06:22.531+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><title type='text'>Injection Doctor</title><content type='html'>We use in project X a slightly wrapped PicoContainer. The implementation of  several service are registered in the container explicitely. Sometimes people forget to register it, and unfortunately the container fails with an "UnsatisfiedConstructor" error. The error appears only at run-time (we don't have test-coverage for container configuration), and it's misleading: if we need a class A which needs B,&lt;br /&gt;and we forgot to register B, we get the error on class A (which is, per se, OK).&lt;br /&gt;&lt;br /&gt;The solution (proposed) is to instantiate recursively all the services, and to build for each (failed) instantiation a histogram: the more points we get for a service, the "more" needed it is, the probability to&lt;br /&gt;have there the "injection-problem" will be bigger. For the previous example A will get 1 point and B 2 points.&lt;br /&gt;&lt;br /&gt;And here is the source:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Bitstream Vera Sans Mono;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs18     \cf2 public\cf0  \cf2 class\cf0  \cf10 Memoize\cf0 &lt;r,&gt; \{\par ??        \cf2 private\cf0  \cf2 readonly\cf0  \cf10 Func\cf0 &lt;r,&gt; _func;\par ??\par ??        \cf2 public\cf0  Memoize(\cf10 Func\cf0 &lt;r,&gt; func) \{\par ??            _func = func;\par ??        \}\par ??\par ??        \cf2 private\cf0  \cf10 IDictionary\cf0 &lt;t,&gt; _cache = \cf2 new\cf0  \cf10 Dictionary\cf0 &lt;t,&gt;();\par ??\par ??        \cf2 public\cf0  R Call(T value) \{\par ??            R result;\par ??            \cf2 if\cf0  (_cache.ContainsKey(value)) \{\par ??                result = _cache[value];\par ??            \} \cf2 else\cf0  \{\par ??                result = _func(value);\par ??                _cache[value] = result;\par ??            \}\par ??            \cf2 return\cf0  result;\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:9pt;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; &lt;span style="color:teal;"&gt;Memoize&lt;/span&gt;&lt;r,&gt; {&lt;/r,&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;readonly&lt;/span&gt; &lt;span style="color:teal;"&gt;Func&lt;/span&gt;&lt;r,&gt; _func;&lt;/r,&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; Memoize(&lt;span style="color:teal;"&gt;Func&lt;/span&gt;&lt;r,&gt; func) {&lt;/r,&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            _func = func;&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; &lt;span style="color:teal;"&gt;IDictionary&lt;/span&gt;&lt;t,&gt; _cache = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;Dictionary&lt;/span&gt;&lt;t,&gt;();&lt;/t,&gt;&lt;/t,&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; R Call(T value) {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            R result;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;if&lt;/span&gt; (_cache.ContainsKey(value)) {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;                result = _cache[value];&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            } &lt;span style="color:blue;"&gt;else&lt;/span&gt; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;                result = _func(value);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;                _cache[value] = result;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;return&lt;/span&gt; result;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;    }&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Bitstream Vera Sans Mono;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs18     \cf2 class\cf0  \cf10 InjectionExplorer\cf0  \{\par ??        \cf2 private\cf0  \cf10 Func\cf0 &lt;\cf10 IEnumerable\cf0 &lt;\cf10 Type\cf0&gt;, \cf10 Type\cf0&gt; _greediest_ctor_params;\par ??\par ??        \cf2 public\cf0  InjectionExplorer() \{\par ??            _greediest_ctor_params = \cf2 new\cf0  \cf10 Memoize\cf0 &lt;\cf10 IEnumerable\cf0 &lt;\cf10 Type\cf0&gt;, \cf10 Type\cf0&gt;(GreediestConstructorParametersWorker).Call;\par ??        \}\par ??\par ??        \cf2 public\cf0  \cf10 IEnumerable\cf0 &lt;\cf10 Type\cf0&gt; RequiredTypes(\cf10 Type\cf0  t) \{\par ??            \cf2 return\cf0  _greediest_ctor_params(t);\par ??        \}\par ??\par ??        \cf2 private\cf0  \cf10 ConstructorInfo\cf0  Greediest(\cf10 Type\cf0  t) \{\par ??            \cf10 ConstructorInfo\cf0  greediest = \cf2 null\cf0 ;\par ??            \cf2 int\cf0  greediest_param_length = -1;\par ??            \cf2 foreach\cf0  (\cf10 ConstructorInfo\cf0  ctor \cf2 in\cf0  t.GetConstructors()) \{\par ??                \cf2 if\cf0  (ctor.GetParameters().Length&gt; greediest_param_length) \{\par ??                    greediest = ctor;\par ??                    greediest_param_length = ctor.GetParameters().Length;\par ??                \}\par ??            \}\par ??\par ??            \cf2 if\cf0  (greediest == \cf2 null\cf0 ) \{ \cf2 throw\cf0  \cf2 new\cf0  \cf10 Exception\cf0 (\cf13 "No ctor was found"\cf0 ); \}\par ??            \cf2 return\cf0  greediest;\par ??        \}\par ??\par ??        \cf2 private\cf0  \cf10 IEnumerable\cf0 &lt;\cf10 Type\cf0&gt; GreediestConstructorParametersWorker(\cf10 Type\cf0  t) \{\par ??            \cf10 ConstructorInfo\cf0  ctor = Greediest(t);\par ??            \cf2 return\cf0  \cf10 Enumerables\cf0 .Do.Map&lt;\cf10 Type\cf0 , \cf10 ParameterInfo\cf0&gt;(ctor.GetParameters(), \cf2 delegate\cf0 (\cf10 ParameterInfo\cf0  info) \{ \cf2 return\cf0  info.ParameterType; \});\par ??        \}\par ??    \}\par ??\par ??    \cf2 class\cf0  \cf10 InjectionDoctor\cf0  \{\par ??        \cf2 private\cf0  \cf2 readonly\cf0  \cf10 IEnumerable\cf0 &lt;\cf10 Type\cf0&gt; _types;\par ??        \cf2 private\cf0  \cf2 readonly\cf0  \cf10 Func\cf0 &lt;\cf2 object\cf0 , \cf10 Type\cf0&gt; _instantiate;\par ??        \cf2 private\cf0  \cf2 readonly\cf0  \cf10 InjectionExplorer\cf0  _explorer;\par ??        \cf2 private\cf0  \cf2 readonly\cf0  \cf10 IDictionary\cf0 &lt;\cf10 Type\cf0 , \cf2 int\cf0&gt; _failed_instantiations;\par ??\par ??        \cf2 public\cf0  InjectionDoctor(\cf10 IEnumerable\cf0 &lt;\cf10 Type\cf0&gt; types, \cf10 Func\cf0 &lt;\cf2 object\cf0 , \cf10 Type\cf0&gt; instantiate) \{\par ??            _types = types;\par ??            _instantiate = instantiate;\par ??            _explorer = \cf2 new\cf0  \cf10 InjectionExplorer\cf0 ();\par ??            _failed_instantiations = \cf2 new\cf0  \cf10 Dictionary\cf0 &lt;\cf10 Type\cf0 , \cf2 int\cf0&gt;();\par ??        \}\par ??\par ??\par ??        \cf2 public\cf0  \cf2 void\cf0  Examine() \{\par ??            \cf10 Enumerables\cf0 .Do.ForEach(_types, TryInstantiate);\par ??        \}\par ??\par ??        \cf2 public\cf0  \cf2 void\cf0  PrettyPrint() \{\par ??            \cf2 string\cf0  print_format = \cf13 "\{0\} -&gt; \{1\}"\cf0 ;\par ??\par ??            \cf10 Console\cf0 .WriteLine(print_format, \cf13 "Type"\cf0 , \cf13 "Failed Instatiation Count"\cf0 );\par ??            \cf2 foreach\cf0  (\cf10 KeyValuePair\cf0 &lt;\cf10 Type\cf0 , \cf2 int\cf0&gt; failed_instantiation \cf2 in\cf0  SortFailedInstatiationsByFailedCount()) \{\par ??                \cf10 Console\cf0 .WriteLine(print_format, failed_instantiation.Key, failed_instantiation.Value);\par ??            \}\par ??        \}\par ??\par ??        \cf2 private\cf0  \cf10 IEnumerable\cf0 &lt;\cf10 KeyValuePair\cf0 &lt;\cf10 Type\cf0 ,\cf2 int\cf0&gt;&gt; SortFailedInstatiationsByFailedCount() \{\par ??            \cf10 List\cf0 &lt;\cf10 KeyValuePair\cf0 &lt;\cf10 Type\cf0 , \cf2 int\cf0&gt;&gt; pairs = \cf2 new\cf0  \cf10 List\cf0 &lt;\cf10 KeyValuePair\cf0 &lt;\cf10 Type\cf0 , \cf2 int\cf0&gt;&gt;();\par ??            \cf2 foreach\cf0  (\cf10 KeyValuePair\cf0 &lt;\cf10 Type\cf0 , \cf2 int\cf0&gt; failed_instantiation \cf2 in\cf0  _failed_instantiations) \{\par ??                pairs.Add(failed_instantiation);\par ??            \}\par ??\par ??            pairs.Sort(\cf2 delegate\cf0 (\cf10 KeyValuePair\cf0 &lt;\cf10 Type\cf0 , \cf2 int\cf0&gt; x, \cf10 KeyValuePair\cf0 &lt;\cf10 Type\cf0 , \cf2 int\cf0&gt; y) \{ \cf2 return\cf0  y.Value.CompareTo(x.Value); \});\par ??            \cf2 return\cf0  pairs;\par ??        \}\par ??\par ??        \cf2 private\cf0  \cf10 Type\cf0  Instantiable(\cf10 Type\cf0  candidate) \{\par ??            \cf2 if\cf0  (candidate.IsArray) \{\par ??                \cf2 return\cf0  Instantiable(candidate.GetElementType());\par ??            \}\par ??            \cf2 return\cf0  candidate;\par ??        \}\par ??        \cf2 private\cf0  \cf2 void\cf0  TryInstantiate(\cf10 Type\cf0  candidate) \{\par ??            \cf10 Type\cf0  instantiable = Instantiable(candidate);\par ??\par ??            \cf2 if\cf0  (HasFailedInstatiations(instantiable)) \{\par ??                CountFailedInstantiation(instantiable);\par ??                \cf2 return\cf0 ;\par ??            \}\par ??\par ??            \cf2 try\cf0  \{\par ??                _instantiate(instantiable);    \par ??            \} \cf2 catch\cf0  (\cf10 Exception\cf0 ) \{\par ??                CountFailedInstantiation(instantiable);\par ??                TryInstatiateRequiredTypes(instantiable);\par ??            \}\par ??        \}\par ??\par ??        \cf2 private\cf0  \cf2 void\cf0  TryInstatiateRequiredTypes(\cf10 Type\cf0  candidate) \{\par ??            \cf10 Enumerables\cf0 .Do.ForEach(_explorer.RequiredTypes(candidate), TryInstantiate);\par ??        \}\par ??\par ??        \cf2 private\cf0  \cf2 bool\cf0  HasFailedInstatiations(\cf10 Type\cf0  candidate) \{\par ??            \cf2 return\cf0  _failed_instantiations.ContainsKey(candidate);\par ??        \}\par ??\par ??        \cf2 private\cf0  \cf2 void\cf0  CountFailedInstantiation(\cf10 Type\cf0  candidate) \{\par ??            \cf2 if\cf0  (! HasFailedInstatiations(candidate)) \{ _failed_instantiations[candidate] = 0; \}\par ??            _failed_instantiations[candidate] += 1;\par ??        \}\par ??\par ??        \cf2 public\cf0  \cf2 int\cf0  FailedInstatiations&lt;t&gt;() \{\par ??            \cf2 if\cf0  (! HasFailedInstatiations(\cf2 typeof\cf0 (T))) \{ \cf2 return\cf0  0; \}\par ??            \cf2 return\cf0  _failed_instantiations[\cf2 typeof\cf0  (T)];\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:9pt;color:black;"&gt;&lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;class&lt;/span&gt; &lt;span style="color:teal;"&gt;InjectionExplorer&lt;/span&gt; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;private&lt;/span&gt; &lt;span style="color:teal;"&gt;Func&lt;/span&gt;&lt;&lt;span style="color:teal;"&gt;IEnumerable&lt;/span&gt;&lt;&lt;span style="color:teal;"&gt;Type&lt;/span&gt;&gt;, &lt;span style="color:teal;"&gt;Type&lt;/span&gt;&gt; _greediest_ctor_params;&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; InjectionExplorer() {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            _greediest_ctor_params = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;Memoize&lt;/span&gt;&lt;&lt;span style="color:teal;"&gt;IEnumerable&lt;/span&gt;&lt;&lt;span style="color:teal;"&gt;Type&lt;/span&gt;&gt;, &lt;span style="color:teal;"&gt;Type&lt;/span&gt;&gt;(GreediestConstructorParametersWorker).Call;&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;public&lt;/span&gt; &lt;span style="color:teal;"&gt;IEnumerable&lt;/span&gt;&lt;&lt;span style="color:teal;"&gt;Type&lt;/span&gt;&gt; RequiredTypes(&lt;span style="color:teal;"&gt;Type&lt;/span&gt; t) {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;return&lt;/span&gt; _greediest_ctor_params(t);&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; &lt;span style="color:teal;"&gt;ConstructorInfo&lt;/span&gt; Greediest(&lt;span style="color:teal;"&gt;Type&lt;/span&gt; t) {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:teal;"&gt;ConstructorInfo&lt;/span&gt; greediest = &lt;span style="color:blue;"&gt;null&lt;/span&gt;;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;int&lt;/span&gt; greediest_param_length = -1;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;foreach&lt;/span&gt; (&lt;span style="color:teal;"&gt;ConstructorInfo&lt;/span&gt; ctor &lt;span style="color:blue;"&gt;in&lt;/span&gt; t.GetConstructors()) {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;                &lt;span style="color:blue;"&gt;if&lt;/span&gt; (ctor.GetParameters().Length &gt; greediest_param_length) {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;                    greediest = ctor;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;                    greediest_param_length = ctor.GetParameters().Length;&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;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;if&lt;/span&gt; (greediest == &lt;span style="color:blue;"&gt;null&lt;/span&gt;) { &lt;span style="color:blue;"&gt;throw&lt;/span&gt; &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;Exception&lt;/span&gt;(&lt;span style="color:maroon;"&gt;"No ctor was found"&lt;/span&gt;); }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;return&lt;/span&gt; greediest;&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; &lt;span style="color:teal;"&gt;IEnumerable&lt;/span&gt;&lt;&lt;span style="color:teal;"&gt;Type&lt;/span&gt;&gt; GreediestConstructorParametersWorker(&lt;span style="color:teal;"&gt;Type&lt;/span&gt; t) {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:teal;"&gt;ConstructorInfo&lt;/span&gt; ctor = Greediest(t);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;return&lt;/span&gt; &lt;span style="color:teal;"&gt;Enumerables&lt;/span&gt;.Do.Map&lt;&lt;span style="color:teal;"&gt;Type&lt;/span&gt;, &lt;span style="color:teal;"&gt;ParameterInfo&lt;/span&gt;&gt;(ctor.GetParameters(), &lt;span style="color:blue;"&gt;delegate&lt;/span&gt;(&lt;span style="color:teal;"&gt;ParameterInfo&lt;/span&gt; info) { &lt;span style="color:blue;"&gt;return&lt;/span&gt; info.ParameterType; });&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;/p&gt;&lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;class&lt;/span&gt; &lt;span style="color:teal;"&gt;InjectionDoctor&lt;/span&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;readonly&lt;/span&gt; &lt;span style="color:teal;"&gt;IEnumerable&lt;/span&gt;&lt;&lt;span style="color:teal;"&gt;Type&lt;/span&gt;&gt; _types;&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;readonly&lt;/span&gt; &lt;span style="color:teal;"&gt;Func&lt;/span&gt;&lt;&lt;span style="color:blue;"&gt;object&lt;/span&gt;, &lt;span style="color:teal;"&gt;Type&lt;/span&gt;&gt; _instantiate;&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;readonly&lt;/span&gt; &lt;span style="color:teal;"&gt;InjectionExplorer&lt;/span&gt; _explorer;&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;readonly&lt;/span&gt; &lt;span style="color:teal;"&gt;IDictionary&lt;/span&gt;&lt;&lt;span style="color:teal;"&gt;Type&lt;/span&gt;, &lt;span style="color:blue;"&gt;int&lt;/span&gt;&gt; _failed_instantiations;&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; InjectionDoctor(&lt;span style="color:teal;"&gt;IEnumerable&lt;/span&gt;&lt;&lt;span style="color:teal;"&gt;Type&lt;/span&gt;&gt; types, &lt;span style="color:teal;"&gt;Func&lt;/span&gt;&lt;&lt;span style="color:blue;"&gt;object&lt;/span&gt;, &lt;span style="color:teal;"&gt;Type&lt;/span&gt;&gt; instantiate) {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            _types = types;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            _instantiate = instantiate;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            _explorer = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;InjectionExplorer&lt;/span&gt;();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            _failed_instantiations = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;Dictionary&lt;/span&gt;&lt;&lt;span style="color:teal;"&gt;Type&lt;/span&gt;, &lt;span style="color:blue;"&gt;int&lt;/span&gt;&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;/p&gt;&lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;void&lt;/span&gt; Examine() {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:teal;"&gt;Enumerables&lt;/span&gt;.Do.ForEach(_types, TryInstantiate);&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;public&lt;/span&gt; &lt;span style="color:blue;"&gt;void&lt;/span&gt; PrettyPrint() {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;string&lt;/span&gt; print_format = &lt;span style="color:maroon;"&gt;"{0} -&gt; {1}"&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:teal;"&gt;Console&lt;/span&gt;.WriteLine(print_format, &lt;span style="color:maroon;"&gt;"Type"&lt;/span&gt;, &lt;span style="color:maroon;"&gt;"Failed Instatiation Count"&lt;/span&gt;);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;foreach&lt;/span&gt; (&lt;span style="color:teal;"&gt;KeyValuePair&lt;/span&gt;&lt;&lt;span style="color:teal;"&gt;Type&lt;/span&gt;, &lt;span style="color:blue;"&gt;int&lt;/span&gt;&gt; failed_instantiation &lt;span style="color:blue;"&gt;in&lt;/span&gt; SortFailedInstatiationsByFailedCount()) {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;                &lt;span style="color:teal;"&gt;Console&lt;/span&gt;.WriteLine(print_format, failed_instantiation.Key, failed_instantiation.Value);&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;/p&gt;&lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;private&lt;/span&gt; &lt;span style="color:teal;"&gt;IEnumerable&lt;/span&gt;&lt;&lt;span style="color:teal;"&gt;KeyValuePair&lt;/span&gt;&lt;&lt;span style="color:teal;"&gt;Type&lt;/span&gt;,&lt;span style="color:blue;"&gt;int&lt;/span&gt;&gt;&gt; SortFailedInstatiationsByFailedCount() {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:teal;"&gt;List&lt;/span&gt;&lt;&lt;span style="color:teal;"&gt;KeyValuePair&lt;/span&gt;&lt;&lt;span style="color:teal;"&gt;Type&lt;/span&gt;, &lt;span style="color:blue;"&gt;int&lt;/span&gt;&gt;&gt; pairs = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;List&lt;/span&gt;&lt;&lt;span style="color:teal;"&gt;KeyValuePair&lt;/span&gt;&lt;&lt;span style="color:teal;"&gt;Type&lt;/span&gt;, &lt;span style="color:blue;"&gt;int&lt;/span&gt;&gt;&gt;();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;foreach&lt;/span&gt; (&lt;span style="color:teal;"&gt;KeyValuePair&lt;/span&gt;&lt;&lt;span style="color:teal;"&gt;Type&lt;/span&gt;, &lt;span style="color:blue;"&gt;int&lt;/span&gt;&gt; failed_instantiation &lt;span style="color:blue;"&gt;in&lt;/span&gt; _failed_instantiations) {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;                pairs.Add(failed_instantiation);&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;            pairs.Sort(&lt;span style="color:blue;"&gt;delegate&lt;/span&gt;(&lt;span style="color:teal;"&gt;KeyValuePair&lt;/span&gt;&lt;&lt;span style="color:teal;"&gt;Type&lt;/span&gt;, &lt;span style="color:blue;"&gt;int&lt;/span&gt;&gt; x, &lt;span style="color:teal;"&gt;KeyValuePair&lt;/span&gt;&lt;&lt;span style="color:teal;"&gt;Type&lt;/span&gt;, &lt;span style="color:blue;"&gt;int&lt;/span&gt;&gt; y) { &lt;span style="color:blue;"&gt;return&lt;/span&gt; y.Value.CompareTo(x.Value); });&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;return&lt;/span&gt; pairs;&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; &lt;span style="color:teal;"&gt;Type&lt;/span&gt; Instantiable(&lt;span style="color:teal;"&gt;Type&lt;/span&gt; candidate) {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;if&lt;/span&gt; (candidate.IsArray) {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;                &lt;span style="color:blue;"&gt;return&lt;/span&gt; Instantiable(candidate.GetElementType());&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;return&lt;/span&gt; candidate;&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;void&lt;/span&gt; TryInstantiate(&lt;span style="color:teal;"&gt;Type&lt;/span&gt; candidate) {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:teal;"&gt;Type&lt;/span&gt; instantiable = Instantiable(candidate);&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; (HasFailedInstatiations(instantiable)) {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;                CountFailedInstantiation(instantiable);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;                &lt;span style="color:blue;"&gt;return&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;try&lt;/span&gt; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;                _instantiate(instantiable);    &lt;/p&gt;&lt;p style="margin: 0px;"&gt;            } &lt;span style="color:blue;"&gt;catch&lt;/span&gt; (&lt;span style="color:teal;"&gt;Exception&lt;/span&gt;) {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;                CountFailedInstantiation(instantiable);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;                TryInstatiateRequiredTypes(instantiable);&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;/p&gt;&lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;private&lt;/span&gt; &lt;span style="color:blue;"&gt;void&lt;/span&gt; TryInstatiateRequiredTypes(&lt;span style="color:teal;"&gt;Type&lt;/span&gt; candidate) {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:teal;"&gt;Enumerables&lt;/span&gt;.Do.ForEach(_explorer.RequiredTypes(candidate), TryInstantiate);&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; &lt;span style="color:blue;"&gt;bool&lt;/span&gt; HasFailedInstatiations(&lt;span style="color:teal;"&gt;Type&lt;/span&gt; candidate) {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;return&lt;/span&gt; _failed_instantiations.ContainsKey(candidate);&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; &lt;span style="color:blue;"&gt;void&lt;/span&gt; CountFailedInstantiation(&lt;span style="color:teal;"&gt;Type&lt;/span&gt; candidate) {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;if&lt;/span&gt; (! HasFailedInstatiations(candidate)) { _failed_instantiations[candidate] = 0; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            _failed_instantiations[candidate] += 1;&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;public&lt;/span&gt; &lt;span style="color:blue;"&gt;int&lt;/span&gt; FailedInstatiations&lt;t&gt;() {&lt;/t&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;if&lt;/span&gt; (! HasFailedInstatiations(&lt;span style="color:blue;"&gt;typeof&lt;/span&gt;(T))) { &lt;span style="color:blue;"&gt;return&lt;/span&gt; 0; }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;return&lt;/span&gt; _failed_instantiations[&lt;span style="color:blue;"&gt;typeof&lt;/span&gt; (T)];&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;    }&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Unit-Test sample:&lt;br /&gt;&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Bitstream Vera Sans Mono;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs18     \cf2 class\cf0  \cf10 B\cf0  \{\par ??        \cf2 private\cf0  \cf2 readonly\cf0  \cf10 C\cf0  _c;\par ??\par ??        \cf2 public\cf0  B(\cf10 C\cf0  c) \{\par ??            _c = c;\par ??            \cf2 throw\cf0  \cf2 new\cf0  \cf10 Exception\cf0 (\cf13 "poof"\cf0 );\par ??        \}\par ??    \}\par ??\par ??    \cf2 class\cf0  \cf10 C\cf0  \{\par ??        \cf2 public\cf0  C() \{\par ??            \cf2 throw\cf0  \cf2 new\cf0  \cf10 Exception\cf0 (\cf13 "poof"\cf0 );\par ??        \}\par ??    \}\par ??\par ??    \cf2 class\cf0  \cf10 D\cf0  \{\par ??        \par ??    \}\par ??\par ??    \cf2 class\cf0  \cf10 E\cf0  \{\par ??        \cf2 private\cf0  \cf2 readonly\cf0  \cf10 C\cf0 [] _cs;\par ??\par ??        \cf2 public\cf0  E(\cf10 C\cf0 [] cs) \{\par ??            _cs = cs;\par ??        \}\par ??    \}\par ??\par ??    \cf2 class\cf0  \cf10 A\cf0  \{\par ??        \cf2 private\cf0  \cf2 readonly\cf0  \cf10 B\cf0  _b;\par ??        \cf2 private\cf0  \cf2 readonly\cf0  \cf10 D\cf0  _d;\par ??\par ??        \cf2 public\cf0  A(\cf10 B\cf0  b, \cf10 D\cf0  d) \{\par ??            _b = b;\par ??            _d = d;\par ??        \}\par ??    \}\par ??\par ??\par ??    [\cf10 TestClass\cf0 ]\par ??    \cf2 public\cf0  \cf2 class\cf0  \cf10 InjectionDoctorSpecifications\cf0  \{\par ??        \cf2 private\cf0  \cf10 DefaultPicoContainer\cf0  _container;\par ??        \cf2 private\cf0  \cf10 InjectionDoctor\cf0  _doctor;\par ??\par ??        [\cf10 TestInitialize\cf0 ]\par ??        \cf2 public\cf0  \cf2 void\cf0  BeforeEachTest() \{\par ??            _container = \cf2 new\cf0  \cf10 DefaultPicoContainer\cf0 (); \par ??        \}\par ??\par ??        \cf2 private\cf0  \cf2 void\cf0  Register(\cf10 IEnumerable\cf0 &lt;\cf10 Type\cf0 &gt; types) \{\par ??            \cf2 foreach\cf0  (\cf10 Type\cf0  t \cf2 in\cf0  types) \{\par ??                _container.RegisterComponent(\cf2 new\cf0  \cf10 CachingComponentAdapter\cf0 (\cf2 new\cf0  \cf10 ConstructorInjectionComponentAdapter\cf0 (t)));\par ??            \}\par ??        \}\par ??\par ??        [\cf10 TestMethod\cf0 ]\par ??        \cf2 public\cf0  \cf2 void\cf0  should_detect_instantiation_failures() \{\par ??            \cf10 IEnumerable\cf0 &lt;\cf10 Type\cf0 &gt; types = \cf2 new\cf0  \cf10 Type\cf0 [] \{\cf2 typeof\cf0  (\cf10 A\cf0 ), \cf2 typeof\cf0  (\cf10 B\cf0 ), \cf2 typeof\cf0  (\cf10 C\cf0 ), \cf2 typeof\cf0  (\cf10 D\cf0 ), \cf2 typeof\cf0 (\cf10 E\cf0 )\};\par ??            Register(types);\par ??            _doctor = \cf2 new\cf0  \cf10 InjectionDoctor\cf0 (types, _container.GetComponentInstanceOfType);\par ??\par ??            _doctor.Examine();\par ??            \cf11 //_doctor.PrettyPrint();\par ??\cf0             \cf10 Assert\cf0 .AreEqual(1, _doctor.FailedInstatiations&lt;\cf10 A\cf0&gt;());\par ??            \cf10 Assert\cf0 .AreEqual(2, _doctor.FailedInstatiations&lt;\cf10 B\cf0&gt;());\par ??            \cf10 Assert\cf0 .AreEqual(3, _doctor.FailedInstatiations&lt;\cf10 C\cf0&gt;());\par ??            \cf10 Assert\cf0 .AreEqual(0, _doctor.FailedInstatiations&lt;\cf10 D\cf0&gt;());\par ??            \cf10 Assert\cf0 .AreEqual(1, _doctor.FailedInstatiations&lt;\cf10 E\cf0&gt;());\par ??        \}\par ??\par ??\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:9pt;color:black;"&gt;&lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;class&lt;/span&gt; &lt;span style="color:teal;"&gt;B&lt;/span&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;readonly&lt;/span&gt; &lt;span style="color:teal;"&gt;C&lt;/span&gt; _c;&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; B(&lt;span style="color:teal;"&gt;C&lt;/span&gt; c) {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            _c = c;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;throw&lt;/span&gt; &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;Exception&lt;/span&gt;(&lt;span style="color:maroon;"&gt;"poof"&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;/p&gt;&lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;class&lt;/span&gt; &lt;span style="color:teal;"&gt;C&lt;/span&gt; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;public&lt;/span&gt; C() {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;throw&lt;/span&gt; &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;Exception&lt;/span&gt;(&lt;span style="color:maroon;"&gt;"poof"&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;/p&gt;&lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;class&lt;/span&gt; &lt;span style="color:teal;"&gt;D&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;/p&gt;&lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;class&lt;/span&gt; &lt;span style="color:teal;"&gt;E&lt;/span&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;readonly&lt;/span&gt; &lt;span style="color:teal;"&gt;C&lt;/span&gt;[] _cs;&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; E(&lt;span style="color:teal;"&gt;C&lt;/span&gt;[] cs) {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            _cs = cs;&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;/p&gt;&lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;class&lt;/span&gt; &lt;span style="color:teal;"&gt;A&lt;/span&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;readonly&lt;/span&gt; &lt;span style="color:teal;"&gt;B&lt;/span&gt; _b;&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;readonly&lt;/span&gt; &lt;span style="color:teal;"&gt;D&lt;/span&gt; _d;&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; A(&lt;span style="color:teal;"&gt;B&lt;/span&gt; b, &lt;span style="color:teal;"&gt;D&lt;/span&gt; d) {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            _b = b;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            _d = d;&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;/p&gt;&lt;p style="margin: 0px;"&gt; &lt;/p&gt;&lt;p style="margin: 0px;"&gt;    [&lt;span style="color:teal;"&gt;TestClass&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;class&lt;/span&gt; &lt;span style="color:teal;"&gt;InjectionDoctorSpecifications&lt;/span&gt; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;private&lt;/span&gt; &lt;span style="color:teal;"&gt;DefaultPicoContainer&lt;/span&gt; _container;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;private&lt;/span&gt; &lt;span style="color:teal;"&gt;InjectionDoctor&lt;/span&gt; _doctor;&lt;/p&gt;&lt;p style="margin: 0px;"&gt; &lt;/p&gt;&lt;p style="margin: 0px;"&gt;        [&lt;span style="color:teal;"&gt;TestInitialize&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;void&lt;/span&gt; BeforeEachTest() {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            _container = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;DefaultPicoContainer&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; &lt;span style="color:blue;"&gt;void&lt;/span&gt; Register(&lt;span style="color:teal;"&gt;IEnumerable&lt;/span&gt;&lt;&lt;span style="color:teal;"&gt;Type&lt;/span&gt;&gt; types) {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;foreach&lt;/span&gt; (&lt;span style="color:teal;"&gt;Type&lt;/span&gt; t &lt;span style="color:blue;"&gt;in&lt;/span&gt; types) {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;                _container.RegisterComponent(&lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;CachingComponentAdapter&lt;/span&gt;(&lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;ConstructorInjectionComponentAdapter&lt;/span&gt;(t)));&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;/p&gt;&lt;p style="margin: 0px;"&gt;        [&lt;span style="color:teal;"&gt;TestMethod&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;void&lt;/span&gt; should_detect_instantiation_failures() {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:teal;"&gt;IEnumerable&lt;/span&gt;&lt;&lt;span style="color:teal;"&gt;Type&lt;/span&gt;&gt; types = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;Type&lt;/span&gt;[] {&lt;span style="color:blue;"&gt;typeof&lt;/span&gt; (&lt;span style="color:teal;"&gt;A&lt;/span&gt;), &lt;span style="color:blue;"&gt;typeof&lt;/span&gt; (&lt;span style="color:teal;"&gt;B&lt;/span&gt;), &lt;span style="color:blue;"&gt;typeof&lt;/span&gt; (&lt;span style="color:teal;"&gt;C&lt;/span&gt;), &lt;span style="color:blue;"&gt;typeof&lt;/span&gt; (&lt;span style="color:teal;"&gt;D&lt;/span&gt;), &lt;span style="color:blue;"&gt;typeof&lt;/span&gt;(&lt;span style="color:teal;"&gt;E&lt;/span&gt;)};&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            Register(types);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            _doctor = &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;InjectionDoctor&lt;/span&gt;(types, _container.GetComponentInstanceOfType);&lt;/p&gt;&lt;p style="margin: 0px;"&gt; &lt;/p&gt;&lt;p style="margin: 0px;"&gt;            _doctor.Examine();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:green;"&gt;//_doctor.PrettyPrint();&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:teal;"&gt;Assert&lt;/span&gt;.AreEqual(1, _doctor.FailedInstatiations&lt;&lt;span style="color:teal;"&gt;A&lt;/span&gt;&gt;());&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:teal;"&gt;Assert&lt;/span&gt;.AreEqual(2, _doctor.FailedInstatiations&lt;&lt;span style="color:teal;"&gt;B&lt;/span&gt;&gt;());&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:teal;"&gt;Assert&lt;/span&gt;.AreEqual(3, _doctor.FailedInstatiations&lt;&lt;span style="color:teal;"&gt;C&lt;/span&gt;&gt;());&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:teal;"&gt;Assert&lt;/span&gt;.AreEqual(0, _doctor.FailedInstatiations&lt;&lt;span style="color:teal;"&gt;D&lt;/span&gt;&gt;());&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:teal;"&gt;Assert&lt;/span&gt;.AreEqual(1, _doctor.FailedInstatiations&lt;&lt;span style="color:teal;"&gt;E&lt;/span&gt;&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;/p&gt;&lt;p style="margin: 0px;"&gt; &lt;/p&gt;&lt;p style="margin: 0px;"&gt;    }&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;The output of the PrettyPrint looks like:&lt;br /&gt;Type -&gt; Failed Instatiation Count&lt;br /&gt;Tests.C -&gt; 3&lt;br /&gt;Tests.B -&gt; 2&lt;br /&gt;Tests.E -&gt; 1&lt;br /&gt;Tests.A -&gt; 1&lt;br /&gt;&lt;br /&gt;Additionally we could add a method bool InjectionDoctor.HaveAllInstantionsSucceded()&lt;br /&gt;ps. The Blogger Code Formatter is not playing nice with the generics: the InjectionDoctor takes as parameter in constructor a function f(Type) -&gt; object. In this way we make the InjectionDoctor container-agnostic.&lt;br /&gt;pps. source-code on request.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-578742009824016020?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/578742009824016020/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=578742009824016020' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/578742009824016020'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/578742009824016020'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2007/08/injection-doctor.html' title='Injection Doctor'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-5028900447682242243</id><published>2007-08-01T09:50:00.000+02:00</published><updated>2007-08-01T11:25:36.504+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c# design'/><title type='text'>Mixing Peer (extension objects in c# 2.0)</title><content type='html'>In project X we have a big hierarchy of objects/interfaces:&lt;br /&gt;Eintrag&lt;br /&gt;- Artikel&lt;br /&gt;    - NeuFormArtikel&lt;br /&gt;    - NormalArtikel&lt;br /&gt;         - AbdaArtikel&lt;br /&gt;- Verweis&lt;br /&gt;- AbrechnungsEintrag&lt;br /&gt;&lt;br /&gt;(The hierarchy is bigger, but this is enough for our purpose.)&lt;br /&gt;We have a case, where in a View we must display a union of fields from this hierarchy. i.e. AbdaArtikel.Preis if the object has such a property, otherwise null/string.Empty.&lt;br /&gt;&lt;br /&gt;We have several options:&lt;br /&gt;- use a visitor for the whole hierarchy&lt;br /&gt;- use a PropertyMapper (reflection-fluent-interface-based machinery) (looks pretty slick, enables a very declarative way of mapping, maybe I will post about it)&lt;br /&gt;- extend/pull the AbdaArtikelPreis into the Eintrag (if we need it there)&lt;br /&gt;- mix in a generic visitor:&lt;br /&gt;&lt;br /&gt;Since the objects/interfaces in the hierarchy are Nhibernate BOs, they are proxied, i.e., in our configuration, we cannot use generic methods in BOs. But we can extend the BO with an object which can:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;we define Eintrag.Peer() { return new EintragPeer( this ); }&lt;/li&gt;&lt;li&gt;now we can extend the peer/mixing with generics&lt;/li&gt;&lt;r,t&gt;&lt;r,t&gt;&lt;t&gt;&lt;t&gt;&lt;br /&gt;&lt;/t&gt;&lt;/t&gt;&lt;/r,t&gt;&lt;/r,t&gt;&lt;/ol&gt; &lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Bitstream Vera Sans Mono;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs18 \cf2 public\cf0  \cf2 class\cf0  EintragPeer \{\par ??    \cf2 private\cf0  \cf2 readonly\cf0  IEintrag _extended;\par ??    \par ??    \cf2 public\cf0  EintragPeer( IEintrag extendable ) \{ _extended = extendable; \}\par ??    \par ??    \cf2 public\cf0  R TryMap&lt;r,t&gt;(Func&lt;r,t&gt; func, R otherwise_default) \cf2 where\cf0  T : IEintrag \{\par ??        \cf2 if\cf0  ( _extended \cf2 is\cf0  T ) \{ \cf2 return\cf0  func( _extended \cf2 as\cf0  T ); \}\par ??        \cf2 return\cf0  otherwise_default;\par ??    \}\par ??\par ??    \cf2 public\cf0  \cf2 void\cf0  TryApply&lt;t&gt;(Action&lt;t&gt; action) \cf2 where\cf0  T : IEintrag \{\par ??        \cf2 if\cf0  (_extended \cf2 is\cf0  T) \{ \cf2 return\cf0  action(_extended \cf2 as\cf0  T); \}\par ??    \}\par ??\}} --&gt; &lt;div face="Consolas" size="9pt" 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;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Bitstream Vera Sans Mono;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs18 \cf2 public\cf0  \cf2 class\cf0  EintragPeer \{\par ??    \cf2 private\cf0  \cf2 readonly\cf0  Eintrag _extended;\par ??    \par ??    \cf2 public\cf0  EintragPeer( Eintrag extendable ) \{ _extended = extendable; \}\par ??    \par ??    \cf2 public\cf0  R TryMap&lt;r,t&gt;(Func&lt;r,t&gt; func, R otherwise_default) \cf2 where\cf0  T : Eintrag \{\par ??        \cf2 if\cf0  ( _extended \cf2 is\cf0  T ) \{ \cf2 return\cf0  func( _extended \cf2 as\cf0  T ); \}\par ??        \cf2 return\cf0  otherwise_default;\par ??    \}\par ??\par ??    \cf2 public\cf0  \cf2 void\cf0  TryApply&lt;t&gt;(Action&lt;t&gt; action) \cf2 where\cf0  T : Eintrag \{\par ??        \cf2 if\cf0  (_extended \cf2 is\cf0  T) \{ \cf2 return\cf0  action(_extended \cf2 as\cf0  T); \}\par ??    \}\par ??\}\par ??} --&gt; &lt;div style="background: white none repeat scroll 0% 50%; font-family: Consolas; font-size: 9pt; 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;public&lt;/span&gt; &lt;span style="color: blue;"&gt;class&lt;/span&gt; EintragPeer {&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;readonly&lt;/span&gt; Eintrag _extended;&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; EintragPeer( Eintrag extendable ) { _extended = extendable; }&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; R TryMap&lt;r,t&gt;(Func&lt;r,t&gt; func, R otherwise_default) &lt;span style="color: blue;"&gt;where&lt;/span&gt; T : Eintrag {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        &lt;span style="color: blue;"&gt;if&lt;/span&gt; ( _extended &lt;span style="color: blue;"&gt;is&lt;/span&gt; T ) { &lt;span style="color: blue;"&gt;return&lt;/span&gt; func( _extended &lt;span style="color: blue;"&gt;as&lt;/span&gt; T ); }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        &lt;span style="color: blue;"&gt;return&lt;/span&gt; otherwise_default;&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;public&lt;/span&gt; &lt;span style="color: blue;"&gt;void&lt;/span&gt; TryApply&lt;t&gt;(Action&lt;t&gt; action) &lt;span style="color: blue;"&gt;where&lt;/span&gt; T : Eintrag {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        &lt;span style="color: blue;"&gt;if&lt;/span&gt; (_extended &lt;span style="color: blue;"&gt;is&lt;/span&gt; T) { &lt;span style="color: blue;"&gt;return&lt;/span&gt; action(_extended &lt;span style="color: blue;"&gt;as&lt;/span&gt; T); }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;    }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;}&lt;/p&gt;&lt;/div&gt; &lt;/div&gt; &lt;ol&gt;&lt;br /&gt;&lt;r,t&gt;&lt;r,t&gt;&lt;t&gt;&lt;t&gt;&lt;br /&gt;&lt;li&gt;Now we can use it as:&lt;/li&gt;&lt;/t&gt;&lt;/t&gt;&lt;/r,t&gt;&lt;/r,t&gt;&lt;/ol&gt; &lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Bitstream Vera Sans Mono;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs18 Preis eintrag_preis = eintrag.Peer().TryMap&lt;preis,artikel&gt;(\par ??    \cf2 delegate\cf0 (Artikel artikel) \{ \cf2 return\cf0  artikel.Preis; \},\par ??    Preis.Null);\par ??} --&gt; &lt;div style="background: white none repeat scroll 0% 50%; font-family: Consolas; font-size: 9pt; 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;Preis eintrag_preis = eintrag.Peer().TryMap&lt;preis,artikel&gt;(&lt;/p&gt;&lt;p style="margin: 0px;"&gt;    &lt;span style="color: blue;"&gt;delegate&lt;/span&gt;(Artikel artikel) { &lt;span style="color: blue;"&gt;return&lt;/span&gt; artikel.Preis; },&lt;/p&gt;&lt;p style="margin: 0px;"&gt;    Preis.Null);&lt;/p&gt;&lt;/div&gt; &lt;preis,rtikel&gt;&lt;preis,artikel&gt;&lt;br /&gt;&lt;br /&gt;Other variations can be build on that.&lt;br /&gt;&lt;br /&gt;&lt;/preis,artikel&gt;&lt;/preis,rtikel&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-5028900447682242243?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/5028900447682242243/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=5028900447682242243' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/5028900447682242243'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/5028900447682242243'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2007/08/mixing-peer-extension-objects-in-c-20.html' title='Mixing Peer (extension objects in c# 2.0)'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-1616255688124089370</id><published>2007-07-19T13:17:00.000+02:00</published><updated>2007-07-19T13:25:09.842+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile process rant'/><title type='text'>"Agile" Process Disentanglement</title><content type='html'>How &lt;a href="http://www.computerhope.com/cgi-bin/search.cgi?s=fubar"&gt;FUBAR&lt;/a&gt; can an "agile" process be, that &lt;a href="http://www.awprofessional.com/articles/article.asp?p=461427&amp;amp;rl=1"&gt;this book&lt;/a&gt; is needed?&lt;br /&gt;How deep in the jungle is the team, that we need a &lt;a href="http://www.c2.com/cgi/wiki?NoSilverBullet"&gt;silver-magic-map&lt;/a&gt; to bring it back &lt;a href="http://www.c2.com/cgi/wiki?DrivingMetaphor"&gt;on the driving-road&lt;/a&gt;?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-1616255688124089370?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/1616255688124089370/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=1616255688124089370' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/1616255688124089370'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/1616255688124089370'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2007/07/agile-process-disentanglement.html' title='&quot;Agile&quot; Process Disentanglement'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-6164369634121051804</id><published>2007-07-18T09:49:00.000+02:00</published><updated>2007-07-18T10:47:17.992+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c# functional programming'/><title type='text'>Functional idioms, Take Three</title><content type='html'>In a hypothetical project in which the &lt;a href="http://www.c2.com/cgi/wiki?LawOfDemeter"&gt;Law of Demeter&lt;/a&gt; is completely ignored navigation through objects is allowed: we can do A.B.C.D.E.DoSomething(). This has a lot of negative effects, already spoken/written, I'm not going into details.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;My 1st suggestion would be to play by the rules, and pull the DoSomething(...) through the hierarchy up to A, where you need it.&lt;/li&gt;&lt;li&gt;But what if you cannot do it ("it is not the way we do it in this project") ? What if, to make the matters worse, every element in the chain could be null (and not a &lt;a href="http://www.c2.com/cgi/wiki?search=NullObject"&gt;NullObject&lt;/a&gt;) ? The chain would explode in a cascade of if-then-else-s to check every element for null, etc...&lt;/li&gt;&lt;ul&gt;&lt;li&gt;Comega has something like int? = A.B.C.GetSomeIntValue(...)&lt;/li&gt;&lt;li&gt;We (C#) could do:&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt; &lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Bitstream Vera Sans Mono;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs18 created.PackungsgroessenEinheitText = \cf10 Chain\cf0 .On.Nullables&lt;\cf10 IArtikel\cf0 , \cf10 INormalArtikel\cf0 , \cf10 Packungsgroesse\cf0 , \cf2 string\cf0&gt;(\par ??                artikel,\par ??                \cf2 delegate\cf0 (\cf10 IArtikel\cf0  x) \{ \cf2 return\cf0  x \cf2 as\cf0  \cf10 INormalArtikel\cf0 ; \},\par ??                \cf2 delegate\cf0 (\cf10 INormalArtikel\cf0  x) \{ \cf2 return\cf0  x.Packungsgroesse; \},\par ??                \cf2 delegate\cf0 (\cf10 Packungsgroesse\cf0  x) \{ \cf2 return\cf0  \cf2 string\cf0 .Format(\cf13 "\{0\} \{1\}"\cf0 , x.Menge, x.Einheit); \}\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:9pt;color:black;"&gt;&lt;p style="margin: 0px;"&gt;created.PackungsgroessenEinheitText = &lt;span style="color:teal;"&gt;Chain&lt;/span&gt;.On.Nullables&lt;&lt;span style="color:teal;"&gt;IArtikel&lt;/span&gt;, &lt;span style="color:teal;"&gt;INormalArtikel&lt;/span&gt;, &lt;span style="color:teal;"&gt;Packungsgroesse&lt;/span&gt;, &lt;span style="color:blue;"&gt;string&lt;/span&gt;&gt;(&lt;/p&gt;&lt;p style="margin: 0px;"&gt;                artikel,&lt;/p&gt;&lt;p style="margin: 0px;"&gt;                &lt;span style="color:blue;"&gt;delegate&lt;/span&gt;(&lt;span style="color:teal;"&gt;IArtikel&lt;/span&gt; x) { &lt;span style="color:blue;"&gt;return&lt;/span&gt; x &lt;span style="color:blue;"&gt;as&lt;/span&gt; &lt;span style="color:teal;"&gt;INormalArtikel&lt;/span&gt;; },&lt;/p&gt;&lt;p style="margin: 0px;"&gt;                &lt;span style="color:blue;"&gt;delegate&lt;/span&gt;(&lt;span style="color:teal;"&gt;INormalArtikel&lt;/span&gt; x) { &lt;span style="color:blue;"&gt;return&lt;/span&gt; x.Packungsgroesse; },&lt;/p&gt;&lt;p style="margin: 0px;"&gt;                &lt;span style="color:blue;"&gt;delegate&lt;/span&gt;(&lt;span style="color:teal;"&gt;Packungsgroesse&lt;/span&gt; x) { &lt;span style="color:blue;"&gt;return&lt;/span&gt; &lt;span style="color:blue;"&gt;string&lt;/span&gt;.Format(&lt;span style="color:maroon;"&gt;"{0} {1}"&lt;/span&gt;, x.Menge, x.Einheit); }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            );&lt;/p&gt;&lt;/div&gt; &lt;ul&gt;&lt;ul&gt;&lt;li&gt; we navigate throught the chain with delegates. The navigation is interrupted on the 1st null hit.&lt;/li&gt;&lt;li&gt;If we watch the "chain" implementation:&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt; &lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Bitstream Vera Sans Mono;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs18    \cf2 public\cf0  \cf2 class\cf0  \cf10 Chain\cf0  \{\par ??        \cf2 private\cf0  Chain() \{\}\par ??\par ??        \cf2 public\cf0  \cf2 static\cf0  \cf10 Chain\cf0  On \{ \cf2 get\cf0  \{ \cf2 return\cf0  \cf2 new\cf0  \cf10 Chain\cf0 (); \} \}\par ??\par ??        \cf2 public\cf0   R Nullables&lt;s,&gt;(S input, \cf10 Func\cf0 &lt;r,&gt; fun_1)\par ??            \cf2 where\cf0  S : \cf2 class\par ??\cf0             \cf2 where\cf0  R : \cf2 class\cf0  \{\par ??\par ??            \cf2 if\cf0  (input == \cf2 null\cf0 ) \{\par ??                \cf2 return\cf0  \cf2 null\cf0 ;\par ??            \}\par ??\par ??            \cf2 return\cf0  fun_1(input);\par ??        \}\par ??\par ??        \cf2 public\cf0  R Nullables&lt;s,&gt;(S input, \cf10 Func\cf0 &lt;r1,s&gt; fun_1, \cf10 Func\cf0 &lt;r,r1&gt; fun_2) \par ??            \cf2 where\cf0  S : \cf2 class\cf0  \par ??            \cf2 where\cf0  R1 : \cf2 class\par ??\cf0             \cf2 where\cf0  R : \cf2 class\cf0  \{\par ??            \cf2 return\cf0  Nullables(Nullables(input, fun_1), fun_2);\par ??        \}\par ??\par ??        \cf2 public\cf0  R Nullables&lt;s,&gt;(S input, \cf10 Func\cf0 &lt;r1,&gt; fun_1, \cf10 Func\cf0 &lt;r2,&gt; fun_2, \cf10 Func\cf0 &lt;r,r2&gt; fun_3)\par ??            \cf2 where\cf0  S : \cf2 class\par ??\cf0             \cf2 where\cf0  R1 : \cf2 class\par ??\cf0             \cf2 where\cf0  R2 : \cf2 class\par ??\cf0             \cf2 where\cf0  R : \cf2 class\cf0  \{\par ??            \cf2 return\cf0  Nullables(Nullables(Nullables(input, fun_1), fun_2), fun_3);\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:9pt;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; &lt;span style="color:teal;"&gt;Chain&lt;/span&gt; {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        &lt;span style="color:blue;"&gt;private&lt;/span&gt; Chain() {}&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;static&lt;/span&gt; &lt;span style="color:teal;"&gt;Chain&lt;/span&gt; On { &lt;span style="color:blue;"&gt;get&lt;/span&gt; { &lt;span style="color:blue;"&gt;return&lt;/span&gt; &lt;span style="color:blue;"&gt;new&lt;/span&gt; &lt;span style="color:teal;"&gt;Chain&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;  R Nullables&lt;s,&gt;(S input, &lt;span style="color:teal;"&gt;Func&lt;/span&gt;&lt;r,&gt; fun_1)&lt;/r,&gt;&lt;/s,&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;where&lt;/span&gt; S : &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;where&lt;/span&gt; R : &lt;span style="color:blue;"&gt;class&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;if&lt;/span&gt; (input == &lt;span style="color:blue;"&gt;null&lt;/span&gt;) {&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;null&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;return&lt;/span&gt; fun_1(input);&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;public&lt;/span&gt; R Nullables&lt;s,&gt;(S input, &lt;span style="color:teal;"&gt;Func&lt;/span&gt;&lt;r1,s&gt; fun_1, &lt;span style="color:teal;"&gt;Func&lt;/span&gt;&lt;r,r1&gt; fun_2) &lt;/r,r1&gt;&lt;/r1,s&gt;&lt;/s,&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;where&lt;/span&gt; S : &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;where&lt;/span&gt; R1 : &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;where&lt;/span&gt; R : &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;return&lt;/span&gt; Nullables(Nullables(input, fun_1), fun_2);&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;public&lt;/span&gt; R Nullables&lt;s,&gt;(S input, &lt;span style="color:teal;"&gt;Func&lt;/span&gt;&lt;r1,&gt; fun_1, &lt;span style="color:teal;"&gt;Func&lt;/span&gt;&lt;r2,&gt; fun_2, &lt;span style="color:teal;"&gt;Func&lt;/span&gt;&lt;r,r2&gt; fun_3)&lt;/r,r2&gt;&lt;/r2,&gt;&lt;/r1,&gt;&lt;/s,&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;            &lt;span style="color:blue;"&gt;where&lt;/span&gt; S : &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;where&lt;/span&gt; R1 : &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;where&lt;/span&gt; R2 : &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;where&lt;/span&gt; R : &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;return&lt;/span&gt; Nullables(Nullables(Nullables(input, fun_1), fun_2), fun_3);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;        }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;    }&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;ul&gt;&lt;ul&gt;&lt;li&gt;we see that this could be very nicely implemented with some &lt;a href="http://en.wikibooks.org/wiki/C++_Programming/Template/Template_Meta-Programming"&gt;C++ metaprogramming templates (see compile-time factorial)&lt;/a&gt;.&lt;br /&gt;&lt;/li&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://research.microsoft.com/fsharp/fsharp.aspx"&gt;F#&lt;/a&gt; has &lt;a href="http://blogs.msdn.com/dsyme/archive/2006/12/18/DraftChaptersUpdateDec2006.aspx"&gt;function composition&lt;/a&gt; through pipelining, offering some optimizations for it&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Tail_recursion"&gt;Tail Call Optimization&lt;/a&gt; !?&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;div style="background: white none repeat scroll 0% 50%; font-family: Consolas; font-size: 9pt; color: black; -moz-background-clip: -moz-initial; -moz-background-origin: -moz-initial; -moz-background-inline-policy: -moz-initial;"&gt;&lt;br /&gt;&lt;p style="margin: 0px;"&gt;&lt;br /&gt;&lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-6164369634121051804?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/6164369634121051804/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=6164369634121051804' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/6164369634121051804'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/6164369634121051804'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2007/07/functional-idioms-take-three.html' title='Functional idioms, Take Three'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-4340074782177888704</id><published>2007-07-09T10:51:00.000+02:00</published><updated>2007-07-18T09:46:57.268+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='c# f# functional programming'/><title type='text'>Functional Idioms, Take Two</title><content type='html'>My friend &lt;a href="http://rkse.blogspot.com/"&gt;Ralf&lt;/a&gt; has &lt;a href="http://rkse.blogspot.com/2007/07/slightly-enhanced-higher-level.html"&gt;extended&lt;/a&gt; the &lt;a href="http://thought-tracker.blogspot.com/2007/04/higher-level-abstractions-on.html"&gt;Enumerating&lt;/a&gt; module, adding a  &lt;a href="http://www.martinfowler.com/bliki/FluentInterface.html"&gt;fluent interface&lt;/a&gt;.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Since the mini-project lives, I think we should create a sourceforge acount for it.&lt;/li&gt;&lt;ul&gt;&lt;li&gt;I have extended the interface with IsEmpty, Count, ApplyOnce, ...&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;I really like the fluent interface. SelectThenCollect is no longer necessary, we can do Select(...).Collect(...)&lt;/li&gt;&lt;ul&gt;&lt;li&gt;if in the initial Enumerable we have m elements and we select n from them, SelectThenCollect is O(m). Select(...).Collect(...) will take O(m)+O(n). (in the current implementation).&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;li&gt;Open Question: the current implementation does eager-evaluation: the select is computed when the method is called. &lt;span style="font-weight: bold;"&gt;Do we need a lazy-implementation?&lt;/span&gt; It could look like a query definition, and the code will be more declarative:&lt;br /&gt;&lt;/li&gt;&lt;ul&gt;&lt;li  style="font-family:courier new;"&gt;&lt;span style="font-size:85%;"&gt;IEnumerating&lt;t&gt; query = Enumerating.On(several_things).Select(IsEven).Collect(ItsColor);&lt;br /&gt;&lt;/t&gt;&lt;/span&gt;&lt;/li&gt;&lt;li  style="font-family:courier new;"&gt;&lt;span style="font-size:85%;"&gt;IEnumerable&lt;t&gt; result_items =  query.Eval();&lt;/t&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;The solution might cache, the specified delegates, for a later (lazy), usage. This might lead to some unwanted side-effects: the garbage collector will not release the objects referenced  in the delegates in the query definition, until ... (the query is released).&lt;/li&gt;&lt;li&gt;Through laziness we could work on &lt;a href="http://blogs.technet.com/apg/archive/2006/11/04/dealing-with-terabytes-with-f.aspx"&gt;very large&lt;/a&gt; (infinite) data &lt;a href="http://blogs.msdn.com/wesdyer/archive/2007/02/13/the-virtues-of-laziness.aspx"&gt;streams&lt;/a&gt;.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-4340074782177888704?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/4340074782177888704/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=4340074782177888704' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/4340074782177888704'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/4340074782177888704'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2007/07/functional-idioms-take-two.html' title='Functional Idioms, Take Two'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-2885122903263535213</id><published>2007-07-03T17:17:00.000+02:00</published><updated>2007-07-03T17:30:01.116+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tdd agile sudoku'/><title type='text'>Sudoku Solver: TDD or not</title><content type='html'>In this &lt;a href="http://ravimohan.blogspot.com/2007/04/learning-from-sudoku-solvers.html"&gt;blog&lt;/a&gt; people are comparing Peter Norvig's &lt;a href="http://norvig.com/sudoku.html"&gt;solution&lt;/a&gt; with Ron Jeffries TDD tries. (read the post, [some] good comments, other links to reddit comments, etc.)&lt;br /&gt;&lt;br /&gt;It is a nice problem to chew on, for me, as Unit-Test/TDD agilist: I think that a TDD approach does &lt;span style="font-weight: bold;"&gt;not&lt;/span&gt; lead to  discover &lt;a href="http://aima.cs.berkeley.edu/newchap05.pdf"&gt;constraint satisfaction algorithms&lt;/a&gt;, it should lead to a clean, testable, &lt;a href="http://www.objectmentor.com/resources/articles/srp.pdf"&gt;SRP&lt;/a&gt; driven architecture. If I remember well, the XP books say that you should start with a "&lt;a href="http://www.xprogramming.com/xpmag/whatisxp.htm#metaphor"&gt;metaphor&lt;/a&gt;", a design starting point.&lt;br /&gt;&lt;br /&gt;disclaimer: this an echo post, i just wanted to link to &lt;a href="http://aima.cs.berkeley.edu/"&gt;AIMA&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-2885122903263535213?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/2885122903263535213/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=2885122903263535213' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/2885122903263535213'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/2885122903263535213'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2007/07/sudoku-solver-tdd-or-not.html' title='Sudoku Solver: TDD or not'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-3402192817683963491</id><published>2007-06-28T21:09:00.000+02:00</published><updated>2007-07-09T10:50:13.934+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='logging unit testing tdd'/><title type='text'>Logging and Unit-Testing</title><content type='html'>Imagine the following situation:&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:Courier New;font-size:8pt;color:black;"&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    1&lt;/span&gt; &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;class&lt;/span&gt; SomeService {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    2&lt;/span&gt;     &lt;span style="color:blue;"&gt;private&lt;/span&gt; &lt;span style="color:blue;"&gt;static&lt;/span&gt; ILogger _logger = &lt;span style="color:blue;"&gt;new&lt;/span&gt; Logger&amp;lt;SomeService&amp;gt;();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    3&lt;/span&gt;     &lt;span style="color:green;"&gt;//...&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    4&lt;/span&gt;     &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;void&lt;/span&gt; DoSomething() {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    5&lt;/span&gt;         _logger.Debug(&lt;span style="color:maroon;"&gt;"I log something cheap {0}"&lt;/span&gt;, _service.DoSomething());&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    6&lt;/span&gt;         &lt;span style="color:green;"&gt;//...&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    7&lt;/span&gt;         &lt;span style="color:blue;"&gt;if&lt;/span&gt; (_logger.IsDebugEnabled()) {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    8&lt;/span&gt;             _logger.Debug(&lt;span style="color:maroon;"&gt;"I log something expensive {0}"&lt;/span&gt;, _service.DoSomethingElse());&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;    9&lt;/span&gt;         }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   10&lt;/span&gt;     }&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;How do we want to test that logging works in this situation?&lt;br /&gt;A proposed solution was:&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:Courier New;font-size:8pt;color:black;"&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   13&lt;/span&gt;   [Test]&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   14&lt;/span&gt;     &lt;span style="color:blue;"&gt;public&lt;/span&gt; &lt;span style="color:blue;"&gt;void&lt;/span&gt; should_log_something() {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   15&lt;/span&gt;         &lt;span style="color:blue;"&gt;using&lt;/span&gt;(disable_appenders_and_introduce_new_appender = &lt;span style="color:blue;"&gt;new&lt;/span&gt; MagicStringAppender()) {&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   16&lt;/span&gt;             _service_under_test.DoSomething();&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   17&lt;/span&gt;             Assert(disable_appenders_and_introduce_new_appender.AllMessages.Contains(&lt;span style="color:maroon;"&gt;"I log ..."&lt;/span&gt;);&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   18&lt;/span&gt;         }&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;   19&lt;/span&gt;     }&lt;/p&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;And here is what I don't like about it:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Static creation of ILogger: by this we make ourselves dependent of the concrete implementation of Logger&lt;type&gt; class. This will pull other dependencies (like log4net) in the environment, despite the fact that these are irrelevant for the test. The logger will be created when the class(type) is instantiated.&lt;br /&gt;&lt;/type&gt;&lt;/li&gt;&lt;li&gt;The check-before logging for expensive log operations, is too low-level. A macro might help (TRY_LOG_DEBUG(...)), or maybe delaying the expensive operation into a lazy delegate: _logger.Debug(Func&lt;string&gt; a_delayed_string_generator). The only objection might be that wrapping the costly operation in a delegate creates an extra object, making in the worst case scenario, the logging even more expensive. (From what I know, delegates &amp;amp; closures are pretty cheap).&lt;br /&gt;&lt;/string&gt;&lt;/li&gt;&lt;li&gt;Maybe we don't know which operations are cheap and which are expensive, maybe in time a cheap log call will evolve to an expensive one. I would prefer a uniform lazy_delegate or macro solution.&lt;/li&gt;&lt;li&gt;We are trying to unit-test a scope which is too big: if the service sends a message to the logger interface, if log4net (and its wrapper) receive the message, if according to the configuration, the log message is sent to the right appender, etc... Suppose that we change the config, and log4net, and the test fails. Then we have a lot of fun debugging. We will say: "why isn't working, I haven't changed anything in months". Because the scope is too big, we have no chance to do a &lt;a href="http://www.artima.com/weblogs/viewpost.jsp?thread=126923"&gt;binary chop&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;We have built another big machinery to manipulate log4net at the wrong end. This machinery must be maintained and support (for example when we want to switch to another log engine)&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;What I would do (probably better):&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Explicitly specify that we want to log in constructor. Either inject an ILogger or an ILoggerFactory.&lt;/li&gt;&lt;li&gt;Test only that the service sends a message to the ILogger interface (a mock or a stub recorder)&lt;/li&gt;&lt;li&gt;Try to use a delegate for delayed/expensive computations.&lt;/li&gt;&lt;li&gt;Use a main logger for the critical  exceptions (like OutOfMemory)&lt;/li&gt;&lt;/ol&gt;---&lt;br /&gt;Update:&lt;br /&gt;- the post it is not about what am I trying to log, it is about "how" I am trying to log. (suppose the expensive operation is dumping a complex object tree to a human-readable-not-xml representation)&lt;br /&gt;- I am not a proponent for logging-testing, but some people would like to do that (logging gives a chill-fuzzy feeling: "I don't know what I have implemented, QA also doesn't have a clue, and now we are relying on log files, on a production-customer-machine. hmmm..."&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-3402192817683963491?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/3402192817683963491/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=3402192817683963491' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/3402192817683963491'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/3402192817683963491'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2007/06/logging-and-unit-testing.html' title='Logging and Unit-Testing'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-5507318527179912998</id><published>2007-06-15T09:16:00.000+02:00</published><updated>2007-06-15T10:01:18.496+02:00</updated><title type='text'>F# FizzBuzz</title><content type='html'>I'm trying to learn &lt;a href="http://del.icio.us/andrei.pamula/f%23"&gt;F#&lt;/a&gt; as the "pragmatic-learn-a-new-changing-the-way-you-think-programming-language-every-year" (sorry about that, &lt;a href="http://german.about.com/library/blwort_long.htm"&gt;it must be the german influence&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;Here are my &lt;a href="http://weblog.raganwald.com/2007/01/dont-overthink-fizzbuzz.html"&gt;FizzBuzz&lt;/a&gt; exercises, based on &lt;a href="http://research.microsoft.com/research/pubs/view.aspx?0rc=p&amp;type=technical+report&amp;amp;id=1275"&gt;F# Active Patterns&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;First try:&lt;br /&gt;&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Bitstream Vera Sans Mono;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs18 \cf2 let\cf0  (| fizz|_ |) x = \cf2 if\cf0  x % 3 = 0 \cf2 then\cf0  Some(\cf13 "fizz"\cf0 ) \cf2 else\cf0  None\par ??\cf2 let\cf0  (| buzz|_ |) x = \cf2 if\cf0  x % 5 = 0 \cf2 then\cf0  Some(\cf13 "buzz"\cf0 ) \cf2 else\cf0  None\par ??\cf2 let\cf0  (| fizzbuzz|_ |) x = \cf2 if\cf0  x % 15 = 0 \cf2 then\cf0  Some(\cf13 "fizzbuzz"\cf0 ) \cf2 else\cf0  None\par ??\par ??\cf2 let\cf0  print_fizzbuzz (x:int) = \par ??\tab \cf2 let\cf0  display text = print_string text; print_newline() \cf2 in\cf0 \tab \par ??\tab \cf2 match\cf0  x \cf2 with\par ??\cf0 \tab | fizzbuzz text \cf2 -&gt;\cf0  display text\par ??\tab | fizz text \cf2 -&gt;\cf0  display text\par ??\tab | buzz text \cf2 -&gt;\cf0  display text\par ??\tab | _ \cf2 -&gt;\cf0  x.ToString() |&gt; display\par ??\tab \par ??\cf2 let\cf0  _ = \cf2 for\cf0  i = 1 \cf2 to\cf0  20 \cf2 do\cf0  print_fizzbuzz i \cf2 done} --&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:Bitstream Vera Sans Mono;font-size:9pt;color:black;"&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color: rgb(43, 145, 175);"&gt;&lt;/span&gt; &lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Bitstream Vera Sans Mono;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs18 \cf2 let\cf0  (| fizz|_ |) x = \cf2 if\cf0  x % 3 = 0 \cf2 then\cf0  Some(\cf13 "fizz"\cf0 ) \cf2 else\cf0  None\par ??\cf2 let\cf0  (| buzz|_ |) x = \cf2 if\cf0  x % 5 = 0 \cf2 then\cf0  Some(\cf13 "buzz"\cf0 ) \cf2 else\cf0  None\par ??\cf2 let\cf0  (| fizzbuzz|_ |) x = \cf2 if\cf0  x % 15 = 0 \cf2 then\cf0  Some(\cf13 "fizzbuzz"\cf0 ) \cf2 else\cf0  None\par ??\par ??\cf2 let\cf0  print_fizzbuzz (x:int) = \par ??\tab \cf2 let\cf0  display text = print_string text; print_newline() \cf2 in\cf0 \tab \par ??\tab \cf2 match\cf0  x \cf2 with\par ??\cf0 \tab | fizzbuzz text \cf2 -&gt;\cf0  display text\par ??\tab | fizz text \cf2 -&gt;\cf0  display text\par ??\tab | buzz text \cf2 -&gt;\cf0  display text\par ??\tab | _ \cf2 -&gt;\cf0  x.ToString() |&gt; display\par ??\tab \par ??\cf2 let\cf0  _ = \cf2 for\cf0  i = 1 \cf2 to\cf0  20 \cf2 do\cf0  print_fizzbuzz i \cf2 done} --&gt; &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:Bitstream Vera Sans Mono;font-size:9pt;color:black;"&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;let&lt;/span&gt; (| fizz|_ |) x = &lt;span style="color:blue;"&gt;if&lt;/span&gt; x % 3 = 0 &lt;span style="color:blue;"&gt;then&lt;/span&gt; Some(&lt;span style="color:maroon;"&gt;"fizz"&lt;/span&gt;) &lt;span style="color:blue;"&gt;else&lt;/span&gt; None&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;let&lt;/span&gt; (| buzz|_ |) x = &lt;span style="color:blue;"&gt;if&lt;/span&gt; x % 5 = 0 &lt;span style="color:blue;"&gt;then&lt;/span&gt; Some(&lt;span style="color:maroon;"&gt;"buzz"&lt;/span&gt;) &lt;span style="color:blue;"&gt;else&lt;/span&gt; None&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;let&lt;/span&gt; (| fizzbuzz|_ |) x = &lt;span style="color:blue;"&gt;if&lt;/span&gt; x % 15 = 0 &lt;span style="color:blue;"&gt;then&lt;/span&gt; Some(&lt;span style="color:maroon;"&gt;"fizzbuzz"&lt;/span&gt;) &lt;span style="color:blue;"&gt;else&lt;/span&gt; None&lt;/p&gt;&lt;p style="margin: 0px;"&gt; &lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;let&lt;/span&gt; print_fizzbuzz (x:int) = &lt;/p&gt;&lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;let&lt;/span&gt; display text = print_string text; print_newline() &lt;span style="color:blue;"&gt;in&lt;/span&gt;    &lt;/p&gt;&lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;match&lt;/span&gt; x &lt;span style="color:blue;"&gt;with&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;    | fizzbuzz text &lt;span style="color:blue;"&gt;-&gt;&lt;/span&gt; display text&lt;/p&gt;&lt;p style="margin: 0px;"&gt;    | fizz text &lt;span style="color:blue;"&gt;-&gt;&lt;/span&gt; display text&lt;/p&gt;&lt;p style="margin: 0px;"&gt;    | buzz text &lt;span style="color:blue;"&gt;-&gt;&lt;/span&gt; display text&lt;/p&gt;&lt;p style="margin: 0px;"&gt;    | _ &lt;span style="color:blue;"&gt;-&gt;&lt;/span&gt; x.ToString() |&gt; display&lt;/p&gt;&lt;p style="margin: 0px;"&gt; &lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;let&lt;/span&gt; _ = &lt;span style="color:blue;"&gt;for&lt;/span&gt; i = 1 &lt;span style="color:blue;"&gt;to&lt;/span&gt; 20 &lt;span style="color:blue;"&gt;do&lt;/span&gt; print_fizzbuzz i &lt;span style="color:blue;"&gt;done&lt;/span&gt;&lt;/p&gt;&lt;/div&gt; &lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Second try: refactor the recognizers to a single parameterized recognizer:&lt;br /&gt;&lt;!-- {\rtf1\ansi\ansicpg\lang1024\noproof1252\uc1 \deff0{\fonttbl{\f0\fnil\fcharset0\fprq1 Bitstream Vera Sans Mono;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0??;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;??\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;??\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;??\red192\green192\blue192;}??\fs18 \par ??\cf2 let\cf0  (| is_multiple|_ |) n text x  = \cf2 if\cf0  x % n = 0 \cf2 then\cf0  Some(text) \cf2 else\cf0  None\par ??\par ??\cf2 let\cf0  print_fizzbuzz (x:int) = \par ??\tab \cf2 let\cf0  display text = print_string text; print_newline() \cf2 in\cf0 \tab \par ??\tab \cf2 match\cf0  x \cf2 with\par ??\cf0 \tab | is_multiple 15 \cf13 "fizzbuzz"\cf0  text \cf2 -&gt;\cf0  display text\par ??\tab | is_multiple 5 \cf13 "fizz"\cf0  text \cf2 -&gt;\cf0  display text\par ??\tab | is_multiple 3 \cf13 "buzz"\cf0  text \cf2 -&gt;\cf0  display text\par ??\tab | _ \cf2 -&gt;\cf0  x.ToString() |&gt; display\par ??\par ??\par ??\cf2 let\cf0  _ = \cf2 for\cf0  i = 1 \cf2 to\cf0  20 \cf2 do\cf0  print_fizzbuzz i \cf2 done\par ??\par ??} --&gt; &lt;div style="background: white none repeat scroll 0% 50%; font-family: Bitstream Vera Sans Mono; font-size: 9pt; 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;br /&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;let&lt;/span&gt; (| is_multiple|_ |) n text x  = &lt;span style="color:blue;"&gt;if&lt;/span&gt; x % n = 0 &lt;span style="color:blue;"&gt;then&lt;/span&gt; Some(text) &lt;span style="color:blue;"&gt;else&lt;/span&gt; None&lt;/p&gt;&lt;p style="margin: 0px;"&gt; &lt;/p&gt;&lt;p style="margin: 0px;"&gt;&lt;span style="color:blue;"&gt;let&lt;/span&gt; print_fizzbuzz (x:int) = &lt;/p&gt;&lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;let&lt;/span&gt; display text = print_string text; print_newline() &lt;span style="color:blue;"&gt;in&lt;/span&gt;    &lt;/p&gt;&lt;p style="margin: 0px;"&gt;    &lt;span style="color:blue;"&gt;match&lt;/span&gt; x &lt;span style="color:blue;"&gt;with&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt;    | is_multiple 15 &lt;span style="color:maroon;"&gt;"fizzbuzz"&lt;/span&gt; text &lt;span style="color:blue;"&gt;-&gt;&lt;/span&gt; display text&lt;/p&gt;&lt;p style="margin: 0px;"&gt;    | is_multiple 5 &lt;span style="color:maroon;"&gt;"fizz"&lt;/span&gt; text &lt;span style="color:blue;"&gt;-&gt;&lt;/span&gt; display text&lt;/p&gt;&lt;p style="margin: 0px;"&gt;    | is_multiple 3 &lt;span style="color:maroon;"&gt;"buzz"&lt;/span&gt; text &lt;span style="color:blue;"&gt;-&gt;&lt;/span&gt; display text&lt;/p&gt;&lt;p style="margin: 0px;"&gt;    | _ &lt;span style="color:blue;"&gt;-&gt;&lt;/span&gt; x.ToString() |&gt; display&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;let&lt;/span&gt; _ = &lt;span style="color:blue;"&gt;for&lt;/span&gt; i = 1 &lt;span style="color:blue;"&gt;to&lt;/span&gt; 20 &lt;span style="color:blue;"&gt;do&lt;/span&gt; print_fizzbuzz i &lt;span style="color:blue;"&gt;done&lt;/span&gt;&lt;/p&gt;&lt;p style="margin: 0px;"&gt; &lt;/p&gt;&lt;/div&gt;&lt;br /&gt;(* we do get a warning that the syntax for the parameterized recognizers is under review and it might change in the future release *)&lt;br /&gt;&lt;br /&gt;Please post or backlink for improvements :D&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-5507318527179912998?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/5507318527179912998/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=5507318527179912998' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/5507318527179912998'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/5507318527179912998'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2007/06/f-fizzbuzz.html' title='F# FizzBuzz'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-2185004661162688613</id><published>2007-06-05T13:23:00.000+02:00</published><updated>2007-06-05T14:17:27.267+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='architecture'/><title type='text'>APIs, handling dependencies, agile architecture</title><content type='html'>Somebody said recently that Resharper is "not so lovely" since it cannot handle thousand of files... My argument is that the need to work simultaneously (in a solution) is a smell, and the fact that Resharper crashes at type-parsing with a "System.OutOfMemoryException" exception should amplify the smell (increase our awareness).&lt;br /&gt;&lt;br /&gt;I think we have only two cases: inside the &lt;a href="http://video.google.com/videoplay?docid=-2950949730059754521"&gt;membrane&lt;/a&gt;, or outside the &lt;a href="http://video.google.com/videoplay?docid=-2950949730059754521"&gt;membrane&lt;/a&gt;. The core of the cell represents a service implementation, the membrane represents service definition, outside the membrane are the service consumers/users. &lt;span style="font-style: italic;"&gt;Actually outside the membrane, is inside another membrane: the whole architecture should be splitted in components&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;If we are inside we are working on the implementation of a certain service(object, component). Inside a component we have limited visibility, up to a component interface (the membrane). Maybe some other interfaces, or stand-alone components (without external dependencies, for examples &lt;a href="http://thought-tracker.blogspot.com/2007/04/higher-level-abstractions-on.html"&gt;enumerating&lt;/a&gt;). All refactorings, type-parsing should occur without problem in this component.&lt;br /&gt;&lt;br /&gt;If we are outside, we are service consumers. But we cannot talk to the "core" of the cell, we see only the membrane: the component interface. So we are not influenced by the changes in the implementation of the service (aka the "core").&lt;br /&gt;&lt;br /&gt;What happens if you are a producer and you need to modify service definition. If we don't have a few consumers, we could load all the required components in a solution (producer + all consumers), and refactor the whole thing. If we have many consumers, we need to use &lt;a href="http://www.infoq.com/presentations/effective-api-design"&gt;public API techniques&lt;/a&gt;: we declare the whole interface as obsolete, we declare and implement the new one. After x weeks we delete the old interface (the consumers are responsible for refactoring their own code).&lt;br /&gt;&lt;br /&gt;Isolating the change, is a fundamental principle in designing maintainable architectures. In a &lt;a href="http://www.moviegoods.com/posters/the_blob.asp?affiliateID=415"&gt;world without membranes&lt;/a&gt;, we are just hurting each other.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-2185004661162688613?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/2185004661162688613/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=2185004661162688613' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/2185004661162688613'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/2185004661162688613'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2007/06/apis-handling-dependencies-agile.html' title='APIs, handling dependencies, agile architecture'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-3247964534180478943</id><published>2007-04-10T10:55:00.000+02:00</published><updated>2007-04-10T11:22:05.497+02:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='design'/><title type='text'>Higher-Level Abstractions on Enumerations</title><content type='html'>I am &lt;a href="http://www.codeplex.com/ncollection"&gt;not&lt;/a&gt; &lt;a href="http://www.ruby-doc.org/core/classes/Enumerable.html"&gt;the&lt;/a&gt; &lt;a href="http://www.itu.dk/research/c5/"&gt;only&lt;/a&gt; &lt;a href="http://www.wintellect.com/PowerCollections.aspx"&gt;one&lt;/a&gt; missing a higher-level of abstraction in .Net.&lt;br /&gt;I feel that I wrote thousand times find, select, collect as foreach ...&lt;br /&gt;statement, without the clarity (&lt;a href="http://syntaxfree.wordpress.com/2007/02/10/guido-is-wrong-for-loops-declarativeness-and-charlie-mingus/"&gt;declarativeness&lt;/a&gt;) needed.&lt;br /&gt;Here is my &lt;a href="http://www.geocities.com/andrei_pamula/download/enumerating.zip"&gt;shot&lt;/a&gt;&lt;br /&gt;(very lightweight at it):&lt;br /&gt;&lt;br /&gt;&lt;a href="http://4.bp.blogspot.com/_bFWFWgnb3mw/RhtVYAUqkOI/AAAAAAAAAAU/QlRdNQtL72Q/s1600-h/CropperCapture%5B1%5D.Jpg"&gt;&lt;img style="display:block; margin:0 0 10px 10px;cursor:pointer; cursor:hand;" src="http://4.bp.blogspot.com/_bFWFWgnb3mw/RhtVYAUqkOI/AAAAAAAAAAU/QlRdNQtL72Q/s400/CropperCapture%5B1%5D.Jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5051725277918040290" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;a href="http://2.bp.blogspot.com/_bFWFWgnb3mw/RhtVrgUqkPI/AAAAAAAAAAc/TnqI2LsJteA/s1600-h/CropperCapture%5B5%5D.Jpg"&gt;&lt;img style="display:block; margin:0 0 10px 10px;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_bFWFWgnb3mw/RhtVrgUqkPI/AAAAAAAAAAc/TnqI2LsJteA/s400/CropperCapture%5B5%5D.Jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5051725612925489394" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-3247964534180478943?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/3247964534180478943/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=3247964534180478943' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/3247964534180478943'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/3247964534180478943'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2007/04/higher-level-abstractions-on.html' title='Higher-Level Abstractions on Enumerations'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_bFWFWgnb3mw/RhtVYAUqkOI/AAAAAAAAAAU/QlRdNQtL72Q/s72-c/CropperCapture%5B1%5D.Jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-9093198789677069141</id><published>2007-02-01T10:59:00.000+01:00</published><updated>2007-02-01T11:50:54.760+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tdd'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><title type='text'>Static Considered Harmfull</title><content type='html'>Let's imagine the following situation: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;static class Service {&lt;br /&gt; static void DoSomething(...)&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;class Client {&lt;br /&gt; Client() {}&lt;br /&gt; &lt;br /&gt; void Action() {&lt;br /&gt;  Service.DoSomething(...)&lt;br /&gt; }&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;We have the following smells: &lt;br /&gt;&lt;br /&gt;&lt;b&gt;1. Tight-Coupling&lt;/b&gt; &lt;br /&gt;- The client object is tight-coupled with the Service class. &lt;br /&gt;- We cannot exchange, polymorphically, the Service.DoSomething(...) &lt;br /&gt;with another service FunkyService?.DoSomething. &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;2. "Lying" Constructor&lt;/b&gt; &lt;br /&gt;- The client's constructor doesn't declare all the dependecies. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;3. Tight-Coupling Propagation&lt;/b&gt; &lt;br /&gt;- If the class Service has dependencies to other static classes &lt;br /&gt;(methods, instances, properties), than these dependencies propagate into &lt;br /&gt;the client. The "inoffensive" Service.DoSomething(...) is just the tip of an iceberg of singletons. &lt;br /&gt;&lt;br /&gt;Proposed Solution: &lt;br /&gt;In an OO world, responsabilities are realized by objects. &lt;br /&gt;Unfortunately in static-typed langugages classes ARE NOT objects. &lt;br /&gt;(in smalltalk/ruby they are, we don't have this problem) &lt;br /&gt;&lt;br /&gt;So let's do it right from the beginning: &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;interface IService {&lt;br /&gt; void DoSomething(...)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;[Inject]&lt;br /&gt;class Service {&lt;br /&gt; void DoSomething(...)&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class Client {&lt;br /&gt; Client(IService service) { _service = service }&lt;br /&gt; void Action(service.DoSomething(...));&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Benefits: &lt;br /&gt;- we are unattached from the implementation of the IService.DoSomething &lt;br /&gt;- we have explicitely defined the responsability of the client to delegate/ask a &lt;br /&gt;query to the IService implementor &lt;br /&gt;- We can provide different implementations to the IService &lt;br /&gt;- UnitTesting is easier: if the implementation of the IService has been tested, &lt;br /&gt;then in the Client's unit-tests we are only interested in the call to IService, &lt;br /&gt;which we can mock. &lt;br /&gt;- Instance creation is handled by dependency injection container &lt;br /&gt;(if you need only one, create just only one) &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;An example in ruby (classes are factory objects): &lt;br /&gt;http://onestepback.org/articles/depinj/&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-9093198789677069141?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/9093198789677069141/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=9093198789677069141' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/9093198789677069141'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/9093198789677069141'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2007/02/static-considered-harmfull.html' title='Static Considered Harmfull'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-115995753675814775</id><published>2006-10-04T12:22:00.000+02:00</published><updated>2006-10-04T12:29:09.180+02:00</updated><title type='text'></title><content type='html'>A bile on the &lt;a href="http://jroller.com/page/fate?entry=the_death_of_agile"&gt;the death of agile&lt;/a&gt; and an other post about the flip side of agile as religion vs. agility at google: &lt;a href="http://steve-yegge.blogspot.com/2006/09/good-agile-bad-agile_27.html"&gt;Good Agile, Bad Agile&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-115995753675814775?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/115995753675814775/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=115995753675814775' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115995753675814775'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115995753675814775'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/10/bile-on-the-death-of-agile-and-other.html' title=''/><author><name>moxica</name><uri>http://www.blogger.com/profile/10084204479295620888</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-115824496659832480</id><published>2006-09-14T16:42:00.000+02:00</published><updated>2006-09-14T16:42:46.676+02:00</updated><title type='text'>Agile Project Management Planning and Budgetting</title><content type='html'>&lt;p&gt;Great &lt;a href="http://www.infoq.com/presentations/Agile-planning-and-budgetting"&gt;presentation&lt;/a&gt; via InfoQ by David Hussman.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-115824496659832480?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/115824496659832480/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=115824496659832480' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115824496659832480'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115824496659832480'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/09/agile-project-management-planning-and.html' title='Agile Project Management Planning and Budgetting'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-115796282459585232</id><published>2006-09-11T10:20:00.000+02:00</published><updated>2006-09-11T10:20:24.653+02:00</updated><title type='text'>Liskov Substitution in Dynamic Languages</title><content type='html'>&lt;p&gt;A &lt;a href="http://butunclebob.com/ArticleS.MichaelFeathers.LiskovSubstitutionInDynamicLanguages"&gt;nice discussion&lt;/a&gt; on Michael S. Feathers blog.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://onestepback.org/"&gt;Jim Weirich&lt;/a&gt; observes:&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;The original LSP is defined in terms of types and subtypes, not classes and subclasses. In Ruby, we try to remind people that type is not related to class. It seems to me that LSP still applies to dynamic languages, even if there is no direct language construct for type.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Also a link to &lt;a href="http://thought-tracker.blogspot.com/2006/04/to-interface-or-not-to-interface.html"&gt;dynamic/static type contracts (interfaces)&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-115796282459585232?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/115796282459585232/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=115796282459585232' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115796282459585232'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115796282459585232'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/09/liskov-substitution-in-dynamic.html' title='Liskov Substitution in Dynamic Languages'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-115761819314958395</id><published>2006-09-07T10:36:00.000+02:00</published><updated>2006-09-07T10:36:33.230+02:00</updated><title type='text'>Gmail Tricks</title><content type='html'>&lt;p&gt;found &lt;a href="http://21st.blogspot.com/2006/09/use-gmail-generate-unlimited-e-mail.html"&gt;here&lt;/a&gt;:&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;Gmail has an interesting quirk where you can add a plus sign (+) after your Gmail address, and it'll still get to your inbox. It's called plus-addressing, and it essentially gives you an unlimited number of e-mail addresses to play with. Here's how it works: say your address is pinkyrocks@gmail.com, and you want to automatically label all work e-mails. Add a plus sign and a phrase to make it pinkyrocks+work@gmail.com and set up a filter to label it work (to access your filters go to Settings-&amp;gt;Filters and create a filter for messages addressed to pinkyrocks+work@gmail.com. Then add the label work).&lt;br /&gt;&lt;br /&gt;More real world examples:&lt;br /&gt;&lt;br /&gt;Find out who is spamming you: Be sure to use plus-addressing for every form you fill out online and give each site a different plus address.&lt;br /&gt;&lt;br /&gt;Example: You could use&lt;br /&gt;pinkyrocks+nytimes@gmail.com for nytimes.com&lt;br /&gt;pinkyrocks+freestuff@gmail.com for freestuff.com&lt;br /&gt;Then you can tell which site has given your e-mail address to spammers, and automatically send them to the trash.&lt;br /&gt;&lt;br /&gt;Automatically label your incoming mail: I've talked about that above.&lt;br /&gt;&lt;br /&gt;Archive your mail: If you receive periodic updates about your bank account balance or are subscribed to a lot of mailing lists that you don't check often, then you can send that sort of mail to the archives and bypass your Inbox.&lt;br /&gt;&lt;br /&gt;Example: For the mailing list, you could give pinkyrocks+mailinglist1@gmail.com as your address, and assign a filter that will archive mail to that address automatically. Then you can just check in once in a while on the archive if you want to catch up.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-115761819314958395?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/115761819314958395/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=115761819314958395' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115761819314958395'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115761819314958395'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/09/gmail-tricks.html' title='Gmail Tricks'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-115754923088918996</id><published>2006-09-06T15:27:00.000+02:00</published><updated>2006-09-06T15:27:11.036+02:00</updated><title type='text'>Software Development as Turkey</title><content type='html'>&lt;p&gt;from Darren Hobbs &lt;a href="http://www.darrenhobbs.com/archives/2006/09/yet_another_ana.html"&gt;entry&lt;/a&gt;:&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;You can't achieve the same effect when roasting a turkey by doubling the temperatuire and halving the cooking time. Similarly a project cannot have the number of people doubled and the duration halved and get the same result. The rate of knowledge crunching is not increased by adding more people.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-115754923088918996?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/115754923088918996/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=115754923088918996' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115754923088918996'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115754923088918996'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/09/software-development-as-turkey.html' title='Software Development as Turkey'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-115753610412626270</id><published>2006-09-06T11:48:00.000+02:00</published><updated>2006-09-06T11:48:24.130+02:00</updated><title type='text'>Closures in Java</title><content type='html'>&lt;p&gt;Another post with links.&lt;br /&gt;&lt;br /&gt;From &lt;a href="http://debasishg.blogspot.com/2006/08/closures-in-java-and-other-side-of.html"&gt;Debasish blog&lt;/a&gt;, a link to &lt;a href="http://blogs.sun.com/gbracha/entry/achieving_closure"&gt;Gilad Bracha's blog entry&lt;/a&gt; (with some nice comments)&lt;br /&gt;Pick from post:&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;One question that naturally arises is &amp;quot;what took you so long?&amp;quot;.&lt;br /&gt;...&lt;br /&gt;Since the late 90s, I've brought the topic up now and again. At times, even I have reluctantly been convinced that it is too late, because we've done so many things that would have been easy with closures in different ways. This means the benefits aren't as high as in a language like Scheme, or Self, or Smalltalk. The cost is non-trivial, to be sure.&lt;br /&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Pick from the comments:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;SUN never cared to implement Closures in Java.The reason why they are caring about now is Microsoft introduced them in C#.&lt;br /&gt;&lt;br /&gt;So the funda is IF YOU WANT A NEW FEATURE IN JAVA DONT ASK SUN,(ITS TIME WASTE), BETTER ASK MICROSOFT, ONCE MS IMPLEMENTS THAT FEATURE IN THEIR LANGUAGE, THE NEXT YEAR SUN WILL CONSIDER THAT FEATURE. (This is also the quickest way of getting your favourite feature in JAVA).&lt;/blockquote&gt;&lt;br /&gt;(1st enums, support for dynamic languages, now closures...) :D&lt;br /&gt;&lt;br /&gt;And a link to &lt;a href="http://jaggregate.sourceforge.net/examples.html"&gt;jaggregate examples&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-115753610412626270?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/115753610412626270/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=115753610412626270' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115753610412626270'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115753610412626270'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/09/closures-in-java.html' title='Closures in Java'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-115398640607721186</id><published>2006-07-27T09:46:00.000+02:00</published><updated>2006-07-27T09:46:46.146+02:00</updated><title type='text'>Myths, Lies, and Truths about the Linux kernel</title><content type='html'>&lt;p&gt;Greg Kroah-Hartman's &lt;a href="http://www.kroah.com/log/linux/ols_2006_keynote.html"&gt;slides&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-115398640607721186?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/115398640607721186/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=115398640607721186' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115398640607721186'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115398640607721186'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/07/myths-lies-and-truths-about-linux.html' title='Myths, Lies, and Truths about the Linux kernel'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-115392456917806827</id><published>2006-07-26T16:36:00.000+02:00</published><updated>2006-07-26T16:36:09.186+02:00</updated><title type='text'>Google Tech Talk: Cornelia Brunner - 'On Girls, Boys and IT Careers'</title><content type='html'>&lt;p&gt;&lt;a href="http://video.google.com/videoplay?docid=-9059265454566485886"&gt;google video&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-115392456917806827?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/115392456917806827/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=115392456917806827' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115392456917806827'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115392456917806827'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/07/google-tech-talk-cornelia-brunner-on.html' title='Google Tech Talk: Cornelia Brunner - &apos;On Girls, Boys and IT Careers&apos;'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-115392346203192711</id><published>2006-07-26T16:17:00.000+02:00</published><updated>2006-09-27T05:47:22.953+02:00</updated><title type='text'>Comments in code</title><content type='html'>&lt;p&gt;from wiki: '&lt;a href="http://c2.com/cgi/wiki?ToNeedComments"&gt;to need comments&lt;/a&gt;' and &lt;a href="http://c2.com/cgi/wiki?TooMuchDocumentation"&gt;'too much documentation&lt;/a&gt;'&lt;br /&gt;&lt;br /&gt;C&lt;span style="font-size:10pt; font-family:Arial;"&gt;lass comments - OK.&lt;br /&gt;Method comments - NO&lt;br /&gt;Comments in code - NO&lt;/span&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;If you need a comment to specify the behaviour of an object/method, specify that behaviour in some unit-tests. In that way you get runnable, automatic, one-click behaviour testing. If your test cases have good names, than you won't need to actually read the code in the tests, a brief look at the method names should say how an object/method reacts.&lt;br /&gt;&lt;br /&gt;Tim Ottinger writes &lt;a href="http://butunclebob.com/ArticleS.TimOttinger.ApologizeIncode"&gt;here&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;A comment is an apology for not choosing a more clear name, or a more reasonable set of parameters, or for the failure to use explanatory variables and explanatory functions. Apologies for making the code unmaintainable, apologies for not using well-known algorithms, apologies for writing 'clever' code, apologies for not having a good version control system, apologies for not having finished the job of writing the code, or for leaving vulnerabilities or flaws in the code, apologies for hand-optimizing C code in ugly ways. And documentation comments are no better. In fact, I have my doubts about docstrings.&lt;br /&gt;&lt;br /&gt;If something is hard to understand or inobvious, then someone *ought* to apologize for not fixing it. That's the worst kind of coding misstep. It's okay if I don't really get how something works so long as I know how to use it, and it really does work. But if it's too easy to misuse, you had better start writing. And if you write more comment than code, it serves you right. This stuff is supposed to be useful and maintainable, you know?&lt;br /&gt;&lt;br /&gt;Is there any use of comments that are not apologies? I don't think so. I can't think of one. Is there any good reason to write a comment? Only if you've done something &amp;quot;wrong&amp;quot;.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-115392346203192711?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/115392346203192711/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=115392346203192711' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115392346203192711'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115392346203192711'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/07/comments-in-code.html' title='Comments in code'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-115391120883726902</id><published>2006-07-26T12:53:00.000+02:00</published><updated>2006-07-26T12:53:30.183+02:00</updated><title type='text'>Podcast: Scott Ambler - Advanced Agile Techniques</title><content type='html'>&lt;p&gt;&lt;a href="http://media.techtarget.com/audioCast/TSSCOM/Scott_Ambler-Click_Edits.mp3"&gt;mp3 here&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-115391120883726902?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/115391120883726902/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=115391120883726902' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115391120883726902'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115391120883726902'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/07/podcast-scott-ambler-advanced-agile.html' title='Podcast: Scott Ambler - Advanced Agile Techniques'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-115383859854628374</id><published>2006-07-25T16:43:00.000+02:00</published><updated>2006-07-25T16:43:18.643+02:00</updated><title type='text'>Interview with Andy Hunt - Practices of an Agile Developer</title><content type='html'>&lt;p&gt;&lt;a href="http://perlcast.com/2006/07/12/practices-of-an-agile-developer/"&gt;on perlcast&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-115383859854628374?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/115383859854628374/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=115383859854628374' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115383859854628374'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115383859854628374'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/07/interview-with-andy-hunt-practices-of.html' title='Interview with Andy Hunt - Practices of an Agile Developer'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-115383000013226586</id><published>2006-07-25T14:20:00.000+02:00</published><updated>2006-07-25T14:20:00.353+02:00</updated><title type='text'>no null</title><content type='html'>&lt;p&gt;I've seen too many NullPointerExceptions.&lt;br /&gt;Apparently I am not the only, see &lt;a href="http://www.artima.com/forums/flat.jsp?forum=106&amp;amp;thread=168511"&gt;the post&lt;/a&gt; from Michael Feathers:&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;Passing null in production code is a very bad idea. It’s an example of what I call offensive programming – programming in way that encourages defensive programming. The better way to code is to deal with nulls as soon as they happen and translate them to null objects or exceptions. Unfortunately, &lt;a href="http://goodmath.blogspot.com/2006/05/practical-applications-of-good-math.html"&gt;this isn’t common knowledge&lt;/a&gt;.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Keith Ray explains how it is done in Objective-C:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;In Cocoa / Objective-C programming, I still prefer an empty string over a null pointer, or an empty container-object over a null object, but the language does have a key difference: calling object methods on null-pointers does not normally crash! (But sometimes method parameters being null can cause a crash.)&lt;br /&gt;&lt;br /&gt;Foo* aFoo = nil;&lt;br /&gt;Bar* aResult = [aFoo someMethod: anArgument ];&lt;br /&gt;&lt;br /&gt;calling someMethod (as above) on a nil object DOES NOTHING (it does not crash or throw an exception) and returns nil.&lt;br /&gt;&lt;br /&gt;The Cocoa UI frameworks take advantage of this. For example, the objects that implements a Button or a Menu item would have two members variables: a pointer to an object, and a &amp;quot;selector&amp;quot; that identifies what method to call on the object. The method that handles a click (or whatever) would be written something like this:&lt;br /&gt;&lt;br /&gt;[ targetObject performSelector: actionSelector withArgument: self ];&lt;br /&gt;&lt;br /&gt;instead of like this:&lt;br /&gt;&lt;br /&gt;if ( targetObject != nil ) {&lt;br /&gt;[ targetObject performSelector: actionSelector withArgument: self ];&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;No need to check for a null targetObject. There would be a need to check for a null-selector (in the performSelector:withArgument: method), since the selector isn't actually an object.&lt;br /&gt;&lt;br /&gt;People have objected that null acting like the &amp;quot;null object pattern&amp;quot; hides bugs, but too many times have I gotten web-apps sending me messages that a &amp;quot;null pointer exception has occurred&amp;quot; so I assert that null-pointer exceptions are not helping people find bugs as well as test-driven development, or thorough code-reviews and testing, would do. I expect that if null had the &amp;quot;null object&amp;quot; behavior, the web-app would have returned an partial or empty result rather than a crashing message, and that would be fine for a most users.&lt;br /&gt;&lt;br /&gt;If the &amp;quot;null = null object pattern&amp;quot; behavior is an expected and documented part of the language, it can work quite well. Cocoa and NextStep programmers are, and have been, very productive using a language with this behavior.&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Achileas Margaritis makes a very good point:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;No, the problem with nulls is not their existence, but that there are not separate types.&lt;/blockquote&gt;&lt;br /&gt;This is the real problem: null is no object, you cannot send any message to it (you cannot call any method on it). So if I declare a function: doSomethingWith(Object somethingElse), than it is clear that I expect an object (and null is no object !!!) as argument for the method. (the same goes for the result of a function: object provideSomething()).&lt;br /&gt;&lt;br /&gt;A colleague said that null is like a &amp;quot;joker&amp;quot; when playing cards. Nice metaphor, but null is an &amp;quot;evil&amp;quot; jocker.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-115383000013226586?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/115383000013226586/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=115383000013226586' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115383000013226586'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115383000013226586'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/07/no-null.html' title='no null'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-115375375009161248</id><published>2006-07-24T17:09:00.000+02:00</published><updated>2006-07-24T17:09:10.243+02:00</updated><title type='text'>Misstating the Evidence for Agile and Iterative Development</title><content type='html'>&lt;p&gt;got the &lt;a href="http://www.xprogramming.com/xpmag/misstatingtheevidence.htm"&gt;link&lt;/a&gt; from &lt;a href="http://www.artima.com/forums/flat.jsp?forum=106&amp;thread=167501"&gt;this post&lt;/a&gt; (an interesting read, as well).&lt;br /&gt;and the extra &lt;a href="http://groups.google.com/group/comp.software.extreme-programming/msg/3e2dbddfe3ec9416"&gt;link&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-115375375009161248?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/115375375009161248/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=115375375009161248' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115375375009161248'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115375375009161248'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/07/misstating-evidence-for-agile-and.html' title='Misstating the Evidence for Agile and Iterative Development'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-115271298854232711</id><published>2006-07-12T16:03:00.000+02:00</published><updated>2006-07-12T16:03:08.546+02:00</updated><title type='text'>Java "new" for non-static iinner classes</title><content type='html'>&lt;p&gt;By (over) using non-static inner-classes, I came to the following code:&lt;br /&gt;&lt;br /&gt;InnerClass created = outer_class_instance&lt;strong&gt;.new&lt;/strong&gt; InnerClass(...);&lt;br /&gt;The &amp;quot;new&amp;quot; operator is completely misleading: is no method(message) of the OuterClass.&lt;br /&gt;It just couples the creation to the outer_class_instance scope.&lt;br /&gt;&lt;br /&gt;strange...&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-115271298854232711?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/115271298854232711/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=115271298854232711' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115271298854232711'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115271298854232711'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/07/java-new-for-non-static-iinner-classes.html' title='Java &quot;new&quot; for non-static iinner classes'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-115271268384561531</id><published>2006-07-12T15:58:00.000+02:00</published><updated>2006-07-12T15:58:03.923+02:00</updated><title type='text'>Functional Programming</title><content type='html'>&lt;p&gt;Peter Norvig's &lt;a href="http://www.norvig.com/python-lisp.html"&gt;&amp;quot;Python for Lisp Programmers&lt;/a&gt;&amp;quot;&lt;br /&gt;Another &amp;quot;&lt;a href="http://www.strout.net/python/pythonvslisp.html"&gt;comparison of Python and Lisp&lt;/a&gt;&amp;quot;&lt;br /&gt;James Edward Gray  &lt;a href="http://blog.grayproductions.net/articles/category/higher-order-ruby"&gt;&amp;quot;Higher Order Ruby&lt;/a&gt;&amp;quot;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.lsharp.org/"&gt;Lisp Scripting&lt;/a&gt; for .Net&lt;br /&gt;&lt;a href="http://research.microsoft.com/fsharp/fsharp.aspx"&gt;F# ML/OCaml&lt;/a&gt; variant for .Net (nice sample &lt;a href="http://www.dcooney.com/ViewEntry.aspx?ID=499"&gt;here&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;First feelings:&lt;br /&gt;- Python is more functional than object oriented (watch-out for lambdas cannot contain statements)&lt;br /&gt;- Ruby is more smalltalk-ish (I found it easier to use than Python)&lt;br /&gt;- Lisp is more readble than ML/OCaml&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-115271268384561531?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/115271268384561531/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=115271268384561531' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115271268384561531'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115271268384561531'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/07/functional-programming.html' title='Functional Programming'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-115107455574514667</id><published>2006-06-23T16:55:00.000+02:00</published><updated>2006-06-23T16:55:57.116+02:00</updated><title type='text'>Java 4s</title><content type='html'>&lt;p&gt;Try this in java:&lt;br /&gt;&lt;br /&gt;(4 == 4)&lt;br /&gt;(new Integer(4) == new Integer(4))&lt;br /&gt;&lt;br /&gt;well the first one is true, the second one is false. Why do I need 2 instances of the number (integer) 4 in java I don't know. I couldn't find any example (excuse). After all 4 is immutable, I cannot change it's state, I cannot make a 5 out of it.&lt;br /&gt;&lt;br /&gt;I could say that in Smalltalk, or ruby, where everything is an object, yada, yada.... But Sun &lt;strong&gt;owns&lt;/strong&gt; Java,&lt;br /&gt;they &lt;strong&gt;own&lt;/strong&gt; the &lt;strong&gt;Integer&lt;/strong&gt; class, so when I call the constructor I should always get the &lt;strong&gt;same&lt;/strong&gt; instance.&lt;br /&gt;&lt;br /&gt;and we have the same symptoms (changed behaviour) with booleans:&lt;br /&gt;&lt;br /&gt;(false == false)&lt;br /&gt;(new Boolean(false) == new Boolean(false))&lt;br /&gt;&lt;br /&gt;WTF !? I can have a million false objects in java. And for What? To be garbage collected, from autoboxing/unboxing? How hard is it to create a pool inside the Boolean class and to return always the FALSE object  for Boolean(false) ?&lt;br /&gt;&lt;br /&gt;Finally, there is another guy who feels my pain: &amp;quot;&lt;a href="http://www.ddj.com/184405016"&gt;Java's new Considered Harmful . The problem stems from memory allocation and polymorphsim&lt;/a&gt;&amp;quot;. Well actually he feels more pain, but that's his problem :D&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-115107455574514667?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/115107455574514667/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=115107455574514667' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115107455574514667'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/115107455574514667'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/06/java-4s.html' title='Java 4s'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114977674204551426</id><published>2006-06-08T16:25:00.000+02:00</published><updated>2006-06-08T16:25:44.403+02:00</updated><title type='text'>Google Hiring Strategy</title><content type='html'>&lt;p&gt;Via Peter Norvig, from Google Research Labs: &amp;quot;&lt;a href="http://googleresearch.blogspot.com/2006/03/hiring-lake-wobegon-strategy.html"&gt;The Lake Wobegon Strategy&lt;/a&gt;&amp;quot;.&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114977674204551426?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114977674204551426/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114977674204551426' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114977674204551426'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114977674204551426'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/06/google-hiring-strategy.html' title='Google Hiring Strategy'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114976048026283773</id><published>2006-06-08T11:54:00.000+02:00</published><updated>2006-06-08T11:54:50.046+02:00</updated><title type='text'>Java Generics Aren't</title><content type='html'>&lt;p&gt;Via &lt;a href="http://www.dekorte.com/blog/blog.cgi?do=item&amp;id=1908"&gt;Steve Dekorte&lt;/a&gt;, from &lt;a href="http://www.mindview.net/WebLog/log-0050"&gt;Bruce Eckel&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;em&gt;So&lt;/em&gt; [java]&lt;em&gt; generics are really &amp;quot;autocasting.&amp;quot;&lt;/em&gt;&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114976048026283773?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114976048026283773/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114976048026283773' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114976048026283773'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114976048026283773'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/06/java-generics-arent.html' title='Java Generics Aren&apos;t'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114959384683816889</id><published>2006-06-06T13:37:00.000+02:00</published><updated>2006-06-06T13:38:06.996+02:00</updated><title type='text'>NUllObject and Visitor</title><content type='html'>&lt;p&gt;I have a problem with nulls: they are not objects. I cannot handle a null like any other object: I have to stop, check if it is null or not, and only after that, go on.&lt;br /&gt;&lt;br /&gt;The problem is partially solved by throwing (checked) exception: now I have to handle an exception, instead of a null, which might have been propagated, unseen, unheard, through the stack, god-knows-where.&lt;br /&gt;&lt;br /&gt;To the rescue comes &lt;a href="http://www.c2.com/cgi/wiki?NullObject"&gt;NullObject:&lt;/a&gt; special object, implements the interface, does nothing.&lt;br /&gt;But how do we close the implementation, but still we leave room from improvements: the &lt;a href="http://www.c2.com/cgi/wiki?VisitorPattern"&gt;Visitor&lt;/a&gt;: &amp;quot;&lt;em&gt;Visitor lets you define a new operation without changing the classes of the elements on which it operates&lt;/em&gt;.&amp;quot; (Actually the NullObject should be provided, in my case, by an O/R mapping layer, but I want to extend this object, for my needs). In this case, every &amp;quot;normal&amp;quot; object should do the double dispatching:&lt;br /&gt;&lt;br /&gt;accept(Visitor v) { v.visit(this); }&lt;br /&gt;&lt;br /&gt;only the NullObject should do nothing:&lt;br /&gt;&lt;br /&gt;NullObject.accept(Visitor v) { }&lt;br /&gt;&lt;br /&gt;And in C# where we have delegates, the Visitor could be a function/delegate.&lt;br /&gt;&lt;br /&gt;-- apparently I am not the first one which thought of &lt;a href="http://www.c2.com/cgi/wiki?NullObjectAndVisitor"&gt;NullObject and Visitor&lt;/a&gt;.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114959384683816889?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114959384683816889/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114959384683816889' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114959384683816889'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114959384683816889'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/06/nullobject-visitor.html' title='NUllObject and Visitor'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114890679039382488</id><published>2006-05-29T14:46:00.000+02:00</published><updated>2006-05-29T14:46:30.466+02:00</updated><title type='text'>No Pain, No Gain</title><content type='html'>&lt;p&gt;&lt;a href="https://jmockit.dev.java.net/tutorial.html"&gt;jmockit&lt;/a&gt; is cool, but if &amp;quot;hacking&amp;quot; around a clean solution is so easy, when are we going to learn to avoid &lt;a href="http://butunclebob.com/ArticleS.MichaelFeathers.ItsTimeToDeprecateFinal"&gt;final classes&lt;/a&gt;, and API calls (&amp;quot;&lt;a href="http://www.objectmentor.com/resources/bookstore/books/welc/"&gt;My Application Is All API Calls&lt;/a&gt;&amp;quot;), when are we going to refactor our code to a clean OO solution: &lt;strong&gt;objects&lt;/strong&gt; represent roles/responsabilities (&lt;a href="http://www.c2.com/cgi/wiki?SingleResponsibilityPrinciple"&gt;one-to-one relationship&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;If you are climber, you take care of your equipment, you don't ducktape your cord !!!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114890679039382488?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114890679039382488/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114890679039382488' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114890679039382488'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114890679039382488'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/05/no-pain-no-gain.html' title='No Pain, No Gain'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114848455602523642</id><published>2006-05-24T17:29:00.000+02:00</published><updated>2006-05-24T17:29:16.030+02:00</updated><title type='text'>Play And Learn</title><content type='html'>&lt;p&gt;from &lt;a href="http://www.rubyquiz.com/"&gt;RubyQuiz&lt;/a&gt; you could learn something about &lt;a href="http://www.rubyquiz.com/quiz70.html"&gt;the use of continuations and Amb operator for Constraint Processing&lt;/a&gt;. This is so much fun !!!&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114848455602523642?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114848455602523642/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114848455602523642' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114848455602523642'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114848455602523642'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/05/play-and-learn.html' title='Play And Learn'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114848393229052222</id><published>2006-05-24T17:18:00.000+02:00</published><updated>2006-05-24T17:18:52.300+02:00</updated><title type='text'>Arc Suggestions</title><content type='html'>&lt;blockquote&gt;&lt;br /&gt;    &lt;p&gt;Paul Graham posted the collected suggestions for (his) &amp;quot;new Lisp&amp;quot; &lt;a href="http://www.archub.org/arcsug.txt"&gt;here&lt;/a&gt;. Some nice points: concurrency continuations, OO, macros... But I liked:&lt;br /&gt;&lt;br /&gt;*** Dan Milstein: Concurrency&lt;br /&gt;&lt;br /&gt;One problem which, IMHO, no popular language has come even&lt;br /&gt;close to solving well is allowing a programmer to write multithreaded&lt;br /&gt;code. This is particularly important in server-side programming, one of&lt;br /&gt;Arc's major targets. I've written a good deal of multithreaded Java, and&lt;br /&gt;the threading model is deeply, deeply wrong. As a programmer, there's&lt;br /&gt;almost no one way to write the kind of abstractions which let you forget&lt;br /&gt;about the details. You're always sitting there, trying to work through&lt;br /&gt;complicated scenarios in your head, visualizing the run-time structure of&lt;br /&gt;your program.&lt;br /&gt;&lt;br /&gt;I didn't see another way until I read John H. Reppy's &amp;quot;Concurrent&lt;br /&gt;Programming in ML&amp;quot;. Instead of building his concurrency constructs around&lt;br /&gt;monitored access to shared memory, he builds them around a message passing&lt;br /&gt;model (both synchronous and asynchronous). What's more, he provides&lt;br /&gt;powerful means of capturing a concurrent pattern in an abstraction which&lt;br /&gt;hides the details.&lt;br /&gt;&lt;br /&gt;I highly recommend giving that book a read. Here's an example of some of&lt;br /&gt;what you get (not the abstraction, actually, just the basic power of&lt;br /&gt;message-passing over shared memory). The abstraction facilities are&lt;br /&gt;complex enough that, like Lisp macros, a small example doesn't really&lt;br /&gt;capture their power. I'm in no way familiar with concurrent extensions to&lt;br /&gt;Lisp, so I'm not able to provide the code for how much harder it would be&lt;br /&gt;in CL or Scheme. Assuming they were augmented with a shared memory model&lt;br /&gt;(as Java is), which forces the programmer to deal with synchrnoized access&lt;br /&gt;to memory, I can only imagine it would be significantly more complex.&lt;br /&gt;&lt;br /&gt;A producer/consumer buffer. You want a buffer with a finite number of&lt;br /&gt;cells. If a producer tries to add an element to a full buffer, it should&lt;br /&gt;block until a consumer removes an element. If a consumer tries to remove&lt;br /&gt;an element from an empty buffer, it should block until a producer adds&lt;br /&gt;something.&lt;br /&gt;&lt;br /&gt;In Concurrent ML:&lt;br /&gt;&lt;br /&gt;datatype 'a buffer = BUF of {&lt;br /&gt; insCh : 'a chan,&lt;br /&gt; remCh : 'a chan&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;fun buffer () = let &lt;br /&gt; val insCh = channel() and remCh = channel()&lt;br /&gt;&lt;br /&gt; fun loop [] = loop [recv inCh]&lt;br /&gt; | loop buf = if (length buf &amp;gt; maxlen)&lt;br /&gt; then (send (remCh, hd buf); loop (tl, buf))&lt;br /&gt; else (select remCh!(hd buf) =&amp;gt; loop (tl buf)&lt;br /&gt; or insCh?x =&amp;gt; loop (buf @ [x]))&lt;br /&gt;&lt;br /&gt; in&lt;br /&gt; spawn loop;&lt;br /&gt; BUF{&lt;br /&gt; insCh = insCh,&lt;br /&gt; remCh = remCh&lt;br /&gt; }&lt;br /&gt; end&lt;br /&gt;&lt;br /&gt;fun insert (BUF{insCh, ...}, v) = send (insCh, v)&lt;br /&gt;&lt;br /&gt;fun remove (BUF{remCh, ...}) = recv remCh&lt;br /&gt;&lt;br /&gt;---------------&lt;br /&gt;&lt;br /&gt;Translated into a Lisp-ish syntax (very easy to do from ML), this would&lt;br /&gt;look something like:&lt;br /&gt;&lt;br /&gt;(defstruct buffer&lt;br /&gt; ins-ch&lt;br /&gt; rem-ch)&lt;br /&gt;&lt;br /&gt;(defun create-buffer ()&lt;br /&gt; (let ((ins-ch (make-channel))&lt;br /&gt; (rem-ch (make-channel)))&lt;br /&gt; (labels ((loop (buf)&lt;br /&gt; (cond ((null buf)&lt;br /&gt; (loop (list (recv ins-ch))))&lt;br /&gt; ((&amp;gt; (length buf) maxlen)&lt;br /&gt; (send rem-ch (car buf))&lt;br /&gt; (loop (cdr buf)))&lt;br /&gt; (t&lt;br /&gt; (select &lt;br /&gt; (rem-ch ! (car buf) =&amp;gt; (loop (cdr buf)))&lt;br /&gt; (ins-ch ? x =&amp;gt; (loop (append buf (list x)))))))))&lt;br /&gt; (spawn #'loop)&lt;br /&gt; (make-buffer :ins-ch ins-ch :rem-ch rem-ch))))&lt;br /&gt;&lt;br /&gt;(defun insert (b v)&lt;br /&gt; (send (buffer-ins-ch b) v))&lt;br /&gt;&lt;br /&gt;(defun remove (b)&lt;br /&gt; (recv (buffer-rem-ch b)))&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Key things to notice:&lt;br /&gt;&lt;br /&gt;1) Language features:&lt;br /&gt;&lt;br /&gt;Communication between threads *only* occurs over channel objects, which can&lt;br /&gt;be thought of as one-element queues. In CML, channels are typed, but in&lt;br /&gt;Lisp they probably wouldn't be.&lt;br /&gt;&lt;br /&gt;send/recv: synchronous (blocking) communication over the channel. A thread&lt;br /&gt;can attempt to send an object over the channel, and will then block until&lt;br /&gt;another thread does a recv on the channel.&lt;br /&gt;&lt;br /&gt;Creating a new thread is done via 'spawn', which takes a function as its&lt;br /&gt;argument. (I can't remember what the signature of that function is&lt;br /&gt;supposed to be -- clearly, in this case it can't be a function of no&lt;br /&gt;arguments, but imagine it to be something like that).&lt;br /&gt;&lt;br /&gt;Selective communication: the call to 'select' is one of the very powerful&lt;br /&gt;features. It is like a concurrent conditional -- it simultaneously blocks&lt;br /&gt;on a list of send/recv calls, and executes the associated code with&lt;br /&gt;whichever call returns first (and then drops the rest of the calls). The !&lt;br /&gt;syntax means an attempt to send, the ? means an attempt to receieve. In&lt;br /&gt;both cases, the '=&amp;gt;' connects the associated code to execute. (I haven't&lt;br /&gt;really come up with a Lispy translation of that syntax).&lt;br /&gt;&lt;br /&gt;I don't think select could be efficiently implemented without language&lt;br /&gt;support. It requires a sort of 'partial blocking', which is tricky to&lt;br /&gt;implement on top of normal blocking.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2) The Idiom&lt;br /&gt;&lt;br /&gt;The buffer is implemented as a separate thread which has connections to two&lt;br /&gt;channels and an internal list to keep track of the elements of the buffer.&lt;br /&gt;This thread runs through a loop forever, taking the current state of the&lt;br /&gt;buffer as its argument, and waiting on the channels in the body of its&lt;br /&gt;code. It is tail-recursive.&lt;br /&gt;&lt;br /&gt;Note the absolute lack of any code to deal with synchronization or locking.&lt;br /&gt;You might notice the inefficient list mechanism (that append is going to&lt;br /&gt;get costly in terms of new cons cells), and think that this is only safe&lt;br /&gt;code because of the inefficient functional programming style. In fact,&lt;br /&gt;that's not true! The 'loop' function could desctructively modify a list&lt;br /&gt;(or array) to which only it had access. There would still be no potential&lt;br /&gt;for sync'ing problems, since only that one thread has access to the&lt;br /&gt;internal state of the buffer, and it automatically syncs on the sends and&lt;br /&gt;receieves. It's only handling one request at a time, automatically, so it&lt;br /&gt;can do whatever it wants during that time. It could even be safely&lt;br /&gt;rewritten as a do loop.&lt;br /&gt;&lt;br /&gt;What I find so enormously powerful and cool about this is that the&lt;br /&gt;programmer doesn't need to worry about the run-time behavior of the system&lt;br /&gt;at all. At all. The lexical structure of the system captures the run-time&lt;br /&gt;behavior -- if there is mutating code inside of the 'loop' function, you&lt;br /&gt;don't have to look at every other function in the file to see if it is&lt;br /&gt;maybe modifying that same structure. This is akin to the power of lexical&lt;br /&gt;scoping over global scoping. I have never seen concurrent code which lets&lt;br /&gt;me ignore so much.&lt;br /&gt;&lt;br /&gt;This really just scratches the surface of Concurrent ML (and doesn't touch&lt;br /&gt;on the higher-level means of abstraction). But I hope it gives a sense of&lt;br /&gt;how worthwhile a language it is to learn from.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3) Issues&lt;br /&gt;&lt;br /&gt;I think that channels themselves would be fairly easy to implement on top&lt;br /&gt;of the usual operating system threading constructs (without needing a&lt;br /&gt;thread for each one). However, the style which this message-passing model&lt;br /&gt;promotes can easily lead to a *lot* of threads -- if you have a lot of&lt;br /&gt;buffers, and each of them has its own thread, things can get out of hand&lt;br /&gt;quickly. I believe that Mr. Reppy has explored these very issues in his&lt;br /&gt;implementation of CML.&lt;br /&gt;&lt;br /&gt;http://cm.bell-labs.com/cm/cs/who/jhr/sml/cml/&lt;br /&gt;&lt;br /&gt;Insofar as I have time (which, realistically, I don't) I would love nothing&lt;br /&gt;more than to play around with implementing CML'ish concurrency constructs&lt;br /&gt;in a new version of Lisp like Arc.&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114848393229052222?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114848393229052222/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114848393229052222' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114848393229052222'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114848393229052222'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/05/arc-suggestions.html' title='Arc Suggestions'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114848359628459277</id><published>2006-05-24T17:13:00.000+02:00</published><updated>2006-05-24T17:13:17.060+02:00</updated><title type='text'>Google engEDU</title><content type='html'>&lt;p&gt;&lt;a href="http://video.google.com/videosearch?q=google+engEDU&amp;page=1&amp;lv=1&amp;so=1"&gt;A list&lt;/a&gt; with &amp;quot;all&amp;quot; (!?) educational videos from google&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114848359628459277?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114848359628459277/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114848359628459277' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114848359628459277'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114848359628459277'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/05/google-engedu.html' title='Google engEDU'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114839942904336086</id><published>2006-05-23T17:50:00.000+02:00</published><updated>2006-05-23T17:50:30.880+02:00</updated><title type='text'>One More Thing</title><content type='html'>&lt;p&gt;I really enjoyed the &amp;quot;Behaviour Driven Development&amp;quot; &lt;a href="http://video.google.com/videosearch?q=Behaviour+Driven+Development"&gt;presentation&lt;/a&gt; which Dave Astels did at Google. And here is the &amp;quot;one more thing&amp;quot;:&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;    &lt;p&gt;&amp;quot;I always thought that Smalltalk would beat Java, I just didn't know  it would be called 'Ruby' when it did.&amp;quot; - Kent Beck&lt;/p&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114839942904336086?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114839942904336086/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114839942904336086' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114839942904336086'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114839942904336086'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/05/one-more-thing.html' title='One More Thing'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114830027599068863</id><published>2006-05-22T14:17:00.000+02:00</published><updated>2006-05-22T14:17:56.070+02:00</updated><title type='text'>Speed Kills</title><content type='html'>&lt;p&gt;Found an &lt;a href="http://butunclebob.com/ArticleS.UncleBob.SpeedKills"&gt;UncleBob's blog entry&lt;/a&gt;:&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;    &lt;p&gt;Speed is the prime destroyer of software systems. In our rush to get something to execute we make mess upon mess. We push and shove the code around in a frenzied effort to make something work. And then, once we achieve the desired behavior, we consider ourselves to be done, and move on to the next urgent task.&lt;br /&gt;&lt;br /&gt;Of course we all realize that this is self-destructive behavior. We know that the more we rush the deeper the messes become, and the slower and slower we will go. We know that the only way to keep development going fast is to work carefully, deliberately, and slowly. We know that if we do this, we will keep our systems clean and well structured. We know that clean and well structured systems are easy to change. We know this. Yet we find it difficult to act on this knowledge. &lt;br /&gt;&lt;br /&gt;The traditional productivity curve for software projects is a sigmoid. It starts very high, and remains high for the first few months. This is the honeymoon period when the team is cranking. They get lots of good work done, and they get it done quickly. But then the messes begin to build. Those messes slow us down. The productivity curve enters a steep and sudden decline. A few months later productivity has bottomed out and asymptotically approaches zero. This is the phase of the project where it takes forever to do even the simplest thing. This is the phase of the project in which the smallest possible estimate is 3 weeks or more. &lt;br /&gt;&lt;br /&gt;As productivity slows to a near halt, the business responds in the only way it can - it adds more people to the project in the forlorn hope of increasing productivity. But these new people, eager to please their employers and peers, continue to rush, thereby adding even more corruption to the existing steaming pile. Productivity continues to decline as the sigmoid approaches zero at the limit.&lt;br /&gt;&lt;br /&gt;The solution to this nearly ubiquitous problem is to act upon what we already know. That speed kills projects. &lt;strong&gt;Slow down. Do a good job. Keep the code clean. Write unit tests. Write acceptance tests. And watch how fast you go!&lt;/strong&gt;&lt;/p&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114830027599068863?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114830027599068863/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114830027599068863' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114830027599068863'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114830027599068863'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/05/speed-kills.html' title='Speed Kills'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114815765675930300</id><published>2006-05-20T22:40:00.000+02:00</published><updated>2006-05-20T22:43:35.650+02:00</updated><title type='text'>Saturday Reading</title><content type='html'>&lt;p&gt;actually watching videos, from TechTalk@Google&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Peter Seibel, &amp;quot;&lt;a href="http://video.google.com/videosearch?q=practical+common+lisp"&gt;Practical Common Lisp&lt;/a&gt;&amp;quot;:&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;    &lt;p&gt;In the late 1920's linguists Edward Sapir and Benjamin Whorf hypothesized that the thoughts we can think are largely determined by the language we speak. In his essay &amp;quot;Beating the Averages&amp;quot; Paul Graham echoed this notion and invented a hypothetical language, Blub, to explain why it is so hard for programmers to appreciate programming language features that aren't present in their own favorite language. Does the Sapir-Whorf hypothesis hold for computer languages? Can you be a great software architect if you only speak Blub? Doesn't Turing equivalence imply that language choice is just another implementation detail? Yes, no, and no says Peter Seibel, language lawyer (admitted, at various times, to the Perl, Java, and Common Lisp bars) and author of the award-winning book _Practical Common Lisp_. In his talk, Peter will discuss how our choices of programming language influences and shapes our pattern languages and the architectures we can, or are likely to, invent. He will also discuss whether it's sufficient to merely broaden your horizons by learning different programming languages or whether you must actually use them.&lt;/p&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;Dave Astels, &amp;quot;&lt;a href="http://video.google.com/videosearch?q=Behaviour+Driven+Development"&gt;Beyond Test Driven Development: Behaviour Driven Development&lt;/a&gt;&amp;quot;:&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;    &lt;p&gt;Test Driven Development (TDD) has become quite well known. Many developers are getting benefit from the practice. But it is possible that we can get even more value. A new practice is getting attention these days: Behaviour Driven Development (BDD).&lt;br /&gt;&lt;br /&gt;BDD removes all vestiges of testing and instead focuses on specifying the behaviour desired in the system being built. This talk will be focus on Ruby and will introduce a new BDD framework: rSpec. The ideas, however, are language independent&lt;/p&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114815765675930300?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114815765675930300/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114815765675930300' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114815765675930300'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114815765675930300'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/05/saturday-reading.html' title='Saturday Reading'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114785477793890782</id><published>2006-05-17T10:32:00.000+02:00</published><updated>2006-05-17T10:32:58.066+02:00</updated><title type='text'>Architects Must Write Code</title><content type='html'>&lt;p&gt;I found a blog entry &lt;a href="http://www.jrothman.com/weblog/2006/04/architects-must-write-code.html"&gt;here&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The comments are pretty interesting:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Bell-Labs has a pattern repository: &lt;a href="http://www.bell-labs.com/cgi-user/OrgPatterns/OrgPatterns?WebIndex"&gt;WebInde of OrgPatterns&lt;/a&gt; (see ArchitectAlsoImplements, DevelopingInPairs).And my favorite:&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;    &lt;p&gt;Architecture, like war plans, do not last longer than the first minute of the battle: the architect must be in the front line, coding, spiking, re-architecturing...&lt;/p&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114785477793890782?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114785477793890782/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114785477793890782' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114785477793890782'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114785477793890782'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/05/architects-must-write-code.html' title='Architects Must Write Code'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114777879563496055</id><published>2006-05-16T13:26:00.000+02:00</published><updated>2006-05-16T15:16:13.013+02:00</updated><title type='text'>Working Effectively with Legacy Code III</title><content type='html'>&lt;p&gt;Jeremy D. Miller has some &lt;a href="http://codebetter.com/blogs/jeremy.miller/archive/2006/05/04/144032.aspx"&gt;notes&lt;/a&gt; about the &lt;a href="http://www.objectmentor.com/resources/bookstore/books/welc/"&gt;book&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Tip #1: Yes, go buy the book, and put it next to &amp;quot;Refactoring&amp;quot; (you know: beware of &lt;a href="http://c2.com/cgi/wiki?CodeSmell"&gt;code smells&lt;/a&gt;)&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Tip #2: &lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;    &lt;p&gt;On most of the XP projects I've been on we've used an &amp;quot;Idea Wall,&amp;quot; just a visible place to write down or post technical improvements.  Anytime we have some slack time we start pulling down tasks from the idea wall.  Occasionally we're able to outpace either testing or requirements analysis and we aren't really able to push any new code.  Whenever that happens we immediately pull things off of the idea wall.  One way to judge if your technical debt is piling up is to watch how crowded the idea wall is getting.  On the other hand, if something stays on the idea wall for a long time, it might not be that important after all.&lt;/p&gt;&lt;br /&gt;    &lt;p&gt;&lt;strong&gt;Design never stops&lt;/strong&gt;, not even for an older codebase&lt;/p&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114777879563496055?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114777879563496055/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114777879563496055' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114777879563496055'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114777879563496055'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/05/working-effectively-with-legacy-code.html' title='Working Effectively with Legacy Code III'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114736158588850677</id><published>2006-05-11T17:33:00.000+02:00</published><updated>2006-05-11T17:33:06.406+02:00</updated><title type='text'>nice</title><content type='html'>&lt;p&gt;&lt;a href="http://www.rense.com/general67/street.htm"&gt;Virtual Street Reality&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114736158588850677?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114736158588850677/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114736158588850677' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114736158588850677'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114736158588850677'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/05/nice.html' title='nice'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114735897347428270</id><published>2006-05-11T16:49:00.000+02:00</published><updated>2006-05-11T16:50:29.486+02:00</updated><title type='text'>Martin Fowler evaluates Ruby</title><content type='html'>&lt;p&gt;&lt;a href="http://martinfowler.com/bliki/EvaluatingRuby.html"&gt;here&lt;/a&gt;:&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;    &lt;p&gt;It's still early days yet, but I now have a handful of project experiences to draw on. So far the results are firmly in favor of Ruby. When I ask the question &amp;quot;do you think you're significantly more productive in Ruby rather than Java/c#&amp;quot;, each time I've got a strong 'yes'. This is enough for me to start saying that for a suitable project, you should give Ruby a spin. Which, of course, only leaves open the small question of what counts as 'suitable'.&lt;/p&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;Is Smalltalk (sorry, I meant ruby) having a coming back?&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114735897347428270?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114735897347428270/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114735897347428270' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114735897347428270'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114735897347428270'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/05/martin-fowler-evaluates-ruby.html' title='Martin Fowler evaluates Ruby'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114727500147520876</id><published>2006-05-10T17:30:00.000+02:00</published><updated>2006-05-10T17:30:01.570+02:00</updated><title type='text'>Lambda the Ultimate - thread</title><content type='html'>&lt;p&gt;&lt;a href="http://lambda-the-ultimate.org/node/1439#comment"&gt;What do you believe about Programming Languages (that you can't prove (yet))&lt;/a&gt;?&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Interesting thread.You can find some nice gems, in the flame-war dirt.&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114727500147520876?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114727500147520876/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114727500147520876' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114727500147520876'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114727500147520876'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/05/lambda-ultimate-thread.html' title='Lambda the Ultimate - thread'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114725785830019205</id><published>2006-05-10T12:44:00.000+02:00</published><updated>2006-05-10T12:44:18.403+02:00</updated><title type='text'>Should Mock Objects be considered harmful?</title><content type='html'>&lt;p&gt;&lt;a href="http://www.advogato.org/person/robertc/"&gt;Robert Collins&lt;/a&gt; asks the question:&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;    &lt;p&gt;Should Mock Objects be considered harmful? As an optimisation for test suites they are convenient, but they mean you are not testing against the something which can be verified to behave as the concrete interface is meant to, which can lead to Interface Skew.&lt;/p&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;Let's says we have an object A which uses an object B. In OO A and B represent roles: object A does something in collaboration with B. A behaves &amp;quot;right&amp;quot; only if B behaves &amp;quot;right&amp;quot;. So we have a behaviour contract between A and B. This normally represented by some unit-tests for the B role which specify its behaviour. Based on that, we can test A: we &amp;quot;mock&amp;quot; the B role, and see how A reacts. If we want to keep our implementation clean, A knows nothing about B implmentation, it knows only about its behaviour. (B is an interface, or A and B are implemented in a dynamic language).&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Once we have tested B's behaviour and A's behaviour they &amp;quot;should&amp;quot; work together without errors. This doesn't happen: usually B is not throughly tested, the behviour contract is broken. for this case we should have integration-tests: A and B play nicely together.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Testing.Kata: unit-test role B, unit-test role A, integration test A and B. &lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114725785830019205?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114725785830019205/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114725785830019205' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114725785830019205'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114725785830019205'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/05/should-mock-objects-be-considered.html' title='Should Mock Objects be considered harmful?'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114709616611687909</id><published>2006-05-08T15:49:00.000+02:00</published><updated>2006-05-08T15:49:26.186+02:00</updated><title type='text'>Getters And Setters are Evil</title><content type='html'>&lt;p&gt;Setters are evil because they allow you to have inconsistent objects, which they cannot work until they have set their collaborators (see &lt;a href="http://www.picocontainer.org/Good+Citizen"&gt;PicoContainer/Good Citizen&lt;/a&gt;).&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Getters are evil because they allow you to extract the data from the object, instead of putting the action where the data is. (see &lt;a href="http://thought-tracker.blogspot.com/2006/05/violating-encapsulation.html"&gt;violating encapsulation&lt;/a&gt;, or Martin Fowler's &lt;a href="http://www.martinfowler.com/bliki/GetterEradicator.html"&gt;&amp;quot;GetterEradicator&lt;/a&gt;&amp;quot;).&lt;/p&gt;&lt;br /&gt;&lt;p&gt;So everything goes round and back to Allen Holub: &amp;quot;&lt;a href="http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html"&gt;Why getter and setter methods are evil&lt;/a&gt;&amp;quot;. &lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114709616611687909?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114709616611687909/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114709616611687909' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114709616611687909'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114709616611687909'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/05/getters-and-setters-are-evil.html' title='Getters And Setters are Evil'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114674566187455959</id><published>2006-05-04T14:27:00.000+02:00</published><updated>2006-05-04T14:27:41.876+02:00</updated><title type='text'>Violating Encapsulation</title><content type='html'>&lt;p&gt;Dave Astels blogs &lt;a href="http://blog.daveastels.com/articles/2005/10/16/violating-encapsulation"&gt;about it&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;    &lt;p&gt;Something I see all the time, on every team I've been involved with, is code like the following (classes are generalized from examples):&lt;br /&gt;&lt;br /&gt;MyThing[] things = thingManager.getThingList();&lt;br /&gt;for (int i = 0; i &amp;lt; things.length; i++) {&lt;br /&gt; MyThing thing = things[i];&lt;br /&gt; if (thing.getName().equals(thingName)) {&lt;br /&gt; return thingManager.delete(thing);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;This code is tightly coupled to the implementation of myThing in that it gets the name property, knows that it's a string, etc. This is a classic approach from the old days or procedural programming. It is NOT OO.&lt;br /&gt;&lt;br /&gt;How about:&lt;br /&gt;&lt;br /&gt;MyThing[] things = thingManager.getThingList();&lt;br /&gt;for (int i = 0; i &amp;lt; things.length; i++) {&lt;br /&gt; MyThing thing = things[i];&lt;br /&gt; if (thing.isNamed(thingName)) {&lt;br /&gt; return thingManager.delete(thing);&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;p&gt;I've seen this procedural approach thousand times. The problem is that a lot of developers think &amp;quot;procedural&amp;quot;: they never met smalltalk/lisp with its closures. That's why learning a new programming language is good: you will think different, even if you will never get a chance to use the &amp;quot;newly acquired&amp;quot; programming language.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114674566187455959?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114674566187455959/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114674566187455959' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114674566187455959'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114674566187455959'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/05/violating-encapsulation.html' title='Violating Encapsulation'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114674410815020412</id><published>2006-05-04T14:01:00.000+02:00</published><updated>2006-05-04T14:01:48.200+02:00</updated><title type='text'>Startup School</title><content type='html'>&lt;p&gt;Paul Graham on &amp;quot;&lt;a href="http://www.paulgraham.com/startuplessons.html"&gt;the hardest lessons for startups to learn&lt;/a&gt;&amp;quot;.&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114674410815020412?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114674410815020412/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114674410815020412' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114674410815020412'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114674410815020412'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/05/startup-school.html' title='Startup School'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114666696465822565</id><published>2006-05-03T16:36:00.000+02:00</published><updated>2006-05-03T16:36:04.666+02:00</updated><title type='text'>java class loading</title><content type='html'>&lt;p&gt;Andrew C. Oliver &lt;a href="http://linuxintegrators.com/acoliver/code/?permalink=x-242.html"&gt;hates it&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114666696465822565?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114666696465822565/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114666696465822565' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114666696465822565'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114666696465822565'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/05/java-class-loading.html' title='java class loading'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114642042481972434</id><published>2006-04-30T20:07:00.000+02:00</published><updated>2006-04-30T20:07:04.903+02:00</updated><title type='text'>To interface or not to interface</title><content type='html'>&lt;p&gt;I've posted some comments on Troy Brumley's blog &lt;a href="http://www.cincomsmalltalk.com/userblogs/troy/blogView?showComments=true&amp;amp;entry=3323626570"&gt;here&lt;/a&gt; . He liked the metaphor interface is a &amp;quot;firewall&amp;quot;: we use it in order to isolate &amp;quot;changes&amp;quot;: I don't want to be affected by your changes, and you don't want to be affected by my changes.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Actually an interface is a &amp;quot;wall&amp;quot;, a very thin layer, which hides implementation details. And we should use is at framework, package and object level. In practice it doesn't happen: we &amp;quot;trust&amp;quot; our object within an package, or within a framework. &lt;/p&gt;&lt;br /&gt;&lt;p&gt;An interface defines a &amp;quot;contract&amp;quot;: somebody understands this set of messages. Why don't we have interfaces in dynamic languages? Because we don't need this wall, we are always talking to a &lt;a href="http://www.rubygarden.org/ruby?DuckTyping"&gt;duck&lt;/a&gt;.The implementation is always hidden.The contract  resides in the UnitTests.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114642042481972434?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114642042481972434/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114642042481972434' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114642042481972434'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114642042481972434'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/04/to-interface-or-not-to-interface.html' title='To interface or not to interface'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114640174513850228</id><published>2006-04-30T14:55:00.000+02:00</published><updated>2006-05-02T20:02:36.710+02:00</updated><title type='text'>Qumana</title><content type='html'>&lt;p&gt;I tried to download wbloggar, but the site is down. Let's see how is this working...&lt;/p&gt;&lt;br /&gt;&lt;p style="color:#008;text-align:right;"&gt;&lt;small&gt;&lt;em&gt;Powered by&lt;/em&gt; &lt;a href="http://www.qumana.com/"&gt;Qumana&lt;/a&gt;&lt;/small&gt;&lt;/p&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114640174513850228?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114640174513850228/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114640174513850228' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114640174513850228'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114640174513850228'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/04/qumana.html' title='Qumana'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114560609720645979</id><published>2006-04-21T09:33:00.000+02:00</published><updated>2006-04-21T09:54:57.226+02:00</updated><title type='text'>Before and After Ruby</title><content type='html'>found on the "&lt;a href="http://use.perl.org/%7Ejesse/journal/29381"&gt;journal of jess&lt;/a&gt;".&lt;br /&gt;&lt;br /&gt;Also Torsten is wondering &lt;a href="http://astares.blogspot.com/2006/03/beyond-java-buzz.html"&gt;here&lt;/a&gt;: &lt;span style="font-style: italic;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-style: italic;"&gt;What I dont understand is that people complain about Java and start with Ruby right after it.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;What if they would take the next step and directly start using Smalltalk. I'm sure they will enjoy the wonderfull world full of objects&lt;/span&gt;.&lt;br /&gt;&lt;/blockquote&gt;Well I think that Smalltalk environment is too scary for a java developer: no code files, no cvs/subversion, everything is in an image file, etc.&lt;br /&gt;&lt;br /&gt;When a java developer plunges in Smalltalk, he has a "&lt;span style="font-style: italic;"&gt;What now&lt;/span&gt;" &lt;span style="font-style: italic;"&gt;moment&lt;/span&gt;: everything is there, but he does not know where to start.&lt;br /&gt;&lt;br /&gt;Ruby  is the "way" to Smalltalk: easier to learn, but OO imperfect (ruby has "syntax" and not everything is an object)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114560609720645979?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114560609720645979/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114560609720645979' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114560609720645979'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114560609720645979'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/04/before-and-after-ruby.html' title='Before and After Ruby'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114539724067005809</id><published>2006-04-18T23:51:00.000+02:00</published><updated>2006-04-26T11:13:28.023+02:00</updated><title type='text'>The Quality of Many Eyes</title><content type='html'>&lt;a href="http://kerneltrap.org/node/6492"&gt;here&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-style: italic;"&gt;Linux kernel development model implies that the developers can't directly add their changes to the main code branch, but publish their changes. Other developers can review and provide comments, and, more importantly, there is a dedicated person who reviews all the changes, asks for corrections or clarifications, and finally incorporates the changes into the main code branch. This model is extremely rare in producing commercial software, and in the open source software world only some projects use it. Linux kernel has been using this model from the beginning quite effectively.&lt;/span&gt;&lt;br /&gt; &lt;/blockquote&gt;Raise your hand: Who's doing code-reviews? Who's doing pair-programming?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114539724067005809?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114539724067005809/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114539724067005809' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114539724067005809'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114539724067005809'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/04/quality-of-many-eyes.html' title='The Quality of Many Eyes'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114513946870113074</id><published>2006-04-16T00:15:00.000+02:00</published><updated>2006-04-16T00:17:48.716+02:00</updated><title type='text'>saturday reading</title><content type='html'>&lt;a href="http://steve-yegge.blogspot.com/2006/04/lisp-is-not-acceptable-lisp.html"&gt;Lisp is Not an Acceptable Lisp&lt;/a&gt;&lt;br /&gt;and&lt;br /&gt;&lt;a href="http://www.codeartist.org/archive/Steve%20is%20not%20an%20acceptable%20Lisper%251JGXTPI%2DM6M9R8.html"&gt;Steve is Not an Acceptable Lisper&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;from &lt;a href="http://reddit.com/"&gt;reddit&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114513946870113074?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114513946870113074/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114513946870113074' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114513946870113074'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114513946870113074'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/04/saturday-reading_16.html' title='saturday reading'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114503549219602834</id><published>2006-04-14T19:22:00.000+02:00</published><updated>2006-04-14T19:24:52.210+02:00</updated><title type='text'>Smalltalk Flexible Exception Handling</title><content type='html'>&lt;a href="http://www.cincomsmalltalk.com/blog/blogView?showComments=true&amp;amp;entry=3321788777"&gt;when *everything* is an object&lt;/a&gt;&lt;br /&gt;- via James Robertson&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114503549219602834?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114503549219602834/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114503549219602834' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114503549219602834'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114503549219602834'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/04/smalltalk-flexible-exception-handling.html' title='Smalltalk Flexible Exception Handling'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114482928930940847</id><published>2006-04-12T10:06:00.000+02:00</published><updated>2006-04-12T10:08:09.326+02:00</updated><title type='text'>Ruby and Lisp</title><content type='html'>found &lt;a href="http://www.jasani.org/articles/trackback/112"&gt;here&lt;/a&gt;:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;/code&gt;&lt;blockquote&gt;&lt;code&gt;So, Ruby was a Lisp originally, in theory.&lt;br /&gt;Let's call it MatzLisp from now on. ;-)&lt;br /&gt;&lt;/code&gt;– Matz&lt;/blockquote&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;code&gt;Larry Wall never understood Lisp&lt;br /&gt;Guido Van Rossum once read a book on Lisp&lt;br /&gt;Yukihiro Matsumoto once read a book on Lisp and understood some of it&lt;br /&gt;&lt;/code&gt;– Keith Playford&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114482928930940847?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114482928930940847/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114482928930940847' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114482928930940847'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114482928930940847'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/04/ruby-and-lisp.html' title='Ruby and Lisp'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114475176518030764</id><published>2006-04-11T12:15:00.000+02:00</published><updated>2006-04-11T12:36:05.213+02:00</updated><title type='text'>Code Generation</title><content type='html'>Bill Veners &lt;a href="http://www.artima.com/weblogs/viewpost.jsp?thread=152273"&gt;here&lt;/a&gt;&lt;br /&gt;Dave Thomas &lt;a href="http://www.codegeneration.net/tiki-read_article.php?articleId=9http://www.codegeneration.net/tiki-read_article.php?articleId=9"&gt;here&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I don't like code generation. It feels to me as a step backwards and not forwards to a solution.&lt;br /&gt;&lt;br /&gt;Instead of saying: "let's write a class/object  with this functionality", we say: "let's write another class and a template, to generate a file, which compiled, gives us the needed object and functionality". Hmmm....&lt;br /&gt;&lt;br /&gt;If the algorithm is so generic that we can express it in a template/file generator, why can't we write a class which through reflection generates the needed functionality?&lt;br /&gt;&lt;br /&gt;How do you unit-test generated files? Do you test the output code, or do you test the new object? If you test the created object (the new functionality), than you have one additional step in unit-testing: compilation.&lt;br /&gt;&lt;br /&gt;My point is that:&lt;br /&gt;&lt;blockquote style="font-style: italic;"&gt;Ruby is dynamic enough to let be do what I want without leaving the language&lt;/blockquote&gt;Smalltalk is more "extreme" than ruby. There you don't have source files !!!&lt;br /&gt;&lt;br /&gt;Java/C# should be "dynamic" too. I think they already are,  through reflection and dynamic code generation, almost as flexible/generic as Ruby. But the developers are always scare of the performance loss. So they prefer an "immature" optimization, instead of a "clean" solution.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114475176518030764?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114475176518030764/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114475176518030764' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114475176518030764'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114475176518030764'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/04/code-generation.html' title='Code Generation'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114465434952024528</id><published>2006-04-10T09:30:00.000+02:00</published><updated>2006-04-10T09:32:29.676+02:00</updated><title type='text'>SPA 2006</title><content type='html'>James Robertson blogs about &lt;a href="http://www.cincomsmalltalk.com/blog/blogView?searchCategory=spa2006"&gt;spa 2006&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114465434952024528?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114465434952024528/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114465434952024528' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114465434952024528'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114465434952024528'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/04/spa-2006.html' title='SPA 2006'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-14511296.post-114424139911137483</id><published>2006-04-05T14:49:00.000+02:00</published><updated>2006-04-05T14:49:59.363+02:00</updated><title type='text'>chaos = order</title><content type='html'>&lt;a href="http://www.physorg.com/news63381025.html"&gt;hmmm&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/14511296-114424139911137483?l=thought-tracker.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://thought-tracker.blogspot.com/feeds/114424139911137483/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=14511296&amp;postID=114424139911137483' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114424139911137483'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/14511296/posts/default/114424139911137483'/><link rel='alternate' type='text/html' href='http://thought-tracker.blogspot.com/2006/04/chaos-order.html' title='chaos = order'/><author><name>Andrei Pamula</name><uri>http://www.blogger.com/profile/16726342438441009325</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='24' src='http://photos1.blogger.com/img/278/2702/320/34.jpg'/></author><thr:total>0</thr:total></entry></feed>
