tag:blogger.com,1999:blog-145112962024-03-13T02:41:30.576+01:00thought-trackerA Collaborative Readinglajoshttp://www.blogger.com/profile/10084204479295620888noreply@blogger.comBlogger175125tag:blogger.com,1999:blog-14511296.post-65769789121849426392010-03-15T12:59:00.004+01:002010-03-15T13:49:25.201+01:00API Design & ClosuresIn a recent design discussion, I've noticed that the preferred<span style="font-style: italic;"> java-ish</span> approach is rather verbose.<br /><br />Suppose we want to create an expression tree and evaluated-it:<br /><br />solution1:<br />ExpressionTreeBuilder b = new ExpressionTreeBuilder();<br />b.newExprY(a,b);<br />b.newExprX(c,d);<br />....<br />ExpressionTree t = b.toTree();<br />interpreter.eval(t);<br /><br />I find this solution rather difficult for '<span style="font-style: italic;">beginners</span>', 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.<br /><br />A much cleaner solution would be:<br />interpreter.eval { |b|<br /> b.newExprX()<br /> b.newExprY()<br />}<br /><br />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 <a href="http://scala.sygneca.com/patterns/loan">scala loan pattern</a>, or <a href="http://www.xml.com/lpt/a/1637">ruby html builder</a>.Andrei Pamulahttp://www.blogger.com/profile/16726342438441009325noreply@blogger.com1tag:blogger.com,1999:blog-14511296.post-49662632195845298532010-02-16T09:41:00.002+01:002010-02-16T10:12:44.744+01:00Java language EOLvia <a href="http://www.infoq.com/news/2010/01/ThoughtWorks-Technology-Radar">InfoQ</a>, link to the original <a href="http://www1.vtrenz.net/imarkownerfiles/ownerassets/1013/Technology%20Radar%20Jan%202010.pdf">ThoughtWorks paper</a>:<br /><br /><blockquote>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.</blockquote>This boils down to <a href="http://gafter.blogspot.com/">closures.</a> If you start a new project, you could start with a project which allows you to do <a href="http://www.scala-lang.org/node/4960">much</a> <a href="http://dev.bizo.com/2010/01/scala-supports-non-local-returns.html">more</a> then just java. Related presentation: <a href="http://www.infoq.com/presentations/gafter-jvm-closures">Language Parity: Closures & JVM</a>.Andrei Pamulahttp://www.blogger.com/profile/16726342438441009325noreply@blogger.com0tag:blogger.com,1999:blog-14511296.post-358595022777227532009-08-17T11:08:00.008+02:002009-08-21T16:08:25.964+02:00Lambda, Linq, Dynamic ProxiesIn the current project I've introduced some closure/function definitions: functions, actions. The usual stuff. (for reference look at the <a href="http://lampsvn.epfl.ch/trac/scala/browser/scala/tags/R_2_7_5_final/src/library/scala">Scala API</a>, or the google collections, or the Linq Func, or the <a href="http://functionaljava.googlecode.com/svn/artifacts/2.20/javadoc/fj/package-summary.html">functional java</a>).<br /><br />One problem with the current state of <a href="http://gafter.blogspot.com/2007/01/definition-of-closures.html">closures</a> in java is that, even though <a href="http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg03277.html?">objects are closures</a>, and they can be realized with <a href="http://www.cuberick.com/2009/08/anonymous-inner-classes-poor-mans.html">anonymous classes</a> (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 <a href="http://www.scala-lang.org/node/114">reduces</a> the adapter overhead).<br />The other problem is that writing closures with anon-classes is a pain: probably that's why <a href="http://gee.cs.oswego.edu/dl/papers/fj.pdf">Doug Lea</a> is <a href="http://blog.objectmentor.com/articles/2009/06/05/bay-area-scala-enthusiasts-base-meeting-whats-new-in-scala-2-8">looking</a> into <a href="http://www.softwaresecretweapons.com/jspwiki/doug-lea-is-a-grandfather-of-all-scala-actors">scala</a>. In my project's context we basically/mostly have operations on collections, a sort of<br /><a href="http://blogs.warwick.ac.uk/chrismay/entry/writing_functional_java/">google collections dsl</a>. The only 'ugly' part is the function definition: how the predicates/transformers are defined.<br /><br />It remindes me of <a href="http://github.com/szeiger/scala-query/tree/master">Scala Query</a> & <a href="http://szeiger.de/blog/2008/07/27/formal-language-processing-in-scala-part-1/">Formal Language Processing in Scala</a>.<br /><br />I thought of the idea of creating proxies in order to define a function: e.g.<br />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.<br />But now I see that it has been implemented in <a href="http://code.google.com/p/lambdaj/">lambdaj</a> (query collections), and for jpa in <a href="http://code.google.com/p/liquidform/">liquidform</a>.<br /><br />What I've missed is that through dynamic proxies we might provide enough information to build queries a la <a href="http://delicious.com/andrei.pamula/linq%20java">LINQ</a>. (i.e. the information which the c#/vb.net compiler provides on parsing the query,<br />could be built, manually, by means of dynamic proxies, in java).<br />---<br />Update: Looking at <a href="http://delicious.com/andrei.pamula/linq%20java">Linq/query for java</a> frameworks:<br />- one does byte code analysis in order to generate the query expression<br />- one does dynamic proxy<br />- one uses APT to generate query expressions from entities (something which people <a href="http://blog.hibernate.org/Bloggers/Java6CompilerPluginsAndTypesafeCriteriaQueries">wished for jpa 2.0</a>)<br /><br />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.Andrei Pamulahttp://www.blogger.com/profile/16726342438441009325noreply@blogger.com0tag:blogger.com,1999:blog-14511296.post-40511451019901085402009-08-05T15:15:00.003+02:002009-08-05T15:35:04.812+02:00Rx FrameworkA new addition to the .Net platform, the Rx framework, aka 'reactive programming', aka 'linq to events'.<br /><br />Here is the <a href="http://themechanicalbride.blogspot.com/2009/04/rx-framework-asynchronous-programming.html">lang.net presentation</a>, the <a href="http://channel9.msdn.com/shows/Going+Deep/Expert-to-Expert-Brian-Beckman-and-Erik-Meijer-Inside-the-NET-Reactive-Framework-Rx/">theoretical discussion/explanation/proof</a> about the relation between the <a href="http://en.wikipedia.org/wiki/Iterator_pattern">Iterator</a> & <a href="http://en.wikipedia.org/wiki/Observer_pattern">Observer</a> pattern, and another <a href="http://themechanicalbride.blogspot.com/2009/07/introducing-rx-linq-to-events.html">very good explanation</a>.<br /><br />The .Net approach is very elegant and reminded me of <a href="http://publicobject.com/glazedlists/">Glazed Lists</a> and of <a href="http://tomasp.net/blog/reactive-i-fsevents.aspx">F# Reactive Programming.</a><br /><br />Other thought associations were to <a href="http://www.infoq.com/articles/pickering-fsharp-async">F# async workflows</a>, and ruby gui frameworks: <a href="http://leadthinking.com/191-bowline-a-ruby-gui-framework">bowline</a> based on <a href="http://www.appcelerator.com/products/titanium-desktop/">Titanium</a>, and <a href="http://kenai.com/projects/monkeybars/pages/Home">MonkeyBars</a> based on swing.<br /><br />Enjoy!Andrei Pamulahttp://www.blogger.com/profile/16726342438441009325noreply@blogger.com0tag:blogger.com,1999:blog-14511296.post-71335025958907700542009-08-04T10:11:00.007+02:002009-08-04T10:38:43.893+02:00Variations on the visitor patternIn the current project I've written so far at least 20 class hierarchies (+ their visitors) representing <a href="http://en.wikipedia.org/wiki/Algebraic_data_type">ADT</a>s.<br /><br /><span>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. </span><br /><span>So we're out of luck with the </span><a href="http://en.wikipedia.org/wiki/Interpreter_pattern">Interpreter Pattern</a><span>, we use the </span><a href="http://en.wikipedia.org/wiki/Visitor_pattern">Visitor Pattern</a><span>/</span><a href="http://en.wikipedia.org/wiki/Double_dispatch">Double Dispatch</a><span>:</span><br /><br /><span>abstract class Expression {</span><br /><span>....static class Number extends Expression {</span><br /><span> ........public final int n;</span><br /><span>........Number(int n) { this.n = n; }</span><br /><span> ....}</span><br /><span> ....static class Plus extends Expression {</span><br /><span>....</span><span>....</span><span>// since the data is immutable, there makes no sense to create getters</span><br /><span>....</span><span>....</span><span>public final Expression left;</span><br /><span>....</span><span>....</span><span> public final Expression right;</span><br /><span>....</span><span>....</span><span>Plus(left, right) { this.left = left; this.right = right; }</span><br /><span>....</span><span>}</span><br /><br /><span>....</span><span>// toString, equals, hashCode are implemented with apache commons-lang, based on reflection up to the Expression class</span><br /><span>....</span><span>}</span><br /><br /><span>The classic Visitor pattern says:</span><br /><br /><span>interface Visitor {</span><br /><span>....</span><span>void visit(Number n);</span><br /><span>....</span><span>void visit(Plus plus);</span><br /><span>}</span><br /><br /><span>and</span><br /><br /><span>abstract void Expression#accept(Visitor v);</span><br /><span>....</span><span>void Number#accept(Visitor v) { v.visit(this); }</span><br /><span>....</span><span>void Plus#accept(Visitor v) { v.visit(this); }</span><br /><span>// noticed the copy-paste !? (imagine doing that 40+ times...)</span><br /><br /><span>In this example the visitor is a stateful closure which encapsulates a computation its initial data and its final (accumulated) result.</span><br /><br /><span>The problem which might arise is how do we handle adding more data type (i.e. classes) to our hierarchy. See the </span><a href="http://delicious.com/andrei.pamula/expression+problem">Expression Problem</a><span>, </span><a href="http://wiki.apidesign.org/wiki/Case_Study_of_Writing_the_Extensible_Visitor_Pattern">Extensible Visitor</a><span>/</span><a href="http://books.google.com/books?id=DXYZZVlWOAkC&printsec=frontcover&dq=practical+api+design#v=onepage&q=&f=false">book</a><span> (more on </span><a href="http://lmgtfy.com/?q=Extensible%20Visitor">google</a><span> ;). </span><br /><span>The proposed solution is to drill a hole in the type safety, in order to make old code compatible with new code:</span><br /><span><br /></span><span>interface Visitor {</span><br /><span>....</span><span>void visit(Number n);</span><br /><span>....</span><span>void visit(Plus plus);</span><br /><span>....</span><span>v</span><span></span><span>oid otherwise(Expression x);</span><br /><span>}</span><br /><br /><span>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 & the result from the visitor:</span><br /><span><br /></span><span>interface Visitor[A,R] {</span><br /><span>....</span><span>R visit(Number n, A args);</span><br /><span>....</span><span>R visit(Plus plus, A args);</span><br /><span>....</span><span>R otherwise(Expression x, A args);</span><br /><span>}</span><br /><br /><span>we also need to change the signature of the Expression#accept</span><br /><br /><span>abstract [A,R] R Expression#accept(Visitor v, A args);</span><br /><span>....</span><span>[A,R] R Number#accept(Visitor v, A args) { v.visit(this, args); }</span><br /><span>....</span><span>[A,R] R Plus#accept(Visitor v, A args) { v.visit(this, args); }</span><br /><span>// noticed the copy-paste !? (imagine doing that 40+ times...)</span><br /><br /><span>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. </span><br /><br /><span>Another variation is when the visitor returns an element of the type which he visited. For that we need to modify the Expression:</span><br /><br /><span>interface Expression {</span><br /><span>....</span><span>E accept(Visitor v, A args);</span><br /><span>....</span><span>static class Number implements Expression { ... }</span><br /><span>}</span><br /><br /><span>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).</span><br /><br /><span>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.</span><br /><br /><span>Compare that with <a href="http://www.scala-lang.org/node/120">pattern matching</a> on </span><a href="http://www.scala-lang.org/node/107">case-classes</a><span>:</span><br /><span>* no need for toString, equals, hashCode since they are generated by the compiler</span><br /><span>* no need for visitors due to pattern matching</span><br /><span>** no issues with statefull visitors</span><br /><span>* no need for manual written ctors since they are written by the compiler,</span><br /><span>* we get cca 50% less code to maintain.</span><br /><br /><span>Now scale that to 20+ class hierarchies...</span>Andrei Pamulahttp://www.blogger.com/profile/16726342438441009325noreply@blogger.com0tag:blogger.com,1999:blog-14511296.post-84064899854694628732009-07-20T11:01:00.009+02:002009-07-29T10:10:17.804+02:00Why ScalaI wanted to write a post 'Why <a href="http://www.scala-lang.org/">Scala</a> is such a nice/great language', but after I've seen the Martin Odersky presentations at <a href="http://video.google.com/videoplay?docid=553859542692229789">google</a>, and at <a href="http://delicious.com/andrei.pamula/scala+presentation+fosdem+2009">FOSDEM 2009</a>, Bonas Joner at QCon 2009 <span style="text-decoration: underline;">'</span><a href="http://www.slideshare.net/jboner/pragmatic-real-world-scala-45-min-presentation">Pragmatic Real-World Scala</a>)', Evan Weaver with '<a href="http://blog.evanweaver.com/articles/2009/03/13/qcon-presentation/">Improving Running Components at Twitter</a>' and the James Strachan's (of groovy fame) <a href="http://macstrac.blogspot.com/2009/04/scala-as-long-term-replacement-for.html">post</a>, an impressive <a href="http://markthispage.blogspot.com/2009/06/more-than-100-sites-to-study-scala.html">collection of learning Scala resources</a>, I had the impression that there is nothing more to be said (that hasn't be said before).<br /><br />There is even an <a href="http://www.scala-lang.org/node/104">online</a> and <a href="http://www.scala-lang.org/docu/files/ScalaTour.pdf">offline</a> ScalaTour.<br /><br />Nevertheless, we could/should mention<br /><br />Java-Basics:<br /><br />* seamless java integration<br />* <a href="http://www.scala-lang.org/node/91">IDE support</a>, <a href="http://stackoverflow.com/questions/972006/whats-the-best-scala-build-system">build support</a> (maven, ant, sbt, buildr)<br />* <a href="http://stackoverflow.com/questions/953998/code-coverage-tools-for-scala">java code coverage</a><br /><br />OO-Basics:<br />* objects all-way-down (see <a href="http://www.scala-lang.org/docu/files/ScalaOverview.pdf">ScalaOverview</a>) (the Smalltalk way)<br />** primitives are <a href="http://www.drmaciver.com/2008/06/scala-arrays/">efficiently</a> wrapped & handled by the compiler<br />* closures/functions are objects <a href="http://people.csail.mit.edu/gregs/ll1-discuss-archive-html/msg03277.html?">too</a><br />* multiple trait inheritance (e.g. <a href="http://scala.sygneca.com/patterns/utility-belt">utility-belt</a>, <a href="http://johlrogge.wordpress.com/2009/06/27/loggingtools-in-scala/">logging</a>, ...)<br /><br />Fun-Stuff:<br />* <a href="http://lampwww.epfl.ch/%7Eemir/written/MatchingObjectsWithPatterns-TR.pdf">extensible</a> <a href="http://www.scala-lang.org/node/120">pattern matching</a> (i.e. switch on steroids on objects)<br />* functional idioms allowed<br />* <a href="http://www.scala-lang.org/node/127">type inference</a> (<a href="http://delicious.com/andrei.pamula/hindley+milner">Hindley-Milner</a>)<br />* <a href="http://scala-blogs.org/2008/10/manifests-reified-types.html">reified generics</a><br />* <a href="http://delicious.com/andrei.pamula/scala+type+classes">type classes</a><br />* elegant solution to the <a href="http://delicious.com/andrei.pamula/expression+problem">Expression Problem</a>Andrei Pamulahttp://www.blogger.com/profile/16726342438441009325noreply@blogger.com0tag:blogger.com,1999:blog-14511296.post-60726312329451773572009-07-13T14:03:00.004+02:002009-07-13T14:14:36.653+02:00Moved Code Snippets to MercurialI've just moved the tip of the svn trunk to <a href="http://mercurial.selenic.com/wiki/">mercurial</a>.<br />In order to make a push without a password you'll need to modify the .hgrc (specify your google code <username>username, password <password>:<br /><br /><span style="font-family:courier new;">[paths]</span><br /><span style="font-family:courier new;"><span style="font-weight: bold;">thought-tracker</span> = https://<username><span style="font-weight: bold;">username</span>:<span style="font-weight: bold;">password</span><password>@thought-tracker.googlecode.com/hg/</password></username></span><br /><br />In order to get it:<br /><span style="font-family:courier new;">hg clone https://thought-tracker.googlecode.com/hg <local_folder></local_folder></span><span style="font-family: courier new; font-weight: bold;">local_folder</span><br /><br />In order to push/publish it (after a local <span style="font-family:courier new;">hg ci -Am"some msg"</span>):<br /><span style="font-family:courier new;">hg push <span style="font-weight: bold;">thought-tracker</span></span></password></username>Andrei Pamulahttp://www.blogger.com/profile/16726342438441009325noreply@blogger.com0tag:blogger.com,1999:blog-14511296.post-16637825153005772292009-07-09T09:35:00.003+02:002009-07-09T10:23:52.213+02:00DVCS(hg) vs SVN workflowsSuppose we work in an international company, remote sites, not so good connection between those sites.<br />We have the following scenarios:<br /><br />1. We have to do a rather big refactoring, which will take several weeks.<br />- 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)<br />- With hg: you just create a clone-branch, you work on it, you can merge with<->from trunk regularly,<br />whithout any merging problems.<br />- 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<br /><br />2. Junior (remote) developer needs help fixing a unit-test.<br />- With svn: do a branch, svn switch to it, push the code with the broken tests, fix them, merge back to trunk.<br />- With webex: do a remote session an explain the fix<br />- With hg: just pull the changes, make a fix, push them back to the remote developer. (hint: hg is more network-friendly then svn)<br /><br />3. An interface between 2 components is changed radically. Both the user & the implementation must be changed.<br />- With svn: do a branch, do all the changes, merge to trunk<br />- With hg: change the interface in a cloned repository, then share this repository between the user & implementer. They can work in parallel, the last one finishing pulls the changes from the other one and does the integration.<br /><br />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.<br />- He shouldn't integrate friday@17.00. (but he did)<br />- With svn: create a branch, svn switch, push your changes to the server<br />- With hg: a colleague could pull the changes an do the integration + push the changes, without the need to go through the server.<br /><br />5. Always keep the code green.<br />- 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<br />- 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)<br /><br />A lot of the hg power comes from the fact that is changeset-based (unlike <a href="http://subversion.tigris.org/faq.html#changesets">svn</a>) 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.<br /><br />links: <a href="http://delicious.com/andrei.pamula/hg">hg</a>, <a href="http://delicious.com/andrei.pamula/git">git</a>Andrei Pamulahttp://www.blogger.com/profile/16726342438441009325noreply@blogger.com2tag:blogger.com,1999:blog-14511296.post-33639015650620928002009-05-07T15:13:00.000+02:002009-05-07T15:14:26.083+02:0015 Min. Null<div style="width:425px;text-align:left" id="__ss_1399852"><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">15 Minutes Null</a><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=15minnull-090507081231-phpapp02&stripped_title=15-minutes-null"><param name="allowFullScreen" value="true"><param name="allowScriptAccess" value="always"><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=15minnull-090507081231-phpapp02&stripped_title=15-minutes-null" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object><div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;">View more <a style="text-decoration:underline;" href="http://www.slideshare.net/">presentations</a> from <a style="text-decoration:underline;" href="http://www.slideshare.net/andrei.pamula">andrei.pamula</a>.</div></div>Andrei Pamulahttp://www.blogger.com/profile/16726342438441009325noreply@blogger.com0tag:blogger.com,1999:blog-14511296.post-13286251663439563882009-05-04T10:15:00.002+02:002009-05-04T10:17:54.715+02:0015 Min. IoCFrom my series, '15 minutes Lessons Learned', a short introduction to Inversion of Control<br /><br /><div style="width:425px;text-align:left" id="__ss_1381790"><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">15 Min IoC</a><object style="margin:0px" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=15minioc-090504031321-phpapp02&stripped_title=15-min-ioc"><param name="allowFullScreen" value="true"><param name="allowScriptAccess" value="always"><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=15minioc-090504031321-phpapp02&stripped_title=15-min-ioc" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object><div style="font-size:11px;font-family:tahoma,arial;height:26px;padding-top:2px;">View more <a style="text-decoration:underline;" href="http://www.slideshare.net/">presentations</a> from <a style="text-decoration:underline;" href="http://www.slideshare.net/andrei.pamula">andrei.pamula</a>.</div></div>Andrei Pamulahttp://www.blogger.com/profile/16726342438441009325noreply@blogger.com0tag:blogger.com,1999:blog-14511296.post-44048055713454940332009-02-23T13:35:00.002+01:002009-02-23T13:41:46.936+01:00Programming AbstractionsGreat post by Brian Hurt: <a href="http://enfranchisedmind.com/blog/2009/02/22/programming-doesnt-suck-or-at-least-it-shouldnt/">Programming Doesn't Suck! Or At Least It Shouldn't</a>.<br /><br /><p></p><blockquote><p>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.</p> <p>I’m not even talking about leaving your language of choice, I’m talking about thinking outside the box, or even just <em>thinking</em>. 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 <em>are</em> 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.</p><p>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.</p> <p>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 <em>want</em> 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.</p> <p>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.</p></blockquote><p><br /></p><p>Slightly related: Erik Meijer @ JAOO2008: '<a href="http://jaoo.decenturl.com/brisbane-2008-file-path-jaoo">Why Functional Programming (Still) Matters</a>'<br /></p>Andrei Pamulahttp://www.blogger.com/profile/16726342438441009325noreply@blogger.com0tag:blogger.com,1999:blog-14511296.post-58193620186685321332009-02-06T09:34:00.002+01:002009-02-06T09:41:09.031+01:00Failure, take twoRegarding the Agile/Scrum <a href="http://thought-tracker.blogspot.com/2009/01/failure.html">failure</a>, it has been a lot of <a href="http://www.infoq.com/news/2009/02/whole-enchilada-and-context">buzz</a> in the community:<br /><br />James Shore - <a href="http://jamesshore.com/Blog/The-Decline-and-Fall-of-Agile.html">The Decline and Fall of Agile</a><br />Martin Fowler - <a href="http://martinfowler.com/bliki/FlaccidScrum.html">Flaccid Scrum</a><br />Ron Jeffries - <a href="http://xprogramming.com/blog/2009/01/30/context-my-foot/">Context My Foot</a><br /><blockquote>Want to succeed at software? Then it can’t be business as usual. </blockquote>Andrei Pamulahttp://www.blogger.com/profile/16726342438441009325noreply@blogger.com0tag:blogger.com,1999:blog-14511296.post-50420681957627552042009-01-28T09:33:00.002+01:002009-01-28T09:36:24.373+01:00pet project ideaImplement a 'bean-mapper' a la <a href="http://dozer.sourceforge.net/documentation/gettingstarted.html">Dozer</a>, but instead of using the xml files, use dynamic proxies, a la <a href="http://code.google.com/p/liquidform/">LiquidForm</a>.Andrei Pamulahttp://www.blogger.com/profile/16726342438441009325noreply@blogger.com0tag:blogger.com,1999:blog-14511296.post-82492209616880987672009-01-27T11:44:00.003+01:002009-01-28T09:49:48.830+01:00FailureFailure<br /><br />"<a style="font-style: italic;" href="http://www.kevinfitzmaurice.com/cope_failure_not_learning.htm">The only failure is the failure to learn from failure</a>" -- Kevin Everett FitzMaurice<br /><br />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 '<a href="http://agilemanifesto.org/principles.html">agile principles</a>' 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.<br /><br />Maybe this is related to the '<a href="http://c2.com/cgi/wiki?ShuHaRi">Shu Ha Ri</a>' <a href="http://www.aikidofaq.com/essays/tin/shuhari.html">training cycle</a>, <a href="http://c2.com/cgi/wiki?ShuHaRi">which</a>:<br /><a style="font-style: italic;" href="http://c2.com/cgi/wiki?TheThreeExtremos"></a><blockquote><a style="font-style: italic;" href="http://c2.com/cgi/wiki?TheThreeExtremos">TheThreeExtremos</a><span style="font-style: italic;"> lately seem to be recommending a </span><a style="font-style: italic;" href="http://c2.com/cgi/wiki?ShuHaRi">ShuHaRi</a><span style="font-style: italic;"> approach to XP: First, follow </span><em style="font-style: italic;">all</em><span style="font-style: italic;"> the practices. Then, realize </span><a style="font-style: italic;" href="http://c2.com/cgi/wiki?TheyreJustRules">TheyreJustRules</a><span style="font-style: italic;">, and change them (i.e. break some of the original rules). Finally, you don't need to think about the rules anymore. -- </span><a style="font-style: italic;" href="http://c2.com/cgi/wiki?GeorgePaci">GeorgePaci</a></blockquote><br />But in day-to-day business, it is just sloppiness. People don't understand that they are on a <span style="font-weight: bold;">learning journey</span>, 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 <a href="http://www.pragprog.com/titles/prj/ship-it">Ship-It</a>. We've done, it, we are happy, let's go home. No retrospection, no how-can-we-do-it-better-next-time, no <a href="http://en.wikipedia.org/wiki/5_Whys">5-whys</a>. 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.<br /><br />Does this mean that Agile/(Scrum?) is a <a href="http://www.infoq.com/presentations/agile-quality-canary-coalmine">culture-thing</a>? How can we change a 'not-my-problem' culture? How can we stop <a href="http://www.pragprog.com/the-pragmatic-programmer/extracts/software-entropy">sinking in a pool of problems</a>? How can we <a href="http://www.artima.com/intv/fixit.html">start carrying</a>?<br /><br />ps. via <a href="http://delicious.com/raganwald">rangawald's delicious</a>, I found <a href="http://www.defmacro.org/ramblings/taming-perfectionism.html">Taming Perfectionism</a>.Andrei Pamulahttp://www.blogger.com/profile/16726342438441009325noreply@blogger.com0tag:blogger.com,1999:blog-14511296.post-17936311598174044992009-01-16T13:12:00.002+01:002009-01-16T13:15:20.328+01:00The MembraneSuppose 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:<br /><br />A: B, A1, A2<br />B: C, B1, B2, B3<br />C: D, C1, C2<br />D: D1, D2, D3<br /><br />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. }<br />In practice, the problem is that most of the people will use/scatter these properties all over their code, leading to maintenance monsters:<br />- navigation is all over the place, violating the '<a href="http://en.wikipedia.org/wiki/Law_of_Demeter">Law of Demeter</a>'.<br />- <a href="http://jayflowers.com/WordPress/?p=78">Testing</a> is getting a <a href="http://misko.hevery.com/2008/07/18/breaking-the-law-of-demeter-is-like-looking-for-a-needle-in-the-haystack/">lot</a> 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.<br />- The amount of code using <a href="http://martinfowler.com/articles/mocksArentStubs.html">chained objects/train wrecks</a> 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.<br /><br />Possible solutions:<br />a. Define the projection as required by that component/use case, eg IView { A1, B1, C1, D1 } (properties, or getter/setter, etc.)<br />- Define a repository service IRepository.get(...) -> IView<br />- Work against <span style="font-weight: bold;">your abstraction</span> IRepository/IView<br /><br />The IView/IRepository could build through:<br />- DTOs mapping (a la <a href="http://dozer.sourceforge.net/">dozer</a> & <a href="http://dozer-annotate.sourceforge.net/">co</a>.)<br />- wrap & lazy fetch:<br />View {<br /> ctor(A a) { _a = a; }<br /> A1 { _a.A1 }<br /> B1 { _a.B.B1}<br /> C1 { _a.B.C.C1 }<br /> D1 { _a.B.C.D1 }<br />}<br />(<span style="font-style: italic;">a pretty slick solution might be build with LINQ expressions</span>)<br />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.<br />The IRepository/IView abstractions represent the membrane to the external world. (<a href="http://rkse.blogspot.com/">Ralf</a> refers to the pattern as 'external adapter', probably refering to Alistair Cockburn's <a href="http://alistair.cockburn.us/Hexagonal+architecture">'Hexagonal Architecture' paper</a>, I prefer the Alan Kay's <a href="http://video.google.com/videoplay?docid=-2950949730059754521">metaphor</a>).<br /><br />b. Instead of defining the projection IView we could add the <a href="http://www.pragprog.com/articles/tell-dont-ask">required operations</a> on A. This has the benefit of aggregating/reusing common operations on A (usually a <a href="http://www.lostechies.com/blogs/jimmy_bogard/archive/2008/05/20/entities-value-objects-aggregates-and-roots.aspx">root entity</a>).<br />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)<br /><br />Final thoughts:<br />- it is not about DDD/Tell don't Ask vs EJB/DTOs vs XXX, but is about isolation/visibility.<br />- (Unit) Testing asap helps a lot identifying architecture/design smells.Andrei Pamulahttp://www.blogger.com/profile/16726342438441009325noreply@blogger.com0tag:blogger.com,1999:blog-14511296.post-3738434083128713252009-01-09T10:04:00.002+01:002009-01-09T10:07:56.312+01:00toString or not toStringsuppose we have an Id class, which used as a 'pointer' to some persistent entities.<br /><br />abstract class Id<t> {<br /> T _raw;<br /> Id(T raw) { _raw = raw; }<br /> @Overrride void toString() { return _raw.toString(); }<br />}<br /><br />And the Object#toString() documentation says:<br /> /**<br /> * Returns a string representation of the object. In general, the<br /> * #toString method returns a string that<br /> * "textually represents" this object. The result should<br /> * be a concise but informative representation that is easy for a<br /> * person to read.<br /> * It is recommended that all subclasses override this method.<br /> *<br /> * The #toString method for class Object<br /> * returns a string consisting of the name of the class of which the<br /> * object is an instance, the at-sign character `@', and<br /> * the unsigned hexadecimal representation of the hash code of the<br /> * object. In other words, this method returns a string equal to the<br /> * value of:<br /> * getClass().getName() + '@' + Integer.toHexString(hashCode())<br /> **/<br /><br />What is the problem?<br /><br />* we heavily use these Ids in a *lot* of places<br />* id.toString() is used both for Id -> String conversion, as a part of our design and as textual representation for debugging/logging<br />* to subclasses AID<string> and BID<string> will have the same textual representation, making future debugging/logging more confusing then necessary<br />* 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<br />** 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)<br />*** 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()<br /><br />concluding advice: when you model your own domain language/design, be careful what you override.<br /><br /></string></string></t>Andrei Pamulahttp://www.blogger.com/profile/16726342438441009325noreply@blogger.com0tag:blogger.com,1999:blog-14511296.post-91502913680696804662008-11-27T12:48:00.002+01:002008-11-27T12:58:04.112+01:00Pragmatic CompromiseHave you noticed that all the guys who are advocating a compromise code quality vs. speed,<br />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 ' <span style="font-style: italic;">Why is the quality so poor?</span> '.<br />Even if quality is not seen as <a href="http://www.infoq.com/presentations/agile-quality-canary-coalmine">corporate asset</a>, make it a part of your professional ethics.Andrei Pamulahttp://www.blogger.com/profile/16726342438441009325noreply@blogger.com0tag:blogger.com,1999:blog-14511296.post-32061675132446840242008-11-11T09:55:00.004+01:002009-01-18T18:48:25.061+01:00DynamicQueryHas anybody tried to do an EJB DynamicQuery implementation a la <a href="http://grails.org/GORM">groovy</a>, using a <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/reflect/Proxy.html">DynamicProxy</a> ?<br />(post inspired by <a href="http://code.google.com/p/proxymatic/wiki/AutoBoundary">AutoBoundary proxymatic</a>)<br />Apparently yes: check-out the <a href="http://code.google.com/p/liquidform/">LiquidForm</a>.<br />There are some other <a href="http://delicious.com/andrei.pamula/jpa+linq">alternatives</a>, but java is not <a href="http://blogs.msdn.com/charlie/archive/2006/10/05/Links-to-LINQ.aspx">there</a> <a href="http://developer.db4o.com/blogs/carl/archive/2008/05/02/linq-for-java.aspx">yet</a>.Andrei Pamulahttp://www.blogger.com/profile/16726342438441009325noreply@blogger.com0tag:blogger.com,1999:blog-14511296.post-35173066856124577812008-11-10T09:50:00.002+01:002008-11-10T09:58:07.300+01:00Scrum LogAfter reading/watching an impressive amount of presentations from Henrik Kniberg: <a href="http://www.parleys.com/display/PARLEYS/Home#slide=1;title=10%20ways%20to%20screw%20up%20with%20Scrum%20%26%20XP;talk=19267619">parleys</a>, <a href="http://www.crisp.se/henrik.kniberg/presentations/agile2008/10-ways-to-screw-up-with-scrum-and-xp.pdf">slides</a>, <a href="http://www.crisp.se/henrik.kniberg/presentations/agile2008/Technical-Debt-how-not-to-ignore-it.pdf">technical-debt</a>, <a href="http://www.crisp.se/henrik.kniberg/presentations/agile2008/Bootstrapping-Scrum-and-XP-in-a-crisis.pdf">bootstraping scrum and xp in a crisis</a>, <a href="http://blog.crisp.se/henrikkniberg/2008/02/01/1201823760000.html">scrum checklist</a>, and <a href="http://delicious.com/andrei.pamula/scrum">more</a>, I've decided to keep a personal iteration log.<br />It's amazing how much clarity you get at the end of an iteration: the retrospective.Andrei Pamulahttp://www.blogger.com/profile/16726342438441009325noreply@blogger.com0tag:blogger.com,1999:blog-14511296.post-5509094197644938442008-11-03T10:45:00.001+01:002008-11-03T10:47:19.062+01:00Dark Syntax Highlight(in RGB)<br />Brackets: 128,255,0<br />Keywords: 217,167,15<br />Comments: 0,185,0<br />Tasks,ToDos: 0,255,0Andrei Pamulahttp://www.blogger.com/profile/16726342438441009325noreply@blogger.com0tag:blogger.com,1999:blog-14511296.post-56697310639199798142008-10-23T15:01:00.003+02:002008-10-23T15:21:35.404+02:00API UsabilityThe 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 ?<br /><br />The first feedback we get from (unit-)tests. Unfortunately a lot of people don't do that.<br />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...Andrei Pamulahttp://www.blogger.com/profile/16726342438441009325noreply@blogger.com0tag:blogger.com,1999:blog-14511296.post-52247728906238180622008-10-22T16:41:00.002+02:002008-10-22T17:38:43.151+02:00Filter support for PropertyConfiguratorThe 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.<br /><br />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.<br /><br />Keeping the notations used by the log4j source code, filters are configured as follows:<br /><br /><span style="font-size:85%;"><span style="font-family: courier new;">log4j.appender.appenderName.filter.ID=fully.qualified.name.of.filter.class</span><br /><span style="font-family: courier new;">log4j.appender.appenderName.filter.ID.option1=value1</span><br /><span style="font-family: courier new;">...</span><br /><span style="font-family: courier new;">log4j.appender.appenderName.filter.ID.optionN=valueN</span><br /></span><br /><br />You can download the patch directly from the log4j <a href="https://issues.apache.org/bugzilla/show_bug.cgi?id=46049">bug tracker</a>. It can be applied to the current HEAD of the 1.2 branch, more exactly to 1.2.15.lajoshttp://www.blogger.com/profile/10084204479295620888noreply@blogger.com0tag:blogger.com,1999:blog-14511296.post-76768704852410166902008-10-10T09:52:00.001+02:002008-10-10T09:54:18.550+02:00CoderWritten code is a cost, since it has to be maintained. Less code, less maintenance.<br />Maybe we should call developers 'anti-coders'.Andrei Pamulahttp://www.blogger.com/profile/16726342438441009325noreply@blogger.com1tag:blogger.com,1999:blog-14511296.post-10147454573736625582008-08-19T12:45:00.003+02:002008-08-19T13:03:08.254+02:00Option/Maybe monad is a generic NullObjectI've just reviewed the <a href="http://thought-tracker.blogspot.com/2006/06/nullobject-visitor.html">NullObject and Visitor</a> post. It is so similar with the <a href="http://blog.tmorris.net/scalaoption-cheat-sheet/">Option/Maybe</a> monad.<br />ps. Thought's on Validation: Scala/liftweb has an nice <a href="http://github.com/dpp/liftweb/tree/master/lift/src/main/scala/net/liftweb/util/Can.scala">Can</a>.Andrei Pamulahttp://www.blogger.com/profile/16726342438441009325noreply@blogger.com0tag:blogger.com,1999:blog-14511296.post-85841042258939527542008-08-11T18:33:00.006+02:002008-10-17T15:13:14.290+02:00Scala Marketing Challenge<a href="http://suereth.blogspot.com/2008/07/scala-marketing-challenge.html">Josh Suereth</a> would like to <a href="http://suereth.blogspot.com/2008/07/scala-marketing-challenge_29.html">improve</a> the Scala's marketing strategy.<br />This is a tough sell. If we <a href="http://research.microsoft.com/%7Eemeijer/Papers/es012-meijer.pdf">look</a> at the <a href="http://www.coburnventures.com/About_CHANGE/The_Change_Function.html">Change Function</a>:<br /><br />ChangeFunction = F(PerceivedCrisis/PerceivedPainOfAdoption).<br /><br />(btw. read Erik Meijer's paper: '<span class="ft0"><a href="http://research.microsoft.com/%7EEMeijer/Papers/ICFP06.pdf">Confessions of a Used Programming Language Salesman</a>', it's really, really <span style="font-weight: bold;">good.</span>)<br /><br />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 <a href="http://lambda-the-ultimate.org/node/458">concurrency problem</a>, 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.<br /><br />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 <a href="http://java.net/pub/pq/196">scary</a>). 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 '<a href="http://lambda-the-ultimate.org/node/2579">Generics of a Higher Type</a>', type <a href="http://en.wikipedia.org/wiki/Covariance_and_contravariance_%28computer_science%29">covariance/contra-variance</a>. Pretty scary... <a href="http://flickr.com/photos/14461746@N02/2594088214/">booh</a>! Did I say that IDE support is not yet at java's level?<br /><br />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')<br /><br />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'.<br />If you look at the package you'll see they offer concurrency <span style="font-weight: bold;">primitives</span>, and to write shared-state concurrent programs is very <a href="http://www.javaconcurrencyinpractice.com/">hard</a>. You'll have to think a lot <a href="http://lamp.epfl.ch/%7Ephaller/actors.html">more</a> about object isolation and the threading context.<br /><br />In conclusion:<br />- UserPerceivedCrisis: small<br />- PerceivePainOfAdoption: big<br />ChangeFunction -tends-to-> small.<br /><br /><a href="http://www.edge.org/3rd_culture/lanier06/lanier06_index.html">sorry</a>, scala...<br /><br /><br /></span>Andrei Pamulahttp://www.blogger.com/profile/16726342438441009325noreply@blogger.com0