<?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-1598881393381863026</id><updated>2011-07-31T03:01:35.563-07:00</updated><category term='Remove'/><category term='active directory'/><category term='i.t.'/><category term='continuous integration'/><category term='edsger dijkstra'/><category term='branch'/><category term='latex'/><category term='soa'/><category term='junit'/><category term='selenium'/><category term='ejbql'/><category term='distributed systems'/><category term='mythical man-month'/><category term='software development'/><category term='noweb'/><category term='testng'/><category term='ejb3'/><category term='two screens laptop'/><category term='software methodology'/><category term='vim'/><category term='jee'/><category term='touch-screen'/><category term='extreme programming'/><category term='xp'/><category term='session bean'/><category term='java'/><category term='refactoring'/><category term='manage'/><category term='geek'/><category term='concurrency'/><category term='kiss principle'/><category term='oracle'/><category term='zero esquerda'/><category term='interview'/><category term='analysis paralisys'/><category term='build'/><category term='jpa'/><category term='html'/><category term='agile methods'/><category term='design'/><category term='project'/><category term='business studio'/><category term='architecture'/><category term='cruise control'/><category term='dependencies'/><category term='svn'/><category term='user profile'/><category term='trunk'/><category term='formatar'/><category term='ignorance'/><category term='apple'/><category term='domain change'/><category term='perl'/><category term='glassfish'/><category term='concurrent'/><category term='itil'/><category term='tarefas repetitivas'/><category term='agile'/><category term='function point analysis'/><category term='proofs'/><category term='steve jobs'/><category term='managing'/><category term='windows migration'/><category term='uml'/><category term='bpmn'/><category term='nfs'/><category term='stateful beans'/><category term='ant'/><category term='jpql'/><category term='old'/><category term='paradox of choice'/><category term='patterns'/><category term='future computing'/><category term='dependence injection'/><category term='cpan'/><category term='note'/><category term='software sizing'/><category term='cmmi'/><category term='web services'/><category term='book'/><category term='tibco'/><category term='versioning'/><category term='jquery'/><category term='scrum'/><category term='sql'/><category term='orm'/><category term='jboss'/><category term='mathematics'/><category term='microsoft'/><category term='project management'/><category term='model'/><category term='formatacao'/><category term='software testing'/><category term='inteface design'/><category term='artifacts'/><category term='dynamic select'/><category term='human-computer interface'/><title type='text'>Keep Coding</title><subtitle type='html'>Notes on software development</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>41</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-2231743305377645201</id><published>2010-03-10T19:39:00.000-08:00</published><updated>2010-03-10T19:53:48.437-08:00</updated><title type='text'>Moving...</title><content type='html'>I'm moving from &lt;a href="http://blogger.com"&gt;blogger&lt;/a&gt; to &lt;a href="http://wordpress.org"&gt;wordpress&lt;/a&gt; and I got a new &lt;a href="http://marcovaltas.com"&gt;domain&lt;/a&gt;! In the next few days I'll be fixing some issues from the imported data, cleaning up old stuff and theme tuning. Here's is the new url: &lt;a href="http://marcovaltas.com"&gt;http://marcovaltas.com&lt;/a&gt; &lt;div&gt;
&lt;/div&gt;&lt;div&gt;Meanwhile I'll keep the old posts in blogger if eventually someone has a bookmark or a post shows up in Google search. &lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Best,&lt;/div&gt;&lt;div&gt;Marco Valtas.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-2231743305377645201?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/2231743305377645201/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=2231743305377645201' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/2231743305377645201'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/2231743305377645201'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2010/03/moving.html' title='Moving...'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-4250424904363577638</id><published>2009-09-20T15:25:00.000-07:00</published><updated>2009-09-20T15:31:59.200-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='managing'/><category scheme='http://www.blogger.com/atom/ns#' term='itil'/><category scheme='http://www.blogger.com/atom/ns#' term='geek'/><title type='text'>Managing Geeks</title><content type='html'>&lt;p&gt;I just read this &lt;a href="http://www.thekua.com/atwork/2009/09/respect-is-in-the-currency-of-geeks/"&gt;blogpost from Patrick Kua&lt;/a&gt; which
will lead you to &lt;a href="http://www.computerworld.com/s/article/print/9137708/Opinion_The_unspoken_truth_about_managing_geeks?taxonomyName=Management&amp;amp;taxonomyId=14"&gt;this&lt;/a&gt;. As Patrick I don't agree with all, but some points got my attention.&lt;/p&gt;

&lt;h3&gt;Geeks are trained in logic and ordered thought.&lt;/h3&gt;

&lt;p&gt;With these skills you can't make BS decisions, if does not make sense
they will detect it easily. When your IT resists to some business
decision, is better check out what is happening, they can function as
compass against illogic paths.&lt;/p&gt;

&lt;h3&gt;Respect is money&lt;/h3&gt;

&lt;p&gt;In the IT world respect is money. Note that all open source projects
work this way. You can't earn respect with nice talk, smiles or other
common social weapons. IT guys will respect those who knows what they
are talking about and are humble for those things they don't know.
Respect is earned with work, good work and team work.  Force will just
make them shut and let you, or your project, drawn alone. With respect
they will follow you, work late and keep you project the best as they
can.&lt;/p&gt;

&lt;h3&gt;IT can't fake work&lt;/h3&gt;

&lt;p&gt;This was something I never notice but, IT can't fake work (in
general). So, anything that sounds like fake you be detected and can't
be done at all. Usually other departments (who asked for the
impossible) will throw stones on IT, telling that they are slowing the
project. In fact, when I saw this, the root cause was a project
without value, something to cover incompetence or IT is full and can't
deliver at the velocity asked. Is a good thing check what has been
asked to IT. In my experience, IT will prioritize by it self. They
will not respect illogic priorities and the will organize as they see
the business plan. It's very important to make it clear for IT where
your business plan is pointed to, if you do, they will take care of
 projects that point in the same direction.&lt;/p&gt;

&lt;h3&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Well, these are just observations I made through the my years in IT. IT
is a very important staff, usually they can spot problems very fast
and a good understanding of the minds of IT is a good tool to lead
your business to success.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-4250424904363577638?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/4250424904363577638/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=4250424904363577638' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/4250424904363577638'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/4250424904363577638'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2009/09/managing-geeks.html' title='Managing Geeks'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-4665976383335765364</id><published>2009-09-16T06:21:00.000-07:00</published><updated>2009-09-16T06:30:28.408-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='note'/><title type='text'>Blog Quick note - disabled automatic line breaks</title><content type='html'>&lt;p&gt;I just disabled the &lt;em&gt;automatic line breaking&lt;/em&gt; option in blogger.
Probably old posts will be a lot messy but I can't rewrite them all.
&lt;a href="http://www.blogger.com"&gt;Blogger&lt;/a&gt; is not the best tool for blogging
but is what I have. &lt;/p&gt;
&lt;p&gt;The reason for the change is that I'm now writing the posts using
&lt;a href="http://daringfireball.net/projects/markdown/"&gt;Markdown&lt;/a&gt; and
&lt;a href="http://www.vim.org"&gt;Vim&lt;/a&gt; which makes
me a lot more productive in writing for this blog and I hope to write
a lot more now.&lt;/p&gt;

&lt;p&gt;Best.
Marco.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-4665976383335765364?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/4665976383335765364/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=4665976383335765364' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/4665976383335765364'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/4665976383335765364'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2009/09/blog-quick-note-disabled-automatic-line.html' title='Blog Quick note - disabled automatic line breaks'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-3465721672212529731</id><published>2009-09-16T06:09:00.000-07:00</published><updated>2009-09-16T08:09:47.009-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='refactoring'/><category scheme='http://www.blogger.com/atom/ns#' term='mythical man-month'/><category scheme='http://www.blogger.com/atom/ns#' term='software methodology'/><title type='text'>Software Philosophy - Refactoring Paradox</title><content type='html'>&lt;!-- vim: tw=70 spell
 --&gt;

&lt;p&gt;Another day I was talking with a colleague about the &lt;a href="http://www.oodesign.com/interpreter-pattern.html" title="Interpreter Pattern"&gt;Interpreter
Pattern&lt;/a&gt; to solve a &lt;em&gt;implicit language&lt;/em&gt; problem. &lt;a href="http://martinfowler.com" title="Martin Fowler"&gt;Martin
Fowler&lt;/a&gt; describes a pattern called &lt;a href="http://martinfowler.com/eaaCatalog/queryObject.html" title="Query Object"&gt;Query Object&lt;/a&gt; to solve this,
which is a &lt;a href="http://www.oodesign.com/interpreter-pattern.html" title="Interpreter Pattern"&gt;interpreter&lt;/a&gt; focused on database queries.&lt;/p&gt;

&lt;h3&gt;&lt;a href="http://en.wikipedia.org/wiki/Code_refactoring" title="Code Refactoring"&gt;Refactoring&lt;/a&gt; as the best technique&lt;/h3&gt;

&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Code_refactoring" title="Code Refactoring"&gt;Code Refactoring&lt;/a&gt; is, after learn a language, is the most
important thing a developer should know. &lt;a href="http://en.wikipedia.org/wiki/Code_refactoring" title="Code Refactoring"&gt;Refactoring&lt;/a&gt; is what
really reveals what &lt;em&gt;soft&lt;/em&gt; means in &lt;em&gt;software&lt;/em&gt;. When building a bridge
is practically a one shot, once the foundations are ready you can´t
improve them as the construction continues. But with software, you
usually improve the foundations as you go, mostly because nobody knows
where is the other side of the bridge you are building.&lt;/p&gt;

&lt;h3&gt;Refactoring paradox&lt;/h3&gt;

&lt;p&gt;&lt;a href="http://en.wikipedia.org/wiki/Code_refactoring" title="Code Refactoring"&gt;Refactoring&lt;/a&gt; has a implicit paradox, you have to &lt;strong&gt;factor&lt;/strong&gt; before
&lt;strong&gt;refactor&lt;/strong&gt;. You can´t, at first, use such good technique without
make mistakes &lt;em&gt;a priori&lt;/em&gt;. This fact became clear when we had to
refactor a code which was growing to cope with combinations of
SQL queries. In the book &lt;a href="http://www.industriallogic.com/xp/refactoring/"&gt;Refactoring to
Patterns&lt;/a&gt; this problem
is described as &lt;em&gt;Replace Implicit Language with Interpreter&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;But if you think about it you have to code the queries and many
methods to see what implicit language is taking form. Probably you
will not foresee the language, if you try to predict such implicit
language many anti-patterns and bad practices will rise, such as
&lt;a href="http://www.c2.com/cgi/wiki?PrematureOptimization"&gt;&lt;em&gt;Premature
Optimization&lt;/em&gt;&lt;/a&gt;,
&lt;a href="http://c2.com/xp/YouArentGonnaNeedIt.html"&gt;&lt;em&gt;YAGNI&lt;/em&gt;&lt;/a&gt; and etc. For this
particularly problem, if you try to code the solution at first, you
will end with a
&lt;a href="http://docs.jboss.org/hibernate/stable/core/reference/en/html/querycriteria.html"&gt;criteria&lt;/a&gt;
object and without any value from your code since this generic
approach already exists.&lt;/p&gt;

&lt;p&gt;Frederick Brooks in the &lt;a href="http://en.wikipedia.org/wiki/The_Mythical_Man-Month" title="The Mythical Man-Month"&gt;Mythical Man-Month&lt;/a&gt; wrote about the &lt;em&gt;Pilot
System&lt;/em&gt;. This idea implies the construction of a &lt;em&gt;throw-away&lt;/em&gt; when
coding a new system. He argues that if you not plan you will
throw-away anyway. This idea agree with the &lt;em&gt;refactoring paradox&lt;/em&gt;, you
can´t &lt;em&gt;refactor&lt;/em&gt; before &lt;em&gt;factor&lt;/em&gt; and there´s no need for refactoring a
good code, but the chances to get it right on the first try is
minimal, I will make a bold statement that is impossible to get it
right on the first try.&lt;/p&gt;

&lt;h3&gt;Conclusions&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/The_Mythical_Man-Month" title="The Mythical Man-Month"&gt;Brooks&lt;/a&gt; is right, plan to a &lt;em&gt;throw-away&lt;/em&gt;, you will anyway, at
least part of the code will be replaced.&lt;/li&gt;
&lt;li&gt;Don´t fear rewriting, is part of the job, put it on your estimates.&lt;/li&gt;
&lt;li&gt;Software is &lt;em&gt;soft&lt;/em&gt; don´t try to make it &lt;em&gt;hard&lt;/em&gt;, is unnatural.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That´s it.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-3465721672212529731?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/3465721672212529731/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=3465721672212529731' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/3465721672212529731'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/3465721672212529731'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2009/09/software-philosophy-refactoring.html' title='Software Philosophy - Refactoring Paradox'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-7407921606482969859</id><published>2009-07-28T05:10:00.000-07:00</published><updated>2009-07-28T17:31:40.543-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='jpa'/><category scheme='http://www.blogger.com/atom/ns#' term='ejbql'/><category scheme='http://www.blogger.com/atom/ns#' term='orm'/><category scheme='http://www.blogger.com/atom/ns#' term='ejb3'/><category scheme='http://www.blogger.com/atom/ns#' term='jee'/><category scheme='http://www.blogger.com/atom/ns#' term='jpql'/><title type='text'>JPA, a little more complex example.</title><content type='html'>&lt;div style="text-align: center;"&gt;
&lt;/div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_UFTS2NrETHg/Sm-Qo2lZQVI/AAAAAAAAANc/pPmsfW2_OEA/s1600-h/mantis_project_rel.png"&gt;&lt;/a&gt;This week I was writing a tool to extract reports from &lt;a href="http://www.mantisbt.org/"&gt;Mantis Bugtrack&lt;/a&gt; using &lt;a href="http://en.wikipedia.org/wiki/Java_Persistence_API"&gt;JPA &lt;/a&gt;and &lt;a href="http://java.sun.com/products/ejb/"&gt;EJB3&lt;/a&gt;. Since I´m not good in JPQL (sonething like a &lt;a href="http://en.wikipedia.org/wiki/SQL"&gt;SQL&lt;/a&gt; for objects) the &lt;a href="http://www.google.com.br/search?q=JPQL"&gt;search &lt;/a&gt;for &lt;a href="http://edocs.bea.com/kodo/docs41/full/html/ejb3_langref.html"&gt;examples&lt;/a&gt; &lt;a href="http://www.jpox.org/docs/1_2/jpa/jpql.html"&gt;began&lt;/a&gt;. The problem was that all examples were too simple, here´s some notes one a more complex query and how was done.

Mantis is a bugtrack tool and allows a bug relationship and custom fields, my report will make use of both. Below is a simplified diagram of the database tables involved in this process.


&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_UFTS2NrETHg/Sm70wBdF6JI/AAAAAAAAANU/rdhTkXUvGhc/s1600-h/mantisbt.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 172px;" src="http://2.bp.blogspot.com/_UFTS2NrETHg/Sm70wBdF6JI/AAAAAAAAANU/rdhTkXUvGhc/s400/mantisbt.png" alt="" id="BLOGGER_PHOTO_ID_5363493312106195090" border="0" /&gt;&lt;/a&gt;
The scenario was 2 projects. The first (I will call it &lt;span style="font-weight: bold;"&gt;A&lt;/span&gt;) will open bugs for the second (from now called &lt;span style="font-weight: bold;"&gt;B&lt;/span&gt;) the bugs will be related. Example: A operator opens a bug in project &lt;span style="font-weight: bold;"&gt;A&lt;/span&gt;, after that &lt;span style="font-style: italic;"&gt;n&lt;/span&gt; other bugs are opened in project &lt;span style="font-weight: bold;"&gt;B&lt;/span&gt;, the relation between bugs is &lt;span style="font-weight: bold;"&gt;B&lt;/span&gt; are child of &lt;span style="font-weight: bold;"&gt;A&lt;/span&gt;. This relation is explicitly set using Mantis relationship features which will be reflected in our &lt;span style="font-weight: bold;"&gt;bug_relationship&lt;span style="font-weight: bold;"&gt; &lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;table. The last thing on this problem is that a custom field value should be retrieved too for a pivot transformation. Here's another diagram showing the relationship:&lt;div&gt;
&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(0, 0, 238); -webkit-text-decorations-in-effect: underline; "&gt;&lt;img src="http://2.bp.blogspot.com/_UFTS2NrETHg/Sm-Qo2lZQVI/AAAAAAAAANc/pPmsfW2_OEA/s400/mantis_project_rel.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5363664712743076178" style="display: block; margin-top: 0px; margin-right: auto; margin-bottom: 10px; margin-left: auto; text-align: center; cursor: pointer; width: 366px; height: 146px; " /&gt;&lt;/span&gt;&lt;div&gt;To not extend too much this post I will show a simplified version of the mapped entities. Gets, Sets, packages and imports were omitted for the sake of the reader.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;/div&gt;&lt;pre class="brush: java"&gt;
@Entity
@Table(name="mantis_project_table")
public class Project implements Serializable {
 @Id
 private int id;

 private String name;

 @OneToMany(mappedBy="project")
 private Collection&amp;lt;bug&amp;gt; bugs;

    // gets and sets omitted.
}

@Entity
@Table(name="mantis_bug_table")
public class Bug implements Serializable {
 @Id
 private int id;

 @Column(name="project_id",insertable=false,updatable=false)
 private int projectId;
 
 @ManyToOne
 private Project project;

      //gets and sets omitted
}

public enum BugRelationType {
 DUPLICATED(0),
 RELATED(1),
 DEPENDANT(2);

 private final int relationship;
 
 BugRelationType(int rel) {
  this.relationship = rel;
 }

 public Integer toInteger() {
  return Integer.valueOf(this.relationship);
 }

}

@Entity
@Table(name="mantis_custom_field_table")
public class CustomField implements Serializable {
 
 @Id
 private int id;

 private String name;

      // gets and sets omitted

}

@Entity
@Table(name="mantis_custom_field_string_table")
public class CustomFieldString implements Serializable {

 @EmbeddedId
 private CustomFieldStringPK pk;

 private String value;
}

@Embeddable
public class CustomFieldStringPK implements Serializable {

 private static final long serialVersionUID = 1L;

 @Column(name="field_id")
 private Integer fieldId;
 
 @Column(name="bug_id")
 private Integer bugId;
}
&lt;/pre&gt;
&lt;div&gt;Alright, with those entities in hand how we will compose a good JPQL without access the database more than one time? It's possible? Is possible to join all these entities? Those were my questions. The answer is affirmative, but to do so is not straight forward (at least for me) like when I'm writing SQL. &lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Here's is the final query:&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class="brush: sql"&gt;
SELECT 
    bt, cs.value  
FROM  
    CustomFieldString cs,  
    CustomField cf,  
    Project ps, IN (ps.bugs) bs, 
    Project pt, IN (pt.bugs) bt, 
    BugRelationship rel  
WHERE   
    ps = :projSource  
    AND pt = :projTarget  
    AND rel.sourceBugId = bs.id  
    AND rel.destinationBugId = bt.id  
    AND cs.pk.bugId   = bs.id  
    AND cs.pk.fieldId = cf.id  
    AND cf = :customField  
    AND rel.relationshipType = :relType  
&lt;/pre&gt;

&lt;div&gt;Now just fill up the named parameters and you have it, a fairly complex JPQL query.&lt;/div&gt;

&lt;div&gt;That's it.&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/1598881393381863026-7407921606482969859?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/7407921606482969859/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=7407921606482969859' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/7407921606482969859'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/7407921606482969859'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2009/07/jpa-little-more-complex-example.html' title='JPA, a little more complex example.'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_UFTS2NrETHg/Sm70wBdF6JI/AAAAAAAAANU/rdhTkXUvGhc/s72-c/mantisbt.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-5129305981244149257</id><published>2009-07-14T19:38:00.000-07:00</published><updated>2009-07-14T20:06:43.939-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='sql'/><category scheme='http://www.blogger.com/atom/ns#' term='business studio'/><category scheme='http://www.blogger.com/atom/ns#' term='proofs'/><category scheme='http://www.blogger.com/atom/ns#' term='bpmn'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='mathematics'/><category scheme='http://www.blogger.com/atom/ns#' term='tibco'/><category scheme='http://www.blogger.com/atom/ns#' term='oracle'/><category scheme='http://www.blogger.com/atom/ns#' term='edsger dijkstra'/><title type='text'>What is keeping me busy</title><content type='html'>Just a small update on stuff I'm doing in the past weeks.&lt;div&gt;
&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Creating Business Diagrams (&lt;a href="http://en.wikipedia.org/wiki/Business_Process_Modeling_Notation"&gt;BPMN&lt;/a&gt;) and Simulations in &lt;a href="http://developer.tibco.com/business_studio/"&gt;TIBCO Business Studio&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Getting serious in SQL with &lt;a href="http://download.oracle.com/docs/cd/B19306_01/server.102/b14200/functions001.htm#i81407"&gt;analytical functions of Oracle 10g&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Studying how to write mathematical proofs (book: &lt;a href="http://www.amazon.com/How-Prove-Structured-Daniel-Velleman/dp/0521675995/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1247625996&amp;amp;sr=1-1"&gt;How to Prove It&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;Reading (at last!) the classic &lt;a href="http://www.amazon.com/Mythical-Man-Month-Software-Engineering-Anniversary/dp/0201835959/ref=sr_1_1?ie=UTF8&amp;amp;s=books&amp;amp;qid=1247625955&amp;amp;sr=1-1"&gt;Frederick Brooks: The Mythical Man-Month&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Reading some of &lt;a href="http://www.cs.utexas.edu/~EWD/"&gt;Edsger Dijkstra writings&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;
&lt;/div&gt;&lt;div&gt;As you can see my current time in learning is devoted to mathematics, oracle and software development management. In short the mathematical is just improve my skills with logic and reasoning, the oracle study is for my current path to OCP and the management studies is for professional growth. &lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;On the shelve (not at particularly order):&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="http://www.amazon.com/Enterprise-Scrum-Ken-Schwaber/dp/0735623376"&gt;The Enterprise and Scrum&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.amazon.com/Software-Language-Engineering-Domain-Specific-Metamodels/dp/0321553454"&gt;Software Language Engineering&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.amazon.com/SOA-Practice-Distributed-System-Design/dp/0596529554"&gt;SOA in Practice&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;That's it.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-5129305981244149257?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/5129305981244149257/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=5129305981244149257' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/5129305981244149257'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/5129305981244149257'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2009/07/what-is-keeping-me-busy.html' title='What is keeping me busy'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-8210561121586080855</id><published>2009-05-25T16:29:00.000-07:00</published><updated>2009-05-25T18:49:18.506-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='patterns'/><category scheme='http://www.blogger.com/atom/ns#' term='software methodology'/><title type='text'>Technology Loop Paralysis - Anti-Pattern</title><content type='html'>&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Last Sunday I was in the "&lt;/span&gt;&lt;/span&gt;&lt;a href="http://www.caelum.com.br/falando-em-java/"&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Falando em Java 2009&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;" talking with a friend when we got in the subject of new technologies. During the conversation I realized one common anti-pattern that I didn't know about, the &lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Technology Loop Paralysis, &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;TLP for now on.&lt;/span&gt;&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; The &lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;TLP&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; has the following major characteristics:&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;It's seems right,  without attention can't be caught.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Once started, break the loop is hard.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Scrambles all current problems, so disguises itself.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;So, what is &lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;TLP&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;? &lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;TLP&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; is just the change of a technology, maybe a framework, a language or something similar to avoid difficulties in development. The catch is, when a new technology is added all kinds of problems will arise. &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;TLP &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Examples:&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Sometime ago me and another developer had problems in delivering changes to a legacy Java system, the system was poorly designed and any change could break a lot of unrelated features. When the difficulties were explained the manager asked "If we use PHP? Can we fix?".  This is a classic &lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;TLP. &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;The problem wasn't with the language, any effort had to be directed in refactoring not in language change. Experienced developers will notice that this is trap easy to fall, if the developers were inexperienced and more comfortable with PHP they could fall on this trap.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Another &lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;TLP&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; example. In a bugtrack system, developers didn't fill the forms right. Status, ETA and other fields were empty, they also didn't close issues properly. Relations were poorly added and resolutions were not written accordingly. Then, some reports were created to control issues, SLA and so on, but the data was not good. The solution proposed? Change the bugtrack system, but the system wasn't the problem, change it would only disguise all current problems.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;TLP&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; Effect:&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;New technologies will not solve any team, managing structure, unrealistic expectations and similar problems. Once &lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;TLP&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; started these problems will disguise as implementation problems. &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;TLP&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; Name Explanation:&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Technology: Any support system, framework, language or build block to a system.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Loop: The fact that when faced with problems, the team or management choose change the technology without know root cause of the problems faced.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Paralysis: The problems can't be solved and despite the feeling that something is been solved it's not.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;TLP&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; Forces:&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Technologies change and grow more rapidly than our systems, so before a team can finish one project is common that the supporting technologies have new and better versions. &lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Inexperience and anxiety for new features can lure the team and management to adopt every brand new technology around.&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;TLP Solution:&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Experience to avoid fall in &lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;TLP&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; in the first place.&lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-weight: normal; "&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;During a &lt;/span&gt;&lt;/span&gt;&lt;b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;TLP, &lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;span class="Apple-style-span"  style="font-family:verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;the team can stop looping and stick with a technology until it finishes the project. After finished, the upgrade should be considered harmful unless all implications are well understood.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/b&gt;&lt;/div&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/1598881393381863026-8210561121586080855?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/8210561121586080855/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=8210561121586080855' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/8210561121586080855'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/8210561121586080855'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2009/05/technology-loop-paralysis-anti-pattern.html' title='Technology Loop Paralysis - Anti-Pattern'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-1279683492342607964</id><published>2009-04-25T16:46:00.000-07:00</published><updated>2009-04-25T17:41:42.191-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='agile'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><title type='text'>Why Developers shouldn't work long hours.</title><content type='html'>&lt;div&gt;
&lt;/div&gt;&lt;div&gt;In fact this post should be named "Why anyone shouldn't work long hours". Face a problem for long hours, fighting a deadline it will not help, this should common sense, if not, try read about "&lt;a href="http://www.google.com/search?q=Sleep-dependent+memory+consolidation"&gt;Sleep-dependent memory consolidation&lt;/a&gt;". &lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;My point here is not about problem solving, performance and accidents, I think these topics are &lt;a href="http://www.cdc.gov/niosh/docs/2004-143/"&gt;well documented&lt;/a&gt;. But I want to add just one little information on why "long hours" are a problem.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;What happened to me this week is that I had to solve some personal matters, in fact, renew my drivers license. It took me almost a half of day and got me thinking. How come I can do this if my project was late? Stay with a expired driver license? Work until midnight? In either case I will get unsatisfied and worried, with this kind of mood how a good work can done?&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Some arguments against a "long hour" work is that people have to live outside the cubicle, but in fact there's some things more practical. We can't cope with all things we need to do if we are in a "long hour work" policy, there's no time. &lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Developers have to work on a normal scheduling, if not, the consequences are terrible. A tired developer with fall in the &lt;a href="http://en.wikipedia.org/wiki/Copy_and_paste_programming"&gt;easy solution&lt;/a&gt; to reach the deadline. This will lead to a less extensible code, that will lead to problems in module integration, that will make the final period of development a bug hunt and more long hours to find those. Well, what can happen if a you add tired developers, buggy code and deadline approach? Something has to give up. You can't make the developers more efficient with more long hours, the bugs will stay in the code until someone removes them, so the most common to give up is the deadline. The "long hour" solution turns to be longer that you expect.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;That's it.&lt;/div&gt;&lt;div&gt;
&lt;/div&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/1598881393381863026-1279683492342607964?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/1279683492342607964/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=1279683492342607964' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/1279683492342607964'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/1279683492342607964'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2009/04/why-developers-shouldnt-work-long-hours.html' title='Why Developers shouldn&apos;t work long hours.'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-1922462587605616323</id><published>2009-02-23T11:56:00.000-08:00</published><updated>2009-02-23T13:24:59.865-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='steve jobs'/><category scheme='http://www.blogger.com/atom/ns#' term='project management'/><category scheme='http://www.blogger.com/atom/ns#' term='book'/><category scheme='http://www.blogger.com/atom/ns#' term='apple'/><title type='text'>Inside Steve's Brain</title><content type='html'>I just finished the book &lt;a href="http://www.amazon.com/Inside-Steves-Brain-Leander-Kahney/dp/1591841984"&gt;Inside Steve's Brain&lt;/a&gt;, good book specially if you like Apple products like me. One tip about this book is not read the final notes of each chapter, mostly they are shallow summaries out of context.

The book detail some decisions and &lt;i&gt;modus operandi&lt;/i&gt; of Steve Jobs that I personally found very interesting, first because in most of times I agree (in my humble opinion), and secondly because it works, for everyone who knows about the computer market can see that some actions made by him are "default" on computer industry nowadays. Here some points made in the book:
&lt;ul&gt;
 &lt;li&gt;Small and good teams&lt;/li&gt;
 &lt;li&gt;Every one involved from begining to end&lt;/li&gt;
 &lt;li&gt;Avoid the "more features" trap, keep it simple&lt;/li&gt;
 &lt;li&gt;Prototype a lot&lt;/li&gt;
 &lt;li&gt;Keep focused, your user is the focus, but he/she doesn't know what really want&lt;/li&gt;
&lt;/ul&gt;
&lt;b&gt;Small and good teams&lt;/b&gt;

Probably is no news the that any team has to be assembled with good professionals, and &lt;a href="http://en.wikipedia.org/wiki/Brooks%27_law"&gt;adding more people don't help&lt;/a&gt;. And big teams will suffer with the &lt;code&gt;n(n-1)/2&lt;/code&gt; rule for communication channels, if your team is too big probably there's isn't a single view of what should be done.

&lt;b&gt;Everyone involved from begin to end&lt;/b&gt;

Well, the schema software engineers make the software, the designers the design, the marketing people the marketing and so on, doesn't work. In fact, I really believe that didn't work forever. Just ask yourself, in any point of your profession if people told you the big picture, not all the business plan, but a little more, things would  be done differently? Maybe a focus on modularity here and there, or a external configuration system or similar stuff. Probably, in my case, things will need less &lt;a href="http://www.ducttapeguys.com/NASA/index.html"&gt;duct tape&lt;/a&gt; if a more broad view is attached with the requirements.

&lt;b&gt;Avoid the more features trap, keep it simple&lt;/b&gt;

Too much people, including &lt;a href="http://keepcoding.blogspot.com/2008/01/7-things-developer-should-know-to.html"&gt;myself wrote about&lt;/a&gt; the &lt;a href="http://www.google.com.br/search?q=kiss+principle"&gt;KISS principle&lt;/a&gt;.

&lt;b&gt;Prototype a lot&lt;/b&gt;

I believe this is a true way to get good products. No body will get it right on the first shot specially on a complex system. &lt;a href="http://en.wikipedia.org/wiki/Software_prototyping"&gt;Software Prototyping&lt;/a&gt; is a valid approach in development, but it seems that in Apple &lt;a href="http://www.apple.com/macbook/design.html"&gt;every part of a product is prototyped&lt;/a&gt;. In case you're not convinced, they even prototyped the &lt;a href="http://kottke.org/07/03/apple-store-prototypes"&gt;Apple Store&lt;/a&gt;.

&lt;b&gt;Keep focused, your user is the focus, but he/she doesn't know what really want&lt;/b&gt;

Nobody will disagree that focus is important, but some will disagree that consumers don't know what they want. I'm part of a group that believes consumers (users in my case) feel what they want but are incapable of expressing it correctly, why? Because they don't know the tools you have, the possibilities you have in hand to build something. Is more safe to think they can feel a good experience and tell you "I'm  really comfortable using this software", than "I need a checkbox here, a list there and etc." 

People are subject to the &lt;a href="http://en.wikipedia.org/wiki/The_Paradox_of_Choice"&gt;Paradox of Choice&lt;/a&gt; and it seems that Steve Jobs knows this very well.

&lt;b&gt;Conclusion&lt;/b&gt;

This is just a glimpse of what I learned from the book, somethings reinforced my convictions others made me think. It's a very light reading and a good book for who works in this area or not.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-1922462587605616323?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/1922462587605616323/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=1922462587605616323' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/1922462587605616323'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/1922462587605616323'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2009/02/inside-steves-brain.html' title='Inside Steve&apos;s Brain'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-4489532994918677951</id><published>2009-02-18T16:00:00.000-08:00</published><updated>2009-02-18T20:07:16.840-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='testng'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='software testing'/><category scheme='http://www.blogger.com/atom/ns#' term='ant'/><category scheme='http://www.blogger.com/atom/ns#' term='selenium'/><category scheme='http://www.blogger.com/atom/ns#' term='junit'/><title type='text'>Running Selenium with TestNG</title><content type='html'>This week I had to rewrite a bunch of functional tests, mostly &lt;a href="http://seleniumhq.org"&gt;Selenium&lt;/a&gt; stuff. When I think about &lt;a href="http://www.google.com.br/search?q=java+unit+test"&gt;Java Unit tests&lt;/a&gt; the first thing that comes to my mind is the &lt;a href="http://www.junit.org/"&gt;JUnit&lt;/a&gt; framework. All tests that I have written until past week were with JUnit, and  &lt;a href="http://keepcoding.blogspot.com/2008/11/ant-power-cruise-under-control-and.html"&gt;was using it to run Selenium&lt;/a&gt;.

But I got one more requirement, since I was rewriting all tests I would like to change environments (development and pre-production) without dealing in the code where was running the tests. The problem was a simple one, just write configurations with URLs, expected values and so on, for each of my environments. A trivial example is using different URLs in selenium for the same tests. Well, how do this with JUnit?

&lt;b&gt;First approach, using JUnit 3&lt;/b&gt;

In JUnit 3 (old one) you have &lt;a href="http://pub.admc.com/howtos/junit3x/testsuite-chapter.html"&gt;Test Suites&lt;/a&gt;. Programatically you have a chance to read a properties file and give the information to your test classes. Well, this could work if I had not the principle: &lt;em&gt;"Do not write test code if isn't a test."&lt;/em&gt; When I caught myself creating a "little" framework to test my application I realized "I'm in the wrong way". Not that you should never code a "little" framework to simplify even more the tests, but i hadn't the time to do it.

&lt;b&gt;Second approach, using JUnit 4&lt;/b&gt;

Well, JUnit 4 is more flexible, newer and uses annotations; and I didn't explored it well. After some digging i found JUnit's &lt;a href="http://www.devx.com/Java/Article/31983/0/page/3"&gt;Parameterized Tests&lt;/a&gt;, but again I had (bear with me in this one) "to code, code to test code". And one more thing, JUnit 4 have &lt;a href="http://junit.org/junit/javadoc/4.5/org/junit/runners/Suite.html"&gt;Test Suites&lt;/a&gt; but, AFAIK, you only have a annotation version to define the classes for a suite.

&lt;b&gt;JUnit wasn't solving the problem&lt;/b&gt;

After some thought i had two choices, forget about environments, or spend some time coding new stuff that wasn't tests or my application. Justice has to be made, JUnit is a excellent test framework but I think my objectives weren't too "Unitwise". 

&lt;b&gt;TestNG, next generation?&lt;/b&gt;

I heard about &lt;a href="http://testng.org"&gt;TestNG&lt;/a&gt; about a year ago and didn't gave it enough attention, I was happy with JUnit. But, everyday is a new day and I had a problem, so I started to read about TestNG. I was skeptic at first, thinking "maybe this can do it, but I don't have time to learn it all". I was wrong, happily wrong.

&lt;b&gt;TestNG, next generation!&lt;/b&gt;

I have to confess, there's nothing to write here, maybe just some code. Remember the problem? "Two environments, one test, test it all". First, let me show the test example.

&lt;pre class="brush: java"&gt;
package com.keepcoding.test;

import static org.testng.AssertJUnit.*;
import org.testng.annotations.*;
import com.thoughtworks.selenium.*;

public class Google {

 private Selenium selenium;
 
 @BeforeClass
 @Parameters({"selenium.host","selenium.port","selenium.browser","selenium.url"})
 public void startSelenium(String host, String port, String browser, String url) {
  
  this.selenium = new DefaultSelenium(host, Integer.parseInt(port), browser, url);
        this.selenium.start();
        this.selenium.open(url);
 }
 
 @AfterClass(alwaysRun=true)
 public void stopSelenium() {
  this.selenium.stop();
 }
 
 @Test
 @Parameters({"search","expected"})
 public void googling(String search, String expected) {
  try {
   selenium.type("name=q", search);
   selenium.click("name=btnG");
   selenium.waitForPageToLoad("3000");
   assertTrue(selenium.isTextPresent(expected));
   
  } catch (SeleniumException e) {
   fail(e.getMessage());
  }
 }
}
&lt;/pre&gt;

This is a simple test, will start Selenium, open a URL (to be defined), type something (to be defined) and finally check if a text is present. Some notes:

&lt;ul&gt;
 &lt;li&gt;@AfterClass is defined with "always=true" because Selenium has to stop, even on test a failure.&lt;/li&gt;
 &lt;li&gt;Selenium commands are surrounded with a try/catch because I want to avoid ERROR statuses, better a FAILED status if Selenium fails.&lt;/li&gt;
&lt;/ul&gt;

Now let's look on TestNG configuration file:

&lt;pre class="brush: xml" &gt;
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" &gt;
 
&lt;suite name="DevelEnvSuite"  verbose="3" &gt;
    &lt;parameter name="selenium.host" value="localhost"&gt;&lt;/parameter&gt;
    &lt;parameter name="selenium.port" value="4545"&gt;&lt;/parameter&gt;
    &lt;parameter name="selenium.browser" value="*firefox"&gt;&lt;/parameter&gt;
    &lt;parameter name="selenium.url"  value="http://www.google.com"&gt;&lt;/parameter&gt;
  
  &lt;test name="Google" &gt;
    &lt;parameter name="search" value="Keep Coding"&gt;&lt;/parameter&gt;
    &lt;parameter name="expected" value="keepcoding.blogspot.com"&gt;&lt;/parameter&gt;
   &lt;classes&gt;
    &lt;class name="com.keepcoding.test.Google"&gt;&lt;/class&gt;
   &lt;/classes&gt;
  &lt;/test&gt;
  
&lt;/suite&gt;
&lt;/pre&gt;

Here I defined all parameters and what tests should run, as you probably guessed the test search on Google for "Keep Coding" and checks if this blog URL is in the results. The key thing is not the test itself, but it's setup. We have defined Selenium to open a certain URL and if we want change the URL is a simple case of editing the XML file. 

&lt;b&gt;Using Ant to test all environments&lt;/b&gt;

Finally, how test all environments? First, create another TestNG configuration file, change the parameters accordingly, and use Ant to run it all. Here's a build file example:

&lt;pre class="brush: xml; highlight: [36] "&gt;
&lt;?xml version="1.0"?&gt;
&lt;project name="testng_selenium" basedir="." default="build-all"&gt;

  &lt;property name="src.dir" value="src"&gt;&lt;/property&gt;
  &lt;property name="reports.dir" value="testng_reports"&gt;&lt;/property&gt;  
  &lt;property name="build.dir" value="bin"&gt;&lt;/property&gt;
  &lt;property name="lib.dir" value="lib"&gt;&lt;/property&gt;
  
  &lt;taskdef resource="testngtasks" classpath="${lib.dir}/testng-5.8-jdk15.jar"&gt;&lt;/taskdef&gt;
  
  &lt;path id="master-classpath"&gt;
   &lt;fileset dir="${lib.dir}"&gt;
  &lt;include name="*.jar"&gt;&lt;/include&gt;
 &lt;/fileset&gt;
  &lt;pathelement path="${build.dir}"&gt;&lt;/pathelement&gt;
  &lt;/path&gt;
  
  &lt;target name="clean" description="Removes build directory and test results."&gt;
  &lt;delete dir="${build.dir}"&gt;&lt;/delete&gt;
  &lt;delete dir="${reports.dir}"&gt;&lt;/delete&gt;
  &lt;/target&gt;
  
  &lt;target name="build" depends="clean" description="Build Java files."&gt;
    &lt;mkdir dir="${build.dir}"&gt;&lt;/mkdir&gt;
    &lt;javac destdir="${build.dir}" debug="true" deprecation="false" optimize="false" failonerror="true"&gt;
      &lt;src path="${src.dir}"&gt;&lt;/src&gt;
         &lt;classpath refid="master-classpath"&gt;&lt;/classpath&gt;
     &lt;/javac&gt;    
  &lt;/target&gt;
  
  &lt;target name="build-all" description="Build and test all, implies clean." depends="clean,build,tests"&gt;   
  &lt;/target&gt;
  
  &lt;target name="tests" description="Run testNG tests."&gt;
   &lt;mkdir dir="${reports.dir}" &gt;&lt;/mkdir&gt;
 &lt;testng classpathref="master-classpath" outputDir="${reports.dir}" sourcedir="${src.dir}" haltOnfailure="true"&gt;
  &lt;xmlfileset dir="${src.dir}" includes="*_suite.xml"&gt;&lt;/xmlfileset&gt;
 &lt;/testng&gt;
  &lt;/target&gt;

&lt;/project&gt;
&lt;/pre&gt;

This is a simple ant file, the highlighted part shows where you can have as much environments you want, for each one create a file changing parameters, skipping (not in production) tests and so on. TestNG will run one file after another for you.

&lt;b&gt;Conclusion&lt;/b&gt;

TestNG is really impressive, from very simple tests to complex environment tests, you have in hand a set of options to make it happen. When you mix TestNG with Selenium and Ant is possible to build very complex testing. TestNG goes beyond the "units" and provide what you need to think about "collections".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-4489532994918677951?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/4489532994918677951/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=4489532994918677951' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/4489532994918677951'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/4489532994918677951'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2009/02/running-selenium-with-testng.html' title='Running Selenium with TestNG'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-2715269213506343318</id><published>2009-02-08T10:56:00.000-08:00</published><updated>2009-02-17T19:09:29.067-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='ejb3'/><category scheme='http://www.blogger.com/atom/ns#' term='web services'/><category scheme='http://www.blogger.com/atom/ns#' term='architecture'/><category scheme='http://www.blogger.com/atom/ns#' term='versioning'/><category scheme='http://www.blogger.com/atom/ns#' term='jboss'/><category scheme='http://www.blogger.com/atom/ns#' term='soa'/><title type='text'>Web Services Versioning</title><content type='html'>I had a problem last week and it's about &lt;a href="http://en.wikipedia.org/wiki/Web_service"&gt;Web Services&lt;/a&gt; versioning. I &lt;a href="http://www.ibm.com/developerworks/webservices/library/ws-version/"&gt;read&lt;/a&gt; &lt;a href="http://soa.sys-con.com/node/44356"&gt;several&lt;/a&gt; &lt;a href="http://www.oracle.com/technology/pub/articles/web_services_versioning.html"&gt;posts&lt;/a&gt; &lt;a href="http://www.developer.com/services/article.php/3374631"&gt;about&lt;/a&gt; this issue but I didn't found a simple solution. Most solutions are somewhat complex using &lt;a href="http://en.wikipedia.org/wiki/Universal_Description_Discovery_and_Integration"&gt;UDDI&lt;/a&gt; or proprietary based, but my problem was very simple stated like "Once published a Web Service you cannot change it in a way you will brake your clients". So, with this constraint how to evolve your application without break your API or getting too duplicated code?

&lt;span style="font-weight: bold;"&gt;Use URLs with wisdom&lt;/span&gt;

First develop a strategy for your services URLs, put the version of your service inside the URL. In my case:
&lt;ul&gt;&lt;li&gt;http://myapphost/services/v[MAJOR]_[MINOR]/[SERVICE]&lt;/li&gt;&lt;/ul&gt;Here's a example:
&lt;ul&gt;&lt;li&gt;http://myapphost/services/v1_0/SomeGoodService&lt;/li&gt;&lt;li&gt;http://myapphost/services/v1_1/SomeGoodService&lt;/li&gt;&lt;/ul&gt;Note that you should keep the name of the service, this is very important! Same service same name. You don't want SomeGoodService, SomeGoodImprovedService, SomeGoodImprovedFastService to be the names.

For the WSDLs files I use the same reasoning.
&lt;ul&gt;&lt;li&gt;http://myapphost/wsdl/v1_0/SomeGoodService.wsdl&lt;/li&gt;&lt;/ul&gt;Or you can use dynamic WSDLs using functionality of the &lt;a href="http://ws.apache.org/axis/"&gt;webservice framework&lt;/a&gt;, I use JBoss so I can provide a WSDL dynamically.
&lt;ul&gt;&lt;li&gt; http://myapphost/services/v1_0/SomeGoodService?wsdl &lt;/li&gt;&lt;/ul&gt;Using a URL strategy is a good way to tell your client what version of your web service is in use, it's a fixed endpoint and remember that this URL will exists for a very long time.

&lt;span style="font-weight: bold;"&gt;Expose simple versions of your objects&lt;/span&gt;

When you have complex structures or dependencies on your objects this will be reflected inside your client code, so provide a simplification to your client.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_UFTS2NrETHg/SZC-J2CAQII/AAAAAAAAAJo/H0XItmZ-TCU/s1600-h/ws_simple_obj.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 98px;" src="http://2.bp.blogspot.com/_UFTS2NrETHg/SZC-J2CAQII/AAAAAAAAAJo/H0XItmZ-TCU/s400/ws_simple_obj.jpg" alt="" id="BLOGGER_PHOTO_ID_5300945837747093634" border="0" /&gt;&lt;/a&gt;
Such simplification pays off, avoiding complexities of &lt;a href="http://download.oracle.com/docs/cd/B25221_04/web.1013/b25603/apptypemapping.htm"&gt;XML type mapping&lt;/a&gt; is good because you don't know in what language your client will be developed. Making &lt;a href="http://cookbook.soaplite.com/#creating%20custom%20serializer"&gt;deserialization&lt;/a&gt; easy is a good thing.

For a example in my current app I had a object using some &lt;a href="http://joda-time.sourceforge.net/"&gt;joda time&lt;/a&gt; types, if I exposed such object to a web service lot of unnecessary complexity would flow into the client. To fix this I created a simple version of it, here's a simple method signature simplification:

&lt;span style="font-family:courier new;"&gt;void setBeginHour(LocalTime beginHour);&lt;/span&gt;

to

&lt;span style="font-family:courier new;"&gt;void setBeginHour(Calendar beginHour);&lt;/span&gt;

&lt;span style="font-weight: bold;"&gt;
Some dirty details&lt;/span&gt;

Well, enough with recommendations (language and application server agnostic), now let's look into some real implementation. My environment is Java 5 with a JBoss 4.2.2 as application server. I will use a simple web service called AgeService, given a birth date it tells how years old is the client.

Here's the package layout of my web service:

&lt;div style="text-align: left;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_UFTS2NrETHg/SZDmB-YgiuI/AAAAAAAAAJw/SRsFBGTFlXQ/s1600-h/Picture+1.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: left; cursor: pointer; width: 243px; height: 201px;" src="http://2.bp.blogspot.com/_UFTS2NrETHg/SZDmB-YgiuI/AAAAAAAAAJw/SRsFBGTFlXQ/s400/Picture+1.png" alt="" id="BLOGGER_PHOTO_ID_5300989683015125730" border="0" /&gt;&lt;/a&gt;
&lt;ul&gt;&lt;li&gt;br.com.svvs.model - Domain objects for internal use.&lt;/li&gt;&lt;li&gt;br.com.svvs.service - Web Service implementation package.
&lt;/li&gt;&lt;li&gt;br.com.svvs.service.model - Simplified versions of domain objects.&lt;/li&gt;&lt;li&gt;br.com.svvs.service.util - WSTypeAdapter  should translate domain to ws objects and vice-versa.&lt;/li&gt;&lt;/ul&gt;Now let's look into the Birth class:

&lt;pre class="brush: java"&gt;
package br.com.svvs.model;

import org.joda.time.DateTime;

public class Birth {

 private DateTime birthDate;

 public DateTime getBirthDate() {
   return this.birthDate;
 }

 public void setBirthDate(DateTime birthDate) {
   this.birthDate = birthDate;
 }

}
&lt;/pre&gt;

It's a very simple class, the problem is it uses DateTime from &lt;span style="font-weight: bold;"&gt;joda-time&lt;/span&gt; and I do not want expose such implementation detail. To hide this detail let's create a simplified version just for use on my service. Here's is the WSBirthV1_0:

&lt;pre class="brush: java" &gt;
package br.com.svvs.service.model;
import java.util.Calendar;

import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;


@XmlRootElement(
   name="wsBirth",
   namespace="http://wsbirth_1_0.model.service.svvs.com.br"
)
@XmlType(name="wsBirth")
public class WSBirthV1_0 implements WSBirth {

 private Calendar birthDate;

 public void setBirthDate(Calendar birthDate) {
   this.birthDate = birthDate;
 }

 public Calendar getBirthDate() {
   return birthDate;
 }

}
&lt;/pre&gt;

WSBirthV1_0 changes the signature to a simple Calendar object which most XML mappers know how to convert. Note WSBirthV1_0 implements WSBirth, this a marker interface we will use it in WSTypeAdapter, let's look at the code:

&lt;pre class="brush: java" &gt;
package br.com.svvs.service.util;

import org.joda.time.DateTime;

import br.com.svvs.model.Birth;
import br.com.svvs.service.model.WSBirth;
import br.com.svvs.service.model.WSBirthV1_0;

public class WSTypeAdapter {

 public static &amp;lt;T extends WSBirth&amp;gt; T convertTo(Class&amp;lt;T&amp;gt; type, Birth wsbirth) {
 
   String typeClassName = type.getSimpleName();
 
   if(typeClassName.equals("WSBirthV1_0")) {
     return type.cast(convertToWSBirthV1_0(wsbirth));
   } else {
     throw new RuntimeException("Don´t know how to convert " + typeClassName);
   }      
 }

 private static WSBirthV1_0 convertToWSBirthV1_0(Birth birthDate) {
   WSBirthV1_0 wsbirth = new WSBirthV1_0();
   wsbirth.setBirthDate(birthDate.getBirthDate().toCalendar(null));
   return wsbirth;
 }

 public static &amp;lt;T extends WSBirth&amp;gt; Birth createFrom(T wsbirth) {
 
   String versionName = wsbirth.getClass().getSimpleName();
 
   if(versionName.equals("WSBirthV1_0")) {
     return createFromWSBirthV1_0((WSBirthV1_0) wsbirth);
   }
   else {
     throw new RuntimeException("Don´t know how to produce Birth from " + versionName);
   }  
 }

 private static Birth createFromWSBirthV1_0(WSBirthV1_0 wsbirth) {
   Birth birth = new Birth();
   birth.setBirthDate(new DateTime(wsbirth.getBirthDate().getTimeInMillis()));
   return birth;
 }


}
&lt;/pre&gt;

In this class, using generics, we can provide a simple API to convert to and from ws objects. Note the use of our marker interface WSBirth. It's a utility class with static methods, we can grow our private methods for more and more versions. And at last, here's the service:

&lt;pre class="brush: java"&gt;
package br.com.svvs.service;

import javax.ejb.Stateless;
import javax.jws.WebService;

import org.jboss.wsf.spi.annotation.WebContext;
import org.joda.time.DateTime;
import org.joda.time.Interval;

import br.com.svvs.model.Birth;
import br.com.svvs.service.model.WSBirthV1_0;
import br.com.svvs.service.util.WSTypeAdapter;

@Stateless
@WebService(
   name="AgeService",
   serviceName="AgeService",
   targetNamespace="http://age_1_0.service.svvs.com.br"
)
@WebContext(
   contextRoot="/services",
   urlPattern="/v1_0/AgeService"
)
public class AgeService_1_0 {

 public String tellAge(WSBirthV1_0 wsbirth) {
 
   Birth birth = WSTypeAdapter.createFrom(wsbirth);
 
   System.out.println(birth.getBirthDate());
 
   Interval i = new Interval(birth.getBirthDate(), new DateTime(System.currentTimeMillis()));
 
   return "You have " + i.toPeriod().getYears() + " years old.";
 }

}
&lt;/pre&gt;

&lt;span style="font-weight: bold;"&gt;Discussion

&lt;/span&gt;At first it seems to much work but I disagree. When you have to maintain old web services and did not planned for code evolution this could raise much more work, usually with a copy and paste solution (happened to me).

Some good points about this solution:
&lt;ul&gt;&lt;li&gt;You can evolve your code without fear of breaking the old service, just follow the conventions.
&lt;/li&gt;&lt;li&gt;Isolated conversion from domain to ws objects, you don't forward ws objects inside the domain.&lt;/li&gt;&lt;li&gt;Control of what is exposed and how,  simplified client development.&lt;/li&gt;&lt;li&gt;It works.
&lt;/li&gt;&lt;/ul&gt;Some bad points:
&lt;ul&gt;&lt;li&gt;Messy names like ServiceV1_0, ServiceV1_2, WSObjectV1_0 ...&lt;/li&gt;&lt;li&gt;Care should be taken on annotations and namespaces.&lt;/li&gt;&lt;li&gt;If you have complex domain objects, you have to create a simplified version of each object used in your service.&lt;/li&gt;&lt;li&gt;Not simple enough, I still think that could be simpler.
&lt;/li&gt;&lt;/ul&gt; &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-2715269213506343318?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/2715269213506343318/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=2715269213506343318' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/2715269213506343318'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/2715269213506343318'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2009/02/web-services-versioning.html' title='Web Services Versioning'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_UFTS2NrETHg/SZC-J2CAQII/AAAAAAAAAJo/H0XItmZ-TCU/s72-c/ws_simple_obj.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-3875242608146990605</id><published>2008-12-22T17:23:00.000-08:00</published><updated>2008-12-22T18:28:19.547-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='software methodology'/><category scheme='http://www.blogger.com/atom/ns#' term='edsger dijkstra'/><title type='text'>Some thoughts about the real thing.</title><content type='html'>It's been some time that I'm feeling disappointed with software development, probably any developer felt this some day in his (her) career. Software is hard, hard to get it right, and things get pretty ugly when business requirements take place.

Despite all work done in better software management and development, still, get it right is hard. We surely have people who can make good software, I will cite &lt;a href="http://www.thoughtworks.com"&gt;ThoughtWorks&lt;/a&gt; as a example. But it seems to me that the distance from the day by day software from what is posted in &lt;a href="http://blogs.thoughtworks.com/"&gt;PlanetTW&lt;/a&gt; is enormous, at least by my experience.

One fact is that every company has/need some in house software, the big ones and the small ones. They have IT managers which were elected to hire developers in the field to write some code. The managers don't know what correctness means for software, and the developers know that with enough tries something eventually will work. Both far from know who was Edsger Dijkstra and understand the reasons why he wrote:
&lt;blockquote&gt;
Unfathomed misunderstanding is further revealed by the term "software maintenance", as a result of which many people continue to believe that programs - and even programming languages themselves - are subject to wear and tear.&lt;a href="http://www.cs.utexas.edu/users/EWD/ewd10xx/EWD1036.PDF"&gt; EWD1036&lt;/a&gt;.
&lt;/blockquote&gt;This is not just about shooting stones on everybody roof since my is made from glass too, I consider myself one more developer trying to make better code everyday. I'm probably not alone when I mention that the "best things I wrote were in spare time", and that was not because it was off-work code, it was work code, real work code, but I knew what needed to be done and dedicated myself to discover "how" should be done. Time not allowed in many companies.

The real world of today's developer seems a schizophrenic one. In one hand writing, modeling, saying, in the other hand not knowing if wrote, modeled or spoken the true.  Still amazes me how much "It works!" I hear in software development.

Best.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-3875242608146990605?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/3875242608146990605/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=3875242608146990605' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/3875242608146990605'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/3875242608146990605'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2008/12/some-thoughts-about-real-thing.html' title='Some thoughts about the real thing.'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-2101034419336811903</id><published>2008-11-20T06:41:00.000-08:00</published><updated>2008-11-20T07:36:00.528-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='manage'/><category scheme='http://www.blogger.com/atom/ns#' term='dependencies'/><category scheme='http://www.blogger.com/atom/ns#' term='cruise control'/><category scheme='http://www.blogger.com/atom/ns#' term='branch'/><category scheme='http://www.blogger.com/atom/ns#' term='ant'/><category scheme='http://www.blogger.com/atom/ns#' term='trunk'/><category scheme='http://www.blogger.com/atom/ns#' term='svn'/><title type='text'>Ant Power, Cruise under Control and Selenium Fuel (part 4): Managing dependencies in Cruise Control</title><content type='html'>On my &lt;a href="http://keepcoding.blogspot.com/2008/11/ant-power-cruise-under-control-and_3498.html"&gt;last post&lt;/a&gt; I mentioned about how to configure Cruise Control to build projects that depends on another project's artifacts. But I described only the configuration and how to find the latest artifact built. Now is time to show the build files of the projects and how they know what artifact to include. This can be simple as add one more classpath to Ant. But I have one more issue to solve, branches.

The problem here is, as many of you already know branches are &lt;a href="http://svnbook.red-bean.com/en/1.1/ch04s02.html"&gt;used to split the development tree&lt;/a&gt; so you can have all sort of things developed in parallel, like new features, bug fixes and so on.  In my case we usually have a main development tree and a bug fix tree. Of course I wanted that both trees were subject to Cruise Control, so the solution was call the bug fix project "project&lt;span style="color: rgb(255, 0, 0);"&gt;-release&lt;span style="color: rgb(102, 102, 102);"&gt;" and the main project just "project".

When you have such structure you have to &lt;a href="http://svnbook.red-bean.com/en/1.0/ch04s04.html"&gt;merge&lt;/a&gt; both trees from time to time, the problem was if my Ant build file in the release points to a release artifact and the trunk points to a trunk artifact, when they get to merge we always will have to take care of the difference. Not a good thing to do. This was extremely easy to solve because Cruise Control has a build call layout very good.

&lt;/span&gt;&lt;/span&gt;&lt;a style="color: rgb(102, 102, 102);" onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_UFTS2NrETHg/SSV9tvmOLcI/AAAAAAAAAJQ/5eqMN4Dl6Jw/s1600-h/cruise_state.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer; width: 288px; height: 346px;" src="http://4.bp.blogspot.com/_UFTS2NrETHg/SSV9tvmOLcI/AAAAAAAAAJQ/5eqMN4Dl6Jw/s400/cruise_state.jpg" alt="" id="BLOGGER_PHOTO_ID_5270757163731398082" border="0" /&gt;&lt;/a&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;Let's see how Cruise Control starts a build. First it sits and wait for a trigger, usually a commit on the SVN tree. After that if decides (it can subject to Queuing and Veto) to build the project, it calls a build file which has the name build-project.xml and inside that file another Ant call is made to actually run Ant on the project's build file.  The key thing is, you should put the differences on a trunk build or branch build inside this first build file. There, in my case, I define which artifact will be included in the path. Let's see for one project the Cruise Control configuration file and both build files.

Here for the trunk project:
&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;    &amp;lt;schedule interval="60"&amp;gt;
    &amp;lt;ant anthome="/usr/local/cruisecontrol/apache-ant-1.7.0"
    buildfile="build-project.xml"
    target="build"
    uselogger="true"
    usedebug="false"/&amp;gt;
  &amp;lt;/schedule&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
And now for the branch project:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;&lt;span style="color: rgb(102, 102, 102);"&gt;&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;    &amp;lt;schedule interval="60"&amp;gt;
    &amp;lt;ant anthome="/usr/local/cruisecontrol/apache-ant-1.7.0"
    buildfile="build-project-release.xml"
    target="build"
    uselogger="true"
    usedebug="false"/&amp;gt;
  &amp;lt;/schedule&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
The only difference if that Cruise Control calls build on different files for the branch project and for the trunk project. In these files I configure properties suited for each project. Here is the example of both files:

&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;&amp;lt;!-- build-project.xml --&amp;gt;
&amp;lt;!-- for the project (trunk) --&amp;gt;
&amp;lt;target name="build"&amp;gt;
&amp;lt;svn&amp;gt;
  &amp;lt;checkout url="http://localhost/svn/project/trunk" revision="HEAD" destPath="." /&amp;gt;
&amp;lt;/svn&amp;gt;
&amp;lt;ant antfile="build.xml" target="build-all"&amp;gt;
  &amp;lt;property name="moduleA.dir"    value="/var/cc-sandbox/artifacts/moduleA/latest" /&amp;gt;
  &amp;lt;property name="moduleB.dir"   value="/var/cc-sandbox/artifacts/moduleB/latest" /&amp;gt;
&amp;lt;/ant&amp;gt;
&amp;lt;/target&amp;gt;

&amp;lt;!-- build-project-release.xml --&amp;gt;
&amp;lt;!-- for the project-release (branch)--&amp;gt;
&amp;lt;target name="build"&amp;gt;
&amp;lt;svn&amp;gt;
  &amp;lt;checkout url="http://localhost/svn/project/branches/release_1_0" revision="HEAD" destPath="." /&amp;gt;
&amp;lt;/svn&amp;gt;
&amp;lt;ant antfile="build.xml" target="build-all"&amp;gt;
  &amp;lt;property name="moduleA.dir"    value="/var/cc-sandbox/artifacts/moduleA-release/latest" /&amp;gt;
  &amp;lt;property name="moduleB.dir"   value="/var/cc-sandbox/artifacts/moduleB-release/latest" /&amp;gt;
&amp;lt;/ant&amp;gt;
&amp;lt;/target&amp;gt;

&lt;/code&gt;&lt;/pre&gt;
Now, since Ant inherits this properties I have to just create one single build file which is the same for branch and trunk. For example:

&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;  &amp;lt;path id="internal-dep-classpath"&amp;gt;
   &amp;lt;!-- depends on moduleA project --&amp;gt;
   &amp;lt;fileset dir="${moduleA.dir}" &amp;gt;
     &amp;lt;include name="*.jar" /&amp;gt;
   &amp;lt;/fileset&amp;gt;
   &amp;lt;!-- depends on module B libraries --&amp;gt;
   &amp;lt;fileset dir="${moduleB.dir}" &amp;gt;
     &amp;lt;include name="*.jar" /&amp;gt;
   &amp;lt;/fileset&amp;gt;
 &amp;lt;/path&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

That's it. &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;span style="color: rgb(0, 0, 0);"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-2101034419336811903?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/2101034419336811903/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=2101034419336811903' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/2101034419336811903'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/2101034419336811903'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2008/11/nt-power-cruise-under-control-and.html' title='Ant Power, Cruise under Control and Selenium Fuel (part 4): Managing dependencies in Cruise Control'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_UFTS2NrETHg/SSV9tvmOLcI/AAAAAAAAAJQ/5eqMN4Dl6Jw/s72-c/cruise_state.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-4223474144076806009</id><published>2008-11-18T16:27:00.000-08:00</published><updated>2008-11-18T19:00:37.348-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='dependencies'/><category scheme='http://www.blogger.com/atom/ns#' term='cruise control'/><category scheme='http://www.blogger.com/atom/ns#' term='build'/><category scheme='http://www.blogger.com/atom/ns#' term='ant'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='project'/><category scheme='http://www.blogger.com/atom/ns#' term='continuous integration'/><title type='text'>Ant Power, Cruise under Control and Selenium Fuel (part 3): Projects that depends on others artifacts.</title><content type='html'>One thing I had to do when configuring &lt;a href="http://cruisecontrol.sourceforge.net/"&gt;CruiseControl&lt;/a&gt; for the first time was manage the dependencies between projects. It happens that my application project was a &lt;a href="http://en.wikipedia.org/wiki/EAR_%28file_format%29"&gt;EAR&lt;/a&gt; of three other projects (see the diagram below).

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_UFTS2NrETHg/SSNtj-lBCNI/AAAAAAAAAJI/5VlMxwl-c8o/s1600-h/projdeps.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 202px;" src="http://2.bp.blogspot.com/_UFTS2NrETHg/SSNtj-lBCNI/AAAAAAAAAJI/5VlMxwl-c8o/s400/projdeps.jpg" alt="" id="BLOGGER_PHOTO_ID_5270176453814716626" border="0" /&gt;&lt;/a&gt;Each of the modules (A,B and C) has a development tree and the JARs and WARs are assembled into the final EAR. For this reason I needed a way to identify the latest artifact of each project so it can be used to assemble the EAR.

Another thing that I had to manage is control the dependencies in the build loop, as you can see Module C depends on Module B, and Module B depends on Module A. If someone changes the Module A all other modules should be recompiled and assembled to ensure that the build is still possible. Now let's see one solution for this scenario.

&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_UFTS2NrETHg/SSNezmVrlBI/AAAAAAAAAI4/ATFPu6qyarI/s1600-h/cruisecontrol.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 300px; height: 275px;" src="http://3.bp.blogspot.com/_UFTS2NrETHg/SSNezmVrlBI/AAAAAAAAAI4/ATFPu6qyarI/s400/cruisecontrol.png" alt="" id="BLOGGER_PHOTO_ID_5270160229511435282" border="0" /&gt;&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;Projects that depends on others artifacts
&lt;/span&gt;&lt;div style="text-align: left;"&gt;&lt;span style="font-weight: bold;"&gt;
&lt;/span&gt;&lt;span&gt;First let's look into Modules inter dependencies. CruiseControl has a option called &lt;span style="font-weight: bold;"&gt;veto&lt;/span&gt; and is explained in &lt;a href="http://confluence.public.thoughtworks.org/display/CC/DependentProjects"&gt;this wiki entry&lt;/a&gt;.&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; &lt;/span&gt;&lt;span&gt;I took some time to understand how it work  but it worked well.

The key to understand the veto parameter is that instead of the "Module C depends on Module B" you have to think "Module B inhibits the build of Module C and Application EAR", in my case "&lt;span style="font-weight: bold;"&gt;Module A inhibits the build of Module B, Module C and Application EAR&lt;/span&gt;".

Another thing to note is the buildstatus parameter, which tell CruiseControl what triggers a build. In my case "&lt;span style="font-weight: bold;"&gt;Application EAR should be built if something changes on Module A, Module B, Module C or Application EAR&lt;/span&gt;". Below is listed the modificationset of the projects. 

&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;!-- module A --&amp;gt;   
&amp;lt;modificationset quietperiod=&amp;quot;10&amp;quot;&amp;gt;
  &amp;lt;veto&amp;gt;
    &amp;lt;triggers&amp;gt;
      &amp;lt;svn localworkingcopy=&amp;quot;projects/moduleB&amp;quot; /&amp;gt;
    &amp;lt;/triggers&amp;gt;
    &amp;lt;buildstatus logdir=&amp;quot;logs/moduleB&amp;quot;/&amp;gt;
  &amp;lt;/veto&amp;gt;
  &amp;lt;veto&amp;gt;
    &amp;lt;triggers&amp;gt;
      &amp;lt;svn localworkingcopy=&amp;quot;projects/moduleC&amp;quot; /&amp;gt;
    &amp;lt;/triggers&amp;gt;
    &amp;lt;buildstatus logdir=&amp;quot;logs/moduleC&amp;quot;/&amp;gt;
  &amp;lt;/veto&amp;gt;
  &amp;lt;veto&amp;gt;
    &amp;lt;triggers&amp;gt;
      &amp;lt;svn localworkingcopy=&amp;quot;projects/applicationEAR&amp;quot; /&amp;gt;
    &amp;lt;/triggers&amp;gt;
    &amp;lt;buildstatus logdir=&amp;quot;logs/applicationEAR&amp;quot;/&amp;gt;
  &amp;lt;/veto&amp;gt;
  &amp;lt;svn localworkingcopy=&amp;quot;projects/moduleA&amp;quot;/&amp;gt;
&amp;lt;/modificationset&amp;gt;

&amp;lt;!-- module B --&amp;gt;
&amp;lt;modificationset quietperiod=&amp;quot;10&amp;quot;&amp;gt;
  &amp;lt;veto&amp;gt;
    &amp;lt;triggers&amp;gt;
      &amp;lt;svn localworkingcopy=&amp;quot;projects/moduleC&amp;quot; /&amp;gt;
    &amp;lt;/triggers&amp;gt;
    &amp;lt;buildstatus logdir=&amp;quot;logs/moduleC&amp;quot;/&amp;gt;
  &amp;lt;/veto&amp;gt;
  &amp;lt;veto&amp;gt;
    &amp;lt;triggers&amp;gt;
      &amp;lt;svn localworkingcopy=&amp;quot;projects/applicationEAR&amp;quot; /&amp;gt;
    &amp;lt;/triggers&amp;gt;
    &amp;lt;buildstatus logdir=&amp;quot;logs/applicationEAR&amp;quot; /&amp;gt;
  &amp;lt;/veto&amp;gt;

  &amp;lt;buildstatus logdir=&amp;quot;logs/moduleA&amp;quot; /&amp;gt;

  &amp;lt;svn localworkingcopy=&amp;quot;projects/moduleB&amp;quot;/&amp;gt;
&amp;lt;/modificationset&amp;gt;

&amp;lt;!-- module C --&amp;gt;
&amp;lt;modificationset quietperiod=&amp;quot;10&amp;quot;&amp;gt;
  &amp;lt;veto&amp;gt;
    &amp;lt;triggers&amp;gt;
      &amp;lt;svn localworkingcopy=&amp;quot;projects/applicationEAR&amp;quot; /&amp;gt;
    &amp;lt;/triggers&amp;gt;
    &amp;lt;buildstatus logdir=&amp;quot;logs/applicationEAR&amp;quot; /&amp;gt;
  &amp;lt;/veto&amp;gt;

  &amp;lt;buildstatus logdir=&amp;quot;logs/moduleA&amp;quot; /&amp;gt;
  &amp;lt;buildstatus logdir=&amp;quot;logs/moduleB&amp;quot; /&amp;gt;

  &amp;lt;svn localworkingcopy=&amp;quot;projects/moduleC&amp;quot;/&amp;gt;
&amp;lt;/modificationset&amp;gt;

&amp;lt;!-- application EAR --&amp;gt;
&amp;lt;modificationset quietperiod=&amp;quot;10&amp;quot;&amp;gt;

  &amp;lt;buildstatus logdir=&amp;quot;logs/moduleA&amp;quot; /&amp;gt;
  &amp;lt;buildstatus logdir=&amp;quot;logs/moduleB&amp;quot; /&amp;gt;
  &amp;lt;buildstatus logdir=&amp;quot;logs/moduleC&amp;quot; /&amp;gt;

  &amp;lt;svn localworkingcopy=&amp;quot;projects/applicationEAR&amp;quot;/&amp;gt;
&amp;lt;/modificationset&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

With this configuration we have perfect build order. Now, as I mentioned, one project depends on it's predecessor, so Module B requires the artifact of Module A. To achieve this is just add in the build.xml file the path of the last artifact of Module A. But what is this path?

When CruiseControl creates an artifact will use a timestamp directory and to add this directory to the build environment in Ant was (for me) complex. The solution was use the good and old &lt;a href="http://en.wikipedia.org/wiki/Symbolic_link"&gt;symbolic link&lt;/a&gt; on Unix file systems. This pattern is not new, just add a symbolic link to current directory of interest, in this case the last artifact directory. So I've written another simple Perl script that does the job.

&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;#!/usr/bin/perl
# vim: expandtab sw=2 ts=2 bg=dark
# this script links the latest artifact
# to a latest directory so we can use
# the artifact as dependence of another
# project.
use strict;
use warnings;

my $ARTIFACT_DIR = &amp;quot;/var/cc-sandbox/artifacts&amp;quot;;
my $PROJECT_NAME = $ARGV[0];

die(&amp;quot;Missing project name.&amp;quot;) unless $PROJECT_NAME;

my $W_DIR = $ARTIFACT_DIR.&amp;quot;/$PROJECT_NAME&amp;quot;;

opendir(DIR,$W_DIR) or die $!;
  my @dirs = sort(grep { /^\d{14}$/ } readdir(DIR)); # list all dirs, sorted.
closedir(DIR);

# exit if we don't have artifacts.
exit if $#dirs == -1;

# latest directory is on the bottom of
# this array.
my $latest_dir = pop @dirs;

# if we have an latest link lets remove it.
if(-l &amp;quot;$W_DIR/latest&amp;quot;) {
  unlink(&amp;quot;$W_DIR/latest&amp;quot;);
}

# now we create de link to the latest artifact.
symlink(&amp;quot;$W_DIR/$latest_dir&amp;quot;,&amp;quot;$W_DIR/latest&amp;quot;) or die ($!);

exit;
&lt;/code&gt;&lt;/pre&gt;

This script receive as parameter the project name, enters the artifacts directory and creates a symbolic link to the lastest directory called "latest". To run this script just put it in the section publishers of CruiseControl config.xml. Here's a example for Module A project.

&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;publishers&amp;gt;
  &amp;lt;onsuccess&amp;gt;
    &amp;lt;artifactspublisher dest=&amp;quot;artifacts/${project.name}&amp;quot; file=&amp;quot;projects/${project.name}/target/moduleA.jar&amp;quot; /&amp;gt;
    &amp;lt;execute command=&amp;quot;bin/link_latest.pl ${project.name}&amp;quot; /&amp;gt;
  &amp;lt;/onsuccess&amp;gt;
&amp;lt;/publishers&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

After CruiseControl artifactspublishers task run I use execute task to create the link, now I will find the last artifact easily and any build.xml can refer to this directory.

That's it.
 
&lt;/span&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/1598881393381863026-4223474144076806009?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/4223474144076806009/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=4223474144076806009' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/4223474144076806009'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/4223474144076806009'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2008/11/ant-power-cruise-under-control-and_3498.html' title='Ant Power, Cruise under Control and Selenium Fuel (part 3): Projects that depends on others artifacts.'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_UFTS2NrETHg/SSNtj-lBCNI/AAAAAAAAAJI/5VlMxwl-c8o/s72-c/projdeps.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-5806978621650750093</id><published>2008-11-18T06:03:00.000-08:00</published><updated>2009-05-06T07:51:54.799-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='old'/><category scheme='http://www.blogger.com/atom/ns#' term='artifacts'/><category scheme='http://www.blogger.com/atom/ns#' term='cruise control'/><category scheme='http://www.blogger.com/atom/ns#' term='Remove'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Ant Power, Cruise under Control and Selenium Fuel (part 2): Removing old artifacts from CruiseControl.</title><content type='html'>One thing I had to do when using &lt;a href="http://cruisecontrol.sourceforge.net/"&gt;CruiseControl&lt;/a&gt; is remove old artifacts. Since my CruiseControl starts a build on every commit in times of fast development this causes the creation of lots of artifacts. You probably don´t want to keep all of them since your server disk will get full.

Looking at CruiseControl configuration I found a &lt;a href="http://cruisecontrol.sourceforge.net/main/configxml.html#deleteartifacts"&gt;parameter for deletion of artifacts&lt;/a&gt;, but it is limited to check the age of an artifact and &lt;a href="http://webui.sourcelabs.com/cruisecontrol/mail/user/threads/Trimming_Old_Artifacts.meta"&gt;people said&lt;/a&gt; that this configuration assumes your artifacts inside the log directory. When I had CruiseControl setup my artifacts directory is outside of logs/ (I used the &lt;span style="font-weight: bold;"&gt;config.xml&lt;/span&gt; example that comes with CruiseControl and there the  &lt;span style="font-weight: bold;"&gt;artifactpublisher &lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;/span&gt;is configured to a outside directory) so use &lt;span style="font-weight: bold;"&gt;deleteartifacts&lt;/span&gt; wasn´t a option.

&lt;span style="text-decoration: underline;"&gt;Exist a &lt;/span&gt;&lt;a href="http://confluence.public.thoughtworks.org/display/CC/DeleteOldArtifactsWorkAround"&gt;wiki entry&lt;/a&gt; about this but also deletes artifacts based only on age. This is not what I want. If a project doesn´t build for a long time all artifacts will be removed and no last version of the artifact will be available. What I did is just code a simple Perl script that does the job based on age but keeps some artifacts.
&lt;div style="text-align: center;"&gt;&lt;div style="text-align: left;"&gt;
&lt;/div&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_UFTS2NrETHg/SSLngJhNczI/AAAAAAAAAIY/s2PV_Uk0QcM/s1600-h/cruisecontrol.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 300px; height: 275px;" src="http://2.bp.blogspot.com/_UFTS2NrETHg/SSLngJhNczI/AAAAAAAAAIY/s2PV_Uk0QcM/s400/cruisecontrol.png" alt="" id="BLOGGER_PHOTO_ID_5270029053473944370" border="0" /&gt;&lt;/a&gt;

&lt;span style="font-weight: bold;"&gt;Removing old artifacts from CruiseControl&lt;/span&gt;
&lt;/div&gt;
This script should be run by cron at any interval rate you want. There three parameters configurable, the first (MAX_AGE_IN_DAYS) is very clear, how many days old a artifact should be to be removed. The second (MIN_ARTIFACTS_TO_KEEP) tell the script to keep some artifacts even if they´re old enough to be deleted. And the third (ARTIFACTS_DIR) points to your artifacts directory.

The script is pretty simple but solves my problem, keep some of the artifacts while removing too old ones. Here´s the code:

&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;#!/usr/bin/perl
# vim: sw=2 ts=2 expandtab bg=dark
# this script removes old artifacts from cruisecontrol
# to avoid full disk. You can configure a min number
# of artifacts to keep and how many days old a artifact
# is considered too old and should be removed.
# Marco Valtas - 2008.
use strict;
use warnings;
use File::stat;
use File::Path;

################
# configuration session.

# artifacts older than this will be removed.
use constant MAX_AGE_IN_DAYS  =&amp;gt; 10;
# keep at least this number of artifacts.
use constant MIN_ARTIFACTS_TO_KEEP =&amp;gt; 5;
# where we find the artifacts?
use constant ARTIFACTS_DIR =&amp;gt; "/var/cc-sandbox/artifacts";

# end of configuration
################


# open artifacts dir to list all projects.
opendir(ART_DIR,ARTIFACTS_DIR) or die $!;
 # list all projects, skip "." files.
 my @projects = grep { /^[^.]/ } readdir(ART_DIR);
closedir(ART_DIR);

# exit if no project was found.
exit if $#projects == -1;

# foreach project, we dig to find
# all artifacts directories.
foreach my $project (@projects) {

 # project artifacts directory.
 my $W_DIR = ARTIFACTS_DIR."/$project";

 opendir(PROJECT_DIR,$W_DIR) or die $!;
   # list all dirs, sorted so old dirs are first.
   my @artifacts = sort(grep { /^\d{14}$/ } readdir(PROJECT_DIR));
 closedir(PROJECT_DIR);

 # skip this project if not enough artifacts were found.
 next if $#artifacts &lt; MIN_ARTIFACTS_TO_KEEP;

 # for each artifact found (skipping the ones we want to keep)
 # check the age and remove it if necessary.
 foreach my $idx (0..$#artifacts - MIN_ARTIFACTS_TO_KEEP) {
 
   # how many days old is this directory?
   my $stat = stat($W_DIR."/$artifacts[$idx]");
   my $days_old =  int((time - $stat-&amp;gt;mtime) /86400);

   # remove the artifact dir if is too old.
   if($days_old &amp;gt; MAX_AGE_IN_DAYS) {
     rmtree($W_DIR."/$artifacts[$idx]");
   }
 }
}
&lt;/code&gt;&lt;/pre&gt;

That´s it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-5806978621650750093?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/5806978621650750093/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=5806978621650750093' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/5806978621650750093'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/5806978621650750093'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2008/11/ant-power-cruise-under-control-and_18.html' title='Ant Power, Cruise under Control and Selenium Fuel (part 2): Removing old artifacts from CruiseControl.'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_UFTS2NrETHg/SSLngJhNczI/AAAAAAAAAIY/s2PV_Uk0QcM/s72-c/cruisecontrol.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-7160685622012151572</id><published>2008-11-17T16:54:00.000-08:00</published><updated>2008-11-17T18:35:39.191-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='cruise control'/><category scheme='http://www.blogger.com/atom/ns#' term='ant'/><category scheme='http://www.blogger.com/atom/ns#' term='selenium'/><category scheme='http://www.blogger.com/atom/ns#' term='continuous integration'/><title type='text'>Ant Power, Cruise under Control and Selenium Fuel (part 1): Can we run selenium?</title><content type='html'>In the past weeks I'm configuring a &lt;a href="http://martinfowler.com/articles/continuousIntegration.html"&gt;Continuous Integration&lt;/a&gt; environment  with &lt;a href="http://cruisecontrol.sourceforge.net/"&gt;CruiseControl&lt;/a&gt;. It wasn't a easy task. CruiseControl lacks from updated documentation and you have to know &lt;a href="http://ant.apache.org/"&gt;Ant&lt;/a&gt; very well (in my view) to get along with it. Since Ant isn't a easy thing to learn (again, in my view) I had some hard time putting all to work. In this series &lt;span style="font-weight: bold;"&gt;Ant Power, Cruise under Control and Selenium&lt;/span&gt;&lt;span style="font-weight: bold;"&gt; fuel&lt;/span&gt;, I'll try to show some of what I have learned.

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_UFTS2NrETHg/SSIU7ZJJJxI/AAAAAAAAAII/1V4gMQHu8gc/s1600-h/atomicant.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 141px; height: 154px;" src="http://3.bp.blogspot.com/_UFTS2NrETHg/SSIU7ZJJJxI/AAAAAAAAAII/1V4gMQHu8gc/s400/atomicant.png" alt="" id="BLOGGER_PHOTO_ID_5269797524570973970" border="0" /&gt;&lt;/a&gt;

&lt;div style="text-align: center;"&gt;&lt;span style="font-weight: bold;"&gt;Can we run &lt;a href="http://selenium.seleniumhq.org/"&gt;selenium&lt;/a&gt;?&lt;/span&gt;

&lt;div style="text-align: left;"&gt;One not always in cookbooks is conditional behavior of Ant. Ant is capable of a myriad of conditionals but if you look at the &lt;a href="http://ant.apache.org/manual/index.html"&gt;official manual&lt;/a&gt; you will not find a good example on how to use it. So let's see how Ant was used in my project.

As you probably know, &lt;a href="http://selenium.seleniumhq.org/"&gt;Selenium&lt;/a&gt; is a test framework that can emulates a user using a browser. It's a good way to automate &lt;a href="http://en.wikipedia.org/wiki/Acceptance_testing"&gt;acceptance tests&lt;/a&gt;. But to run selenium the project has to successfully be deployed on server, so how to know if the project was deployed?
&lt;ul&gt;&lt;li&gt;First: Learn target depends&lt;/li&gt;&lt;/ul&gt;Ant can establish dependencies between targets, here a simple build.xml file.

&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;project name=&amp;quot;target_depends&amp;quot; default=&amp;quot;build&amp;quot;&amp;gt;
    &amp;lt;target name=&amp;quot;setup&amp;quot;&amp;gt;
            &amp;lt;echo message=&amp;quot;initial setup.&amp;quot; /&amp;gt;
    &amp;lt;/target&amp;gt;
    &amp;lt;target name=&amp;quot;build&amp;quot; depends=&amp;quot;setup&amp;quot;&amp;gt;
            &amp;lt;echo message=&amp;quot;building...&amp;quot; /&amp;gt;
    &amp;lt;/target&amp;gt;
&amp;lt;/project&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

When you run this build file you get this:

&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;$ ant -f a.xml build
Buildfile: a.xml

setup:
     [echo] initial setup.

build:
     [echo] building...

BUILD SUCCESSFUL
Total time: 0 seconds
&lt;/code&gt;&lt;/pre&gt;

What happens is that the target &lt;span style="font-weight: bold;"&gt;build&lt;/span&gt; declares a dependency which is the target &lt;span style="font-weight: bold;"&gt;setup&lt;/span&gt;, so Ant takes care to execute &lt;span style="font-weight: bold;"&gt;setup&lt;/span&gt; before &lt;span style="font-weight: bold;"&gt;build&lt;/span&gt;. Nothing too complex until now.
&lt;ul&gt;&lt;li&gt;Second: Learn target if/unless&lt;/li&gt;&lt;/ul&gt;Something clever about Ant is the if/unless attributes on target element, you can abort the execution of a target if you need to. In the next build file we have three targets, the first inhibits the execution of the second.

&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;project name=&amp;quot;target_depends&amp;quot; default=&amp;quot;build&amp;quot;&amp;gt;
    &amp;lt;target name=&amp;quot;setup&amp;quot;&amp;gt;
            &amp;lt;echo message=&amp;quot;initial setup.&amp;quot;/&amp;gt;
            &amp;lt;property name=&amp;quot;setup_is_ok&amp;quot; value=&amp;quot;&amp;quot;/&amp;gt;
    &amp;lt;/target&amp;gt;
    &amp;lt;target name=&amp;quot;notify_failed_setup&amp;quot; unless=&amp;quot;setup_is_ok&amp;quot;&amp;gt;
            &amp;lt;echo message=&amp;quot;setup failed.&amp;quot;/&amp;gt;
    &amp;lt;/target&amp;gt;
    &amp;lt;target name=&amp;quot;build&amp;quot; depends=&amp;quot;setup,notify_failed_setup&amp;quot;&amp;gt;
            &amp;lt;echo message=&amp;quot;building.&amp;quot;/&amp;gt;
    &amp;lt;/target&amp;gt;
&amp;lt;/project&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

When you run this build file:

&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;$ ant -f a.xml build
Buildfile: a.xml

setup:
     [echo] initial setup.

notify_failed_setup:

build:
     [echo] building.

BUILD SUCCESSFUL
Total time: 0 seconds

&lt;/code&gt;&lt;/pre&gt;

You can note that when we set the property &lt;span style="font-weight: bold;"&gt;setup_is_ok&lt;/span&gt; and since the next target on the chain, &lt;span style="font-weight: bold;"&gt;notify_failed_setup&lt;/span&gt;, has a &lt;span style="font-weight: bold;"&gt;unless&lt;/span&gt; attribute this target will not be fired. The catch here is on the &lt;span style="font-weight: bold;"&gt;depends&lt;/span&gt; of the &lt;span style="font-weight: bold;"&gt;build&lt;/span&gt; target, it tell us the order of our build. Ant doesn't have a &lt;span style="font-weight: bold;"&gt;if/then/else&lt;/span&gt; &lt;span style="font-style: italic;"&gt;per se,&lt;/span&gt; but with &lt;span style="font-weight: bold;"&gt;depends&lt;/span&gt; and &lt;span style="font-weight: bold;"&gt;if/unless&lt;/span&gt; attributes on the &lt;span style="font-weight: bold;"&gt;target&lt;/span&gt; element you can do similar behavior.

&lt;code&gt;
&amp;lt;target name="build" depends="setup,notify_failed_setup"&amp;gt;
&lt;/code&gt;
&lt;ul&gt;&lt;li&gt;Last: A simple &lt;span style="font-weight: bold;"&gt;waitfor&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;For the last step I will use &lt;span style="font-weight: bold;"&gt;waitfor&lt;/span&gt; to know if a project have been successfully deployed, if it is, then we run tests, if is not, I will email me to know that my project isn't deployed.

&lt;pre style="font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%"&gt;&lt;code&gt;&amp;lt;project name=&amp;quot;cond_demo&amp;quot; default=&amp;quot;run_tests&amp;quot; &amp;gt;

  &amp;lt;target name=&amp;quot;check_if_page_exists&amp;quot;&amp;gt;
    &amp;lt;waitfor maxwait=&amp;quot;5&amp;quot; maxwaitunit=&amp;quot;second&amp;quot; checkevery=&amp;quot;1000&amp;quot; timeoutproperty=&amp;quot;page_not_loaded&amp;quot;&amp;gt;
      &amp;lt;http url=&amp;quot;http://localhost/&amp;quot;/&amp;gt;
    &amp;lt;/waitfor&amp;gt;
  &amp;lt;/target&amp;gt;

  &amp;lt;target name=&amp;quot;email_failed_deployment&amp;quot; if=&amp;quot;page_not_loaded&amp;quot;&amp;gt;
    &amp;lt;mail
      from=&amp;quot;Cruise Control&amp;quot;
      tolist=&amp;quot;me&amp;quot;
      subject=&amp;quot;Failed to deploy project: ${ant.project.name}&amp;quot;/&amp;gt;
  &amp;lt;/target&amp;gt;
                 
  &amp;lt;target name=&amp;quot;run_tests&amp;quot; depends=&amp;quot;check_if_page_exists,email_failed_deployment&amp;quot; unless=&amp;quot;page_not_loaded&amp;quot;&amp;gt;
    &amp;lt;echo message=&amp;quot;Will run some tests!&amp;quot; /&amp;gt;
  &amp;lt;/target&amp;gt;

&amp;lt;/project&amp;gt;$

&lt;/code&gt;&lt;/pre&gt;

Now I have some smart behavior, if Ant can't load the page in waitfor in 5 seconds, it will set the property &lt;span style="font-weight: bold;"&gt;page_not_loaded&lt;/span&gt;, this will validate the call to target &lt;span style="font-weight: bold;"&gt;email_failed_deployment&lt;/span&gt; and invalidate the call to target &lt;b&gt;run_tests&lt;/b&gt;.

The &lt;span style="font-weight: bold;"&gt;waitfor&lt;/span&gt; task returns ok if the server returns a code 200, if the server returns 404 the &lt;span style="font-weight: bold;"&gt;waitfor&lt;/span&gt; continues until maxwait. Since during deployment (in JBoss) the server returns 404, for my setup is a way to test a successful deployment. The run of this last build file I leave to the reader. 

One last word, use &lt;code&gt;ant -debug&lt;/code&gt; in these build examples to see exactly how Ant works these files. 

That's it.

&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/1598881393381863026-7160685622012151572?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/7160685622012151572/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=7160685622012151572' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/7160685622012151572'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/7160685622012151572'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2008/11/ant-power-cruise-under-control-and.html' title='Ant Power, Cruise under Control and Selenium Fuel (part 1): Can we run selenium?'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_UFTS2NrETHg/SSIU7ZJJJxI/AAAAAAAAAII/1V4gMQHu8gc/s72-c/atomicant.png' height='72' width='72'/><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-2290494758331694369</id><published>2008-10-25T19:49:00.001-07:00</published><updated>2008-10-29T06:20:47.970-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='session bean'/><category scheme='http://www.blogger.com/atom/ns#' term='dependence injection'/><category scheme='http://www.blogger.com/atom/ns#' term='stateful beans'/><category scheme='http://www.blogger.com/atom/ns#' term='ejb3'/><category scheme='http://www.blogger.com/atom/ns#' term='glassfish'/><category scheme='http://www.blogger.com/atom/ns#' term='Remove'/><category scheme='http://www.blogger.com/atom/ns#' term='jboss'/><title type='text'>Stateful Session Beans, Dependence Injection and @Remove annotation.</title><content type='html'>This week I had a doubt about removing Stateful Session Beans (SFSB). Working on a heavy loaded EJB3 application with about 3K objects been created in a single operation I had to watch very closely the performance of my application. The doubt was: &lt;span style="font-style: italic;"&gt;"In a Stateful Session Bean which uses another Stateful Session Bean that was injected by the container has to be removed explicitly or the container removes it as soon the first bean is removed?"&lt;/span&gt;  Sounds complicated but isn't I will give a example.

If you have studied the life cycle of a &lt;a href="http://www.mastertheboss.com/en/jboss-server/47-ejb-session-beans-.html"&gt;Stateful Bean&lt;/a&gt; you already knows that as soon the container creates a instance of the Bean it starts to fulfill the Beans dependencies. Here's a simple Bean called SFSBFirst, here's the interface:

&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;
&lt;code&gt;package br.com.svvs;
import javax.ejb.Remote;

@Remote
public interface SFSBFirst {
 void call(String message);
 void remove();
}
&lt;/code&gt;&lt;/pre&gt;

And here is the implementation:

&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;package br.com.svvs;

import javax.annotation.PreDestroy;
import javax.ejb.EJB;
import javax.ejb.Remove;
import javax.ejb.Stateful;

@Stateful
public class SFSBFirstBean implements SFSBFirst {

 @EJB private SFSBSecond ssbSecond;

 private String message;

 @Override
 public void call(String message) {
     this.message = message;
     System.out.println(SFSBFirst.class.getName() + ": called(" + message + ")");
     ssbSecond.call(message);
 }

 @Override
 @Remove
 public void remove() {
     System.out.println(SFSBFirst.class.getName() + ": removing(" + this.message + ")");
     //ssbSecond.remove();
 }

 @PreDestroy
 public void preDestroy() {
     System.out.println(SFSBFirst.class.getName() + ": destroying(" + this.message + ")");
 }

}

&lt;/code&gt;&lt;/pre&gt;

This bean declares two exposed methods &lt;code&gt;call(String message)&lt;/code&gt; and &lt;code&gt;remove()&lt;/code&gt;, and ask for the container to inject the bean &lt;code&gt;SFSBSecond&lt;/code&gt;. It also annotate a method with &lt;code&gt;@PreDestroy&lt;/code&gt; which makes the container call it before garbage collect the bean.

It's a simple bean just to check if I have to call &lt;code&gt;remove()&lt;/code&gt; on &lt;code&gt;SFSBSecond&lt;/code&gt; or not. So let's look on &lt;code&gt;SFSBSecond&lt;/code&gt; interface:

&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;package br.com.svvs;

import javax.ejb.Remote;

@Remote
public interface SFSBSecond {
 void call(String message);
 void remove();
}
&lt;/code&gt;&lt;/pre&gt;

And the implementation:

&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;package br.com.svvs;

import javax.annotation.PreDestroy;
import javax.ejb.Remove;
import javax.ejb.Stateful;

@Stateful
public class SSBSecondBean implements SFSBSecond {

 private String message;

 @Override
 public void call(String message) {
     this.message = message;
     System.out.println(SFSBSecond.class.getName() + ": called(" + this.message + ")");
 }

 @Override
 @Remove
 public void remove() {
     System.out.println(SFSBSecond.class.getName() + ": removing(" + this.message + ")");
 }

 @PreDestroy
 public void preDestroy() {
     System.out.println(SFSBSecond.class.getName() + ": destroying(" + this.message + ")");
 }

}
&lt;/code&gt;&lt;/pre&gt;

Still a simple bean too, and now let's look at the test code:

&lt;pre style="border: 1px dashed rgb(153, 153, 153); padding: 5px; overflow: auto; font-family: Andale Mono,Lucida Console,Monaco,fixed,monospace; color: rgb(0, 0, 0); background-color: rgb(238, 238, 238); font-size: 12px; line-height: 14px; width: 100%;"&gt;&lt;code&gt;import javax.naming.InitialContext;
import javax.naming.NamingException;

import br.com.svvs.SFSBFirst;

public class Test {
 public static void main(String[] args) throws NamingException {
     InitialContext ic = new InitialContext();
 
     SFSBFirst ssb = (SFSBFirst) ic.lookup("SFSBFirstBean/remote");
 
     ssb.call("Hello World!");
     ssb.remove();
 }

}
&lt;/code&gt;&lt;/pre&gt;

&lt;span style="font-size:130%;"&gt;Results&lt;/span&gt;

&lt;span style="font-size:100%;"&gt;I used &lt;a href="http://www.jboss.org/jbosstm/downloads/4.2.2"&gt;JBoss 4.2.2 GA&lt;/a&gt; on my tests, the first run I did not removed explicitly the injected bean.&lt;/span&gt; Here's the output:

&lt;pre&gt;
01:09:11,089 INFO  [STDOUT] br.com.svvs.SFSBFirst: called(Hello World!)
01:09:11,142 INFO  [STDOUT] br.com.svvs.SFSBSecond: called(Hello World!)
01:09:11,161 INFO  [STDOUT] br.com.svvs.SFSBFirst: removing(Hello World!)
01:09:11,162 INFO  [STDOUT] br.com.svvs.SFSBFirst: destroying(Hello World!)
&lt;/pre&gt;

As you can see &lt;code&gt;SFSBSecond&lt;/code&gt; was not removed. So if I want to remove it, I have to explicitly call &lt;code&gt;remove()&lt;/code&gt; on the second bean during the &lt;code&gt;remove()&lt;/code&gt; of the first bean. The second run was made calling &lt;code&gt;remove()&lt;/code&gt;:

&lt;pre&gt;
01:11:51,702 INFO  [STDOUT] br.com.svvs.SFSBFirst: called(Hello World!)
01:11:51,706 INFO  [STDOUT] br.com.svvs.SFSBSecond: called(Hello World!)
01:11:51,714 INFO  [STDOUT] br.com.svvs.SFSBFirst: removing(Hello World!)
01:11:51,719 INFO  [STDOUT] br.com.svvs.SFSBSecond: removing(Hello World!)
01:11:51,721 INFO  [STDOUT] br.com.svvs.SFSBSecond: destroying(Hello World!)
01:11:51,721 INFO  [STDOUT] br.com.svvs.SFSBSecond: destroying(Hello World!)
01:11:51,721 INFO  [STDOUT] br.com.svvs.SFSBFirst: destroying(Hello World!)
&lt;/pre&gt;

This time &lt;code&gt;SFSBSecond&lt;/code&gt; was removed, but I am not sure why it appears to be called two times, probably a JBoss bug.

Since a second opinion is always good let's see how the &lt;a href="https://glassfish.dev.java.net/"&gt;glassfish v2&lt;/a&gt; application server behaves. The first test was not calling &lt;code&gt;remove()&lt;/code&gt; on &lt;code&gt;SFSBSecond&lt;/code&gt;:

&lt;pre&gt;
[#|2008-10-29T02:37:08.263-0200|INFO|br.com.svvs.SFSBFirst: called(Hello World!)|#]
[#|2008-10-29T02:37:08.264-0200|INFO|br.com.svvs.SFSBSecond: called(Hello World!)|#]
[#|2008-10-29T02:37:08.267-0200|INFO|br.com.svvs.SFSBFirst: removing(Hello World!)|#]
[#|2008-10-29T02:37:08.267-0200|INFO|br.com.svvs.SFSBFirst: destroying(Hello World!)|#]
&lt;/pre&gt;
Well, as the JBoss server Glassfish doesn´t remove the inject &lt;code&gt;SFSBSecond&lt;/code&gt; bean. And now calling &lt;code&gt;remove()&lt;/code&gt; explicitly:
&lt;pre&gt;[#|2008-10-29T01:50:28.722-0200|INFO|br.com.svvs.SFSBFirst: called(Hello World!)|#]
[#|2008-10-29T01:50:28.722-0200|INFO|br.com.svvs.SFSBSecond: called(Hello World!)|#]
[#|2008-10-29T01:50:28.725-0200|INFO|br.com.svvs.SFSBFirst: removing(Hello World!)|#]
[#|2008-10-29T01:50:28.726-0200|INFO|br.com.svvs.SFSBSecond: removing(Hello World!)|#]
[#|2008-10-29T01:50:28.726-0200|INFO|br.com.svvs.SFSBSecond: destroying(Hello World!)|#]
[#|2008-10-29T01:50:28.726-0200|INFO|br.com.svvs.SFSBFirst: destroying(Hello World!)|#]
&lt;/pre&gt;That appears to be right, the bean was removed in the right order and all variables still in memory.

&lt;span style="font-size:130%;"&gt;Conclusion&lt;/span&gt;

Explicitly remove the injected beans, the application servers JBoss and Glassfish will not do it for you. I think that´s kind odd, since they injected the Bean and a Stateful bean can have only one client it must be destroyed when the client is destroyed, but that´s the way things are.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-2290494758331694369?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/2290494758331694369/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=2290494758331694369' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/2290494758331694369'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/2290494758331694369'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2008/10/stateful-session-beans-dependence.html' title='Stateful Session Beans, Dependence Injection and @Remove annotation.'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-8663103236175959653</id><published>2008-07-19T18:04:00.000-07:00</published><updated>2008-07-19T20:24:35.056-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='distributed systems'/><category scheme='http://www.blogger.com/atom/ns#' term='nfs'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='concurrent'/><category scheme='http://www.blogger.com/atom/ns#' term='concurrency'/><title type='text'>NFS concurrency on distributed systems</title><content type='html'>Last week I had a hard time trying to figure out one way to scale one
application to many machines and many instances on each machine using one NFS
server as point of access. I believe I found one solution to this problem and
here I will explain some of what was done.

First let me explain the problem more clearly, these are the requirements:

* A arbitrary number of files will be on a exported NFS file system.  One
* consumer application have to read a file and import it
contents to a database.
* Each file should be imported only once.  After import the file should be moved
* to a archive directory.  No file can be ignored or skipped if contains valid
* data.  One or more consumers will run on one machine.  One or more machines
* will run on the network.

We can state this problem as a I/O concurrency problem but robust solutions as
Chubby or similar I cannot use because some constrains. These are the
constrains:

* I have not access to the NFS machine except by the exported
file system.
* The solution should be a simple refactoring of the current
application, not a major project nor a redesign.
* The application is written in Perl.

On a first thought I went search for file locking solutions, the idea was
simple. Each consumer will lock the file before attempt to read it, other
consumers should skip the file if it's locked.

NFS has a problem with locking as you can read "Use of NFS Considered Harmful",
to get things worse I was told that the NFS Lock Daemon will not run on the NFS server.

Digging more on file locking you will find this on Linux open() manual:

&lt;pre&gt;
O_EXCL is not supported on NFSv2 or on Linux before kernel 2.6; it is supported
on Linux 2.6 and later, with NFSv3 or later. In environments where NFS O_EXCL
support is not provided, programs that rely on it for performing locking tasks
will contain a race condition.  Portable programs that want to perform atomic
file locking using a lockfile, and need to avoid reliance on NFS support for
O_EXCL, can create a unique file on the same file system (e.g., incorporating
hostname and PID), and use link(2) to make a link to the lockfile. If link(2)
returns 0, the lock is successful. Otherwise, use stat(2) on the unique file to
check if its link count has increased to 2, in which case the lock is also
successful.
&lt;/pre&gt;

So, trying to acquire a lock exclusive on a NFS file system will fail and
despite my best efforts the solution given not worked on my tests.

After more researching I found the CPAN module File::NFSLock.  Some testing was
done and the module worked fine on concurrent processes on one machine. All
processes respected the lock and the files were read it without problems, but as
you might expected things broken on multiple machines.

Another module was tested, File::LockSimple, this module as a parameter for NFS
file system, but still fails on a multiple machines concurrency, as
File::NFSLock worked fine on one machine concurrency.

What were the problems found? Well, the most common problem was that multiple
consumers failed to move the file to our archive directory. The odd thing was
the consumers thought that had the lock, but that was not true. Somehow two or
more consumers had all confirmations of a lock achieved but the move operation
failed.

As a example I will explore File::LockSimple code when it checks if had the
correct lock:


-- snip --
&lt;pre&gt;
# Attempt to create lock
if (open(FILE, "&gt;$lockfile")) {
    local $\ = undef;
    print FILE "$stamp\n";
    close FILE;
    open(FILE, $lockfile);    # Check lock
    my $l;
    chop($l = &lt;file&gt;);
    $locked = $l eq $stamp;
    $l = &lt;file&gt;;            # Must be EOF
    $locked = 0 if defined $l;
    close FILE;
    last if $locked;        # Lock seems to be ours
}
&lt;/pre&gt;
-- snip --


The idea is:

* Write a unique stamp to our lock file.  Open the file again and read if the
* stamp is still our stamp.  If it is, we have the lock, if not, we loosed the
* race.

After some testing I've found that when multiple machines race for the lock
sometimes there's no winner, and the lock stays without parent and the file is
skipped by any other consumer, I had to go with another approach.

&lt;b&gt;The solution&lt;/b&gt;

One premise on file locking is that some other process will try to read/write to
a file when other process is using. The solution basically is put the process in
some wait state until the owner of the lock releases it. In this line of thought
we have one precious requirement, the file should be in a known place and you
cannot move it.

But this is not a problem in my requirement, I can move the file away so the
solution depends on that.

The algorithm in plain text:

"Create a list of all files in the source directory, create a unique directory
path, for each file in the list test if file still exists on the source
directory, if not skip this file and go the next file. If file exists in source
directory try to move it to your unique directory, if move fails skip this file,
if not test file the file is in our unique directory, if it is we have the lock,
if not skip this file and go to the next file."

The premise of this algorithm is:

"No file could be moved from one place to two other places at the same time."

This should hold true for any number of requests to the file system. Here is the
algorithm in pseudo code:

&lt;pre&gt;
source_dir = "some directory"

f[] = list_of_files(source_dir)

uniq_dir = create_uniq_directory()
 
for n=0 where n &lt;= size_of(f[]) do {         
    if(file_exists("source_dir/f[n]") == true) {
        if(move_file("source_dir/f[n]","uniq_dir/f[n]") == true) {
            if(file_exists("uniq_dir/f[n]") {
            # We have the lock
            }
        }
    }
}
&lt;/pre&gt;

 Let's explore the algorithm, first I create a list of all files on my source
directory, the real number can be about 20,000 files. Then a unique directory is
created, the directory is unique for any number of consumers, I use the name of
machine (hostname) + process ID.

For each file in our array we ask if file still exists, if not we skip because
some other consumer probably already got the file.

Now we try move the file away to our unique path. Pay attention that we try to
move the file, because after our first test the move can fail if some other
consumer move it first.  Seems odd, but believe in me this happens.

If the move returned true we go a test if the file is in our unique path. The
thing is, move() can return true even if failed. So we test it again to see if
is telling the truth.

Why move() return true even if failed? The catch is in NFS system, it has a
cache feature and could return true to the caller and then pass call to the
kernel of the server system. What happen is that two clients could issue a
move() request, NFS responds that OK because think that the file is still in the
source directory. But when calls the kernel it detects the absence of the file
and fail, but the client will not know what happened.  I'm not sure if this is
the real case or how NFS handle such calls, my tests point that something like I
described above occur.

The trick is in two things. First, the unique path. Since is unique (directory +
file) NFS will not have cached information about it. So when I ask "file exists
in my unique directory?" NFS has to check the path.

The second, the move operation is in fact a rename() operation and a rename
operation is a atomic. This way we guarantee that when two calls arrive to
rename one file, one of the calls have to fail. So in the same machine, in a
unknown other one call will fail:

&lt;pre&gt;
rename(file, file_new_name);
rename(file, file_other_name);
&lt;/pre&gt;

&lt;b&gt;The final implementation&lt;/b&gt;

Here is a simplified version of what was implemented:

&lt;pre&gt;
#!/usr/bin/perl

use strict;
use warnings;
use File::Copy;
use Sys::Hostname;

use constant SPOOL_DIR =&gt; "/tmp";

my @files; # get files from some object...

# Create unique spool path (concurrency algorithm)
my $file_spool_dir   =  join('/', SPOOL_DIR, hostname, $$);
if(! -d $file_spool_dir) {
    mkpath($file_spool_dir) or die(" ** Could not create spool directory ($!)");
} elsif(! -w $file_spool_dir or ! -r $file_spool_dir) {
  die(" ** Cannot write/read spool dir check permission ($!)");
}

FILE: foreach my $file_path (@files) {

  next FILE if ! -e $file_path; # File still exists?

  my $file_name = File::Spec-&gt;splitpath($file_path);      

  my $file_spool_path = join('/', $file_spool_dir, $file_name);

  # We try move our file to a unique path where nobody will race with us.
  if(move($file_path, $file_spool_path)) {

     # Check if file was moved to our uniq path;
     if(-e $file_spool_path) {
        # we have the file!
     }
  }
} # end of foreach file.
&lt;/pre&gt;


I have to make a note, using File::Copy method move() I'm in fact renaming
the file, the documentation of File::Copy states:

&lt;pre&gt;
If possible, move() will simply rename the file.
&lt;/pre&gt;

As mentioned before, the rename operation is atomic so we espect
that move() will not break our first premise.

&lt;b&gt;Final considerations&lt;/b&gt;

I tried to make the algorithm the best I could, formal proof
is hard especially in concurrent and distributed systems. But
the process worked fine on 25,000 files acessed by 20 consumers
in two machines. No error, no file was lost or skipped without
a good reason.

Despite I can't say this is a bullet proof algorithm, by the tests
it seems hold well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-8663103236175959653?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/8663103236175959653/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=8663103236175959653' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/8663103236175959653'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/8663103236175959653'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2008/07/nfs-concurrency-on-distributed-systems.html' title='NFS concurrency on distributed systems'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-3965794788821452285</id><published>2008-07-07T18:22:00.000-07:00</published><updated>2008-07-07T19:22:32.871-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='jquery'/><category scheme='http://www.blogger.com/atom/ns#' term='dynamic select'/><category scheme='http://www.blogger.com/atom/ns#' term='html'/><title type='text'>Using JQuery to create dynamic HTML select elements.</title><content type='html'>&lt;p&gt;This week I'm working a lot with &lt;a href="http://jquery.com/"&gt;JQuery&lt;/a&gt; and when searching for handling &lt;a href="http://www.w3schools.com/TAGS/tag_select.asp"&gt;html select element&lt;/a&gt; I found little information about it, so I decide blog a little about this subject. &lt;/p&gt;
&lt;p&gt;Typically you want add and remove &lt;strong&gt;options&lt;/strong&gt; from a select box, so I setup a little page that does an append to
a select and removes an option too.&lt;/p&gt;
&lt;p&gt;We will have a Fruit Basket, we put a item in our hand and then eat it. Here's the basket (listing 1):&lt;/p&gt;


&lt;font color="#804040"&gt;&amp;nbsp;1 &lt;/font&gt;&lt;font color="#008080"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;html&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;&amp;nbsp;2 &lt;/font&gt;&amp;nbsp;&amp;nbsp;&lt;font color="#008080"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;head&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;&amp;nbsp;3 &lt;/font&gt;&lt;font color="#a020f0"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;script&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#2e8b57"&gt;&lt;b&gt;type&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;=&lt;/font&gt;&lt;font color="#f10883"&gt;&amp;quot;text/javascript&amp;quot;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#2e8b57"&gt;&lt;b&gt;src&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;=&lt;/font&gt;&lt;font color="#f10883"&gt;&amp;quot;jquery.js&amp;quot;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;script&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;&amp;nbsp;4 &lt;/font&gt;&lt;font color="#a020f0"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;head&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;&amp;nbsp;5 &lt;/font&gt;&amp;nbsp;&amp;nbsp;&lt;font color="#008080"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;body&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;&amp;nbsp;6 &lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#008080"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;table&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;&amp;nbsp;7 &lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#008080"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;tr&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;&amp;nbsp;8 &lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#008080"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;td&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;&amp;nbsp;9 &lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Fruit Basket&lt;font color="#008080"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;br&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;10 &lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#008080"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#2e8b57"&gt;&lt;b&gt;name&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;=&lt;/font&gt;&lt;font color="#f10883"&gt;&amp;quot;basket&amp;quot;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#2e8b57"&gt;&lt;b&gt;size&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;=&lt;/font&gt;&lt;font color="#f10883"&gt;5&lt;/font&gt;&lt;font color="#008080"&gt;&amp;nbsp;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;11 &lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#008080"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;option&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#2e8b57"&gt;&lt;b&gt;value&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;=&lt;/font&gt;&lt;font color="#f10883"&gt;&amp;quot;apple&amp;quot;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;Apple&lt;font color="#008080"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;option&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;12 &lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#008080"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;option&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#2e8b57"&gt;&lt;b&gt;value&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;=&lt;/font&gt;&lt;font color="#f10883"&gt;&amp;quot;banana&amp;quot;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;Banana&lt;font color="#008080"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;option&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;13 &lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#008080"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;option&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#2e8b57"&gt;&lt;b&gt;value&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;=&lt;/font&gt;&lt;font color="#f10883"&gt;&amp;quot;orange&amp;quot;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;Orange&lt;font color="#008080"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;option&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;14 &lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#008080"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;option&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#2e8b57"&gt;&lt;b&gt;value&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;=&lt;/font&gt;&lt;font color="#f10883"&gt;&amp;quot;grape&amp;quot;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;Grape&lt;font color="#008080"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;option&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;15 &lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#008080"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;option&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#2e8b57"&gt;&lt;b&gt;value&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;=&lt;/font&gt;&lt;font color="#f10883"&gt;&amp;quot;starfruit&amp;quot;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;Star Fruit&lt;font color="#008080"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;option&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;16 &lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#008080"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;br&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;17 &lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#008080"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;input&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#2e8b57"&gt;&lt;b&gt;type&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;=&lt;/font&gt;&lt;font color="#f10883"&gt;&amp;quot;button&amp;quot;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#2e8b57"&gt;&lt;b&gt;value&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;=&lt;/font&gt;&lt;font color="#f10883"&gt;&amp;quot;Pickup&amp;quot;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#2e8b57"&gt;&lt;b&gt;name&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;=&lt;/font&gt;&lt;font color="#f10883"&gt;&amp;quot;pickup&amp;quot;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;18 &lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#008080"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;td&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;19 &lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#008080"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;td&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;20 &lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Hand&lt;font color="#008080"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;br&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;21 &lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#008080"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#2e8b57"&gt;&lt;b&gt;name&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;=&lt;/font&gt;&lt;font color="#f10883"&gt;&amp;quot;hand&amp;quot;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#2e8b57"&gt;&lt;b&gt;size&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;=&lt;/font&gt;&lt;font color="#f10883"&gt;5&lt;/font&gt;&lt;font color="#008080"&gt;&amp;nbsp;&amp;gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;select&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;br&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;22 &lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#008080"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;input&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#2e8b57"&gt;&lt;b&gt;type&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;=&lt;/font&gt;&lt;font color="#f10883"&gt;&amp;quot;button&amp;quot;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#2e8b57"&gt;&lt;b&gt;value&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;=&lt;/font&gt;&lt;font color="#f10883"&gt;&amp;quot;Eat!&amp;quot;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#2e8b57"&gt;&lt;b&gt;name&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;=&lt;/font&gt;&lt;font color="#f10883"&gt;&amp;quot;eat&amp;quot;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;23 &lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#008080"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;td&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;24 &lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;font color="#008080"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;tr&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;25 &lt;/font&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;font color="#008080"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;table&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;26 &lt;/font&gt;&amp;nbsp;&amp;nbsp;&lt;font color="#008080"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;body&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;27 &lt;/font&gt;&lt;font color="#008080"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;html&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;

&lt;p&gt;This HTML is a simple one, the table was inserted just to put the selects side-by-side. Note that I didn't put any javascript event handler like &lt;strong&gt;onClick()&lt;/strong&gt;, &lt;strong&gt;onChange()&lt;/strong&gt; and etc. This because with JQuery you can add the event handler very easily without cluttering the HTML.&lt;/p&gt;
&lt;p&gt;Now comes the good stuff, insert a &lt;code&gt;&amp;lt;script type="text/javascript"&amp;gt;&lt;/code&gt; tag and let's see JQuery's magic (listing 2).&lt;/p&gt;


&lt;font color="#804040"&gt;&amp;nbsp;1 &lt;/font&gt;&lt;font color="#008080"&gt;&amp;lt;&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;script&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#2e8b57"&gt;&lt;b&gt;type&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;=&lt;/font&gt;&lt;font color="#f10883"&gt;&amp;quot;text/javascript&amp;quot;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;&amp;nbsp;2 &lt;/font&gt;&lt;font color="#6a59cc"&gt;$&lt;/font&gt;(&lt;font color="#804040"&gt;&lt;b&gt;document&lt;/b&gt;&lt;/font&gt;)&lt;font color="#6a59cc"&gt;.ready&lt;/font&gt;(&lt;font color="#008080"&gt;function&lt;/font&gt;()&lt;font color="#6a59cc"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#008080"&gt;{&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;&amp;nbsp;3 &lt;/font&gt;&lt;font color="#6a59cc"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#0000d4"&gt;// the good stuff goes in here...&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;&amp;nbsp;4 &lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;&amp;nbsp;5 &lt;/font&gt;&lt;font color="#6a59cc"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#0000d4"&gt;// when somebody clicks on Pickup...&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;&amp;nbsp;6 &lt;/font&gt;&lt;font color="#6a59cc"&gt;&amp;nbsp;&amp;nbsp;$&lt;/font&gt;(&lt;font color="#f10883"&gt;&amp;quot;input[name='pickup']&amp;quot;&lt;/font&gt;)&lt;font color="#6a59cc"&gt;.click&lt;/font&gt;(&lt;font color="#008080"&gt;function&lt;/font&gt;()&lt;font color="#6a59cc"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#008080"&gt;{&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;&amp;nbsp;7 &lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;&amp;nbsp;8 &lt;/font&gt;&lt;font color="#6a59cc"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#0000d4"&gt;// there's something selected in our basket?&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;&amp;nbsp;9 &lt;/font&gt;&lt;font color="#6a59cc"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/font&gt;(&lt;font color="#6a59cc"&gt;$&lt;/font&gt;(&lt;font color="#f10883"&gt;&amp;quot;select[name='basket'] :selected&amp;quot;&lt;/font&gt;)&lt;font color="#6a59cc"&gt;.length &amp;gt; &lt;/font&gt;0)&lt;font color="#6a59cc"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#008080"&gt;{&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;10 &lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;11 &lt;/font&gt;&lt;font color="#6a59cc"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fruit_text&amp;nbsp;&amp;nbsp; = $&lt;/font&gt;(&lt;font color="#f10883"&gt;&amp;quot;select[name='basket'] :selected&amp;quot;&lt;/font&gt;)&lt;font color="#6a59cc"&gt;.text&lt;/font&gt;()&lt;font color="#6a59cc"&gt;;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;12 &lt;/font&gt;&lt;font color="#6a59cc"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;fruit_value&amp;nbsp;&amp;nbsp;= $&lt;/font&gt;(&lt;font color="#f10883"&gt;&amp;quot;select[name='basket'] :selected&amp;quot;&lt;/font&gt;)&lt;font color="#6a59cc"&gt;.attr&lt;/font&gt;(&lt;font color="#f10883"&gt;&amp;quot;value&amp;quot;&lt;/font&gt;)&lt;font color="#6a59cc"&gt;;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;13 &lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;14 &lt;/font&gt;&lt;font color="#6a59cc"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#0000d4"&gt;// put the fruit in hand...&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;15 &lt;/font&gt;&lt;font color="#6a59cc"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$&lt;/font&gt;(&lt;font color="#f10883"&gt;&amp;quot;select[name='hand']&amp;quot;&lt;/font&gt;)&lt;font color="#6a59cc"&gt;.append&lt;/font&gt;(&lt;font color="#804040"&gt;&lt;b&gt;new&lt;/b&gt;&lt;/font&gt;&lt;font color="#6a59cc"&gt;&amp;nbsp;Option&lt;/font&gt;(&lt;font color="#6a59cc"&gt;fruit_text, fruit_value&lt;/font&gt;))&lt;font color="#6a59cc"&gt;;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;16 &lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;17 &lt;/font&gt;&lt;font color="#6a59cc"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#0000d4"&gt;// remove the fruit from the basket...&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;18 &lt;/font&gt;&lt;font color="#6a59cc"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$&lt;/font&gt;(&lt;font color="#f10883"&gt;&amp;quot;select[name='basket'] :selected&amp;quot;&lt;/font&gt;)&lt;font color="#6a59cc"&gt;.remove&lt;/font&gt;()&lt;font color="#6a59cc"&gt;;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;19 &lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;20 &lt;/font&gt;&lt;font color="#6a59cc"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#008080"&gt;}&lt;/font&gt;&lt;font color="#6a59cc"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;else&lt;/b&gt;&lt;/font&gt;&lt;font color="#6a59cc"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#008080"&gt;{&lt;/font&gt;&lt;font color="#6a59cc"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/font&gt;&lt;font color="#6a59cc"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#f10883"&gt;false&lt;/font&gt;&lt;font color="#6a59cc"&gt;; &lt;/font&gt;&lt;font color="#008080"&gt;}&lt;/font&gt;&lt;font color="#6a59cc"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#0000d4"&gt;// don't bother with a empty selection&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;21 &lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;22 &lt;/font&gt;&lt;font color="#6a59cc"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#008080"&gt;}&lt;/font&gt;)&lt;font color="#6a59cc"&gt;;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;23 &lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;24 &lt;/font&gt;&lt;font color="#6a59cc"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#0000d4"&gt;// let's eat!&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;25 &lt;/font&gt;&lt;font color="#6a59cc"&gt;&amp;nbsp;&amp;nbsp;$&lt;/font&gt;(&lt;font color="#f10883"&gt;&amp;quot;input[name='eat']&amp;quot;&lt;/font&gt;)&lt;font color="#6a59cc"&gt;.click&lt;/font&gt;(&lt;font color="#008080"&gt;function&lt;/font&gt;()&lt;font color="#6a59cc"&gt;&amp;nbsp;&lt;/font&gt;&lt;font color="#008080"&gt;{&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;26 &lt;/font&gt;&lt;font color="#6a59cc"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;$&lt;/font&gt;(&lt;font color="#f10883"&gt;&amp;quot;select[name='hand'] :selected&amp;quot;&lt;/font&gt;)&lt;font color="#6a59cc"&gt;.remove&lt;/font&gt;()&lt;font color="#6a59cc"&gt;;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;27 &lt;/font&gt;&lt;font color="#6a59cc"&gt;&amp;nbsp;&amp;nbsp;&lt;/font&gt;&lt;font color="#008080"&gt;}&lt;/font&gt;)&lt;font color="#6a59cc"&gt;;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;28 &lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;29 &lt;/font&gt;&lt;font color="#008080"&gt;}&lt;/font&gt;)&lt;font color="#6a59cc"&gt;;&lt;/font&gt;&lt;br&gt;
&lt;font color="#804040"&gt;30 &lt;/font&gt;&lt;font color="#008080"&gt;&amp;lt;/&lt;/font&gt;&lt;font color="#804040"&gt;&lt;b&gt;script&lt;/b&gt;&lt;/font&gt;&lt;font color="#008080"&gt;&amp;gt;&lt;/font&gt;&lt;br&gt;



&lt;p&gt;Now let's explain what is happening.&lt;/p&gt;
&lt;p&gt;If you already knows JQuery you recognize the line 2, this is a simple way to trigger your script when the
document is ready, it's a good practice. Insures that your script will not fire before the browser finished
rendering all page elements.&lt;/p&gt;
&lt;p&gt;In line 6 and 25 we define one anonymous (formally a lambda) function that will be fired on a click event for our both buttons. Pay attention on JQuery &lt;a href="http://docs.jquery.com/Selectors"&gt;selector syntax&lt;/a&gt; it's very important! In line 6 we say to JQuery:&lt;/p&gt;
&lt;p&gt;&lt;code&gt; $("input[name='pickup']")&lt;/code&gt; &lt;/p&gt;
&lt;p&gt;and JQuery understand this:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;"Give me the input element which has the attribute name equals to pickup."&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;If we were ambiguous in our selector JQuery will return more than one element, in this case we could iterate over the matches found with &lt;a href="http://docs.jquery.com/Core/each#callback"&gt;each()&lt;/a&gt; helper.&lt;/p&gt;
&lt;p&gt;We ask to JQuery in line 9 if there's something selected in our basket, if the &lt;strong&gt;length of selected fruits&lt;/strong&gt; is greater than zero let's do something.&lt;/p&gt;
&lt;p&gt;We use some accessors from JQuery and save the text and the value of attribute "value" in two variables, lines 11 and 12. After that, in line 15, we tell JQuery to append a new &lt;a href="http://www.w3schools.com/htmldom/dom_obj_option.asp"&gt;Option object&lt;/a&gt; which is basically the same option selected in our basket.&lt;/p&gt;
&lt;p&gt;Now the last step in this event is remove the fruit from the basket, one way to do this is calling &lt;strong&gt;remove()&lt;/strong&gt; on the JQuery object.&lt;/p&gt;
&lt;p&gt;If you payed attention on the above explanation lines 25 to 27 should be clear. We select what is selected on our hand and just "eat it" (in fact we remove the element). That's it, simple and clean.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-3965794788821452285?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/3965794788821452285/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=3965794788821452285' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/3965794788821452285'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/3965794788821452285'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2008/07/using-jquery-to-create-dynamic-html.html' title='Using JQuery to create dynamic HTML select elements.'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-408301813210041598</id><published>2008-07-06T14:06:00.000-07:00</published><updated>2008-07-06T14:08:54.504-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='active directory'/><category scheme='http://www.blogger.com/atom/ns#' term='windows migration'/><category scheme='http://www.blogger.com/atom/ns#' term='user profile'/><category scheme='http://www.blogger.com/atom/ns#' term='domain change'/><category scheme='http://www.blogger.com/atom/ns#' term='microsoft'/><title type='text'>Easy (lost all your data) Profile Transfer Tool for Windows</title><content type='html'>&lt;p&gt;Recently in my company we had to change domains in Active Directory so all users couldlog into the corporate domain. Well, I previously had a experience like that and I've lost all my configurationdata. But we now used the "Easy User Data Migration" (I really don't remember the correct name) tool fromMicrosoft.&lt;/p&gt;&lt;p&gt;Guess what? I loosed all data again! But I managed to get it back with a simple action, but I was lucky inside the company, others had to search file by file.&lt;/p&gt;&lt;p&gt;First how Microsoft store users data? In a shallow view you can look at your directory:&lt;/p&gt; &lt;pre&gt; C:\Documents and Settings\username.DOMAINNAME&lt;/pre&gt;&lt;p&gt;So, knowing that the transfer would not work I used the backup tool and stored all in my USB drive. After thatI was recommended by the administrators to use the &lt;strong&gt;Easy Transfer Tool&lt;/strong&gt;. Ok, I did it, and for my surprise the tool gathered information about my &lt;code&gt;C:\perl&lt;/code&gt;, &lt;code&gt;C:\ruby&lt;/code&gt; and others directories that I think there's nothing with my profile.&lt;/p&gt;&lt;p&gt;When the tool finished it stored about 760Mb of information in my transfer directory. I thought "It's ok, this is about the size of my &lt;code&gt;C:\Documents and Settings\username.DOAMINNAME&lt;/code&gt; dir, so it's alright". Oh sooo naive!&lt;/p&gt;&lt;p&gt;The domain of the computer was changed and I used to tool to recover all my data, let's talk about my data.&lt;/p&gt;&lt;p&gt;First, my data is a bunch of profile variables that I have to define for Java, Oracle and other personal applications. Is my Firefox profile, my Thunderbird profile, my Twirl profile, Adobe air, Launchy shortcuts, SVN and unix tools for windows. The problem with these data is that I'm constantly defining new variables, shortcuts and getting extensions because any programmer don't like to type the same thing twice when it can be done by a script.&lt;/p&gt;&lt;p&gt;My Desktop is, as for many programmers, full of little tweaks so works better and fast. I had "Process Explorer" launched by default (any programmer in a Windows box should do this) and minimized, well a lot of little stuff.&lt;/p&gt;&lt;p&gt;So I was not willing to tweak the system all again. So I logged in the new domain and launched the tool, waited, waited and message was &lt;strong&gt;Your data was recovered, some you should do manually&lt;/strong&gt;, Uh Oh!&lt;/p&gt;&lt;p&gt;When the desktop came alive the first thing I checked was the profile variables&amp;#8230; and &amp;#8230;. none! My Firefox forgot about me, and the others applications too. So, what the hell was transfered?! I think just the Domain Stuff, just things I assume no one  should worry, even know about it. But about the stuff that was important to me? Even the Desktop Wallpaper was not transfered!&lt;/p&gt;&lt;p&gt;Well, are you asking, how did you recovered your settings? Just renaming the directory:&lt;/p&gt;&lt;p&gt;From:&lt;/p&gt;&lt;pre&gt;C:\Documents and Setting\username.DOMAINNAME&lt;/pre&gt;&lt;p&gt; to:&lt;/p&gt;&lt;pre&gt;C:\Documents and Settings\username.NEWDOMAINNAME&lt;/pre&gt;&lt;p&gt;Bit there's a catch, I'm the Administrator of my machine so I can do that, and the second step was change theowner of all files to my username at my new domain, and only administrators can do that.&lt;/p&gt;&lt;p&gt;What bugs my a lot is why the tool archived all files but fail to put them back in place? We are not using a hack like a samba server or a ldap server mocking a windows server, we did it by the book, but still Windows failed to provide a good experience and took about three days to some users to put the Desktop in order, as I said, I was lucky.&lt;/p&gt;&lt;p&gt;That's it. If you think that a simple change in domain is a simple thing, think again, back up your data and be ready to loose your settings.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-408301813210041598?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/408301813210041598/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=408301813210041598' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/408301813210041598'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/408301813210041598'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2008/07/easy-lost-all-your-data-profile.html' title='Easy (lost all your data) Profile Transfer Tool for Windows'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-3172047229434516580</id><published>2008-07-03T21:52:00.000-07:00</published><updated>2008-07-03T22:11:53.284-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software testing'/><category scheme='http://www.blogger.com/atom/ns#' term='selenium'/><title type='text'>Is Selenium testing good or bad?</title><content type='html'>I've just read &lt;a href="http://blog.jayfields.com/2008/07/immaturity-of-in-browser-testing.html"&gt;this post&lt;/a&gt; of Jay Fields about &lt;a href="http://www.openqa.org"&gt;Selenium&lt;/a&gt;. I have some different points about Selenium testing and its use, I'm owning a post about Selenium so the time came.

First of all, I 'm not a experienced Selenium tester, I've heard about it and waited until have some time to put the tests on a legacy application that I support. Let's put on context, Selenium for me was hard to learn. Jay says that is a easy to learn but wasn't for me. Couple of reasons:

The Selenium IDE is easy but limited, so I went for the big fish SeleniumRC.

My legacy application is very bad implemented. About all pages has invalid HTML syntax and JavaScript errors, and the application has a lot of pages and interactions.

As Jay points out, Selenium has a lot of languages you can write tests and we can get a little confused about what language to choose to write them. This can be a problem but I don't think so, if you think a little why you should choose a language in favor of another. You have just to make the decision of what language suites you better, can be the language you are most familiar or, as I decided, the language of the implementation of your application. I've chosen the second one because my team writes in Java, my app was written in Java and i think is a good thing to keep your tests with your application in the repository. Java has other benefits, typing, with Perl I had to check all return types and look at the API all the time. But with some practice you get how Selenium works and you get to write tests more rapidly.

I really don't know about other experiences with Selenium as Jay mention, if developers had to throw their tests away after certain size, this still is not a problem for me, maybe in the future Selenium bites me, still...

Jay argues that Selenium tests are slow and browsers are buggy, it is absolute true. A simple suite will run in 10 minutes or so, and that's slow. But I don't think this is a Selenium problem, in fact Selenium is fast where it can, surely more  fast than written down scripts for users to test the application. Browsers. Oh! browsers... we developers still fell a major pain when someone shouts "It doesn't work for me!" The browser war made a lot of collateral damage, but still it's not Selenium fault. In fact Selenium came to help us with these damages. Being capable of programatically test my application on a Firefox and IE is a bless.

When a test fail little information is provided, as Jay puts, and it's true. I agree that if more information was provided will be a big gain, but this is not, as far as i know, Selenium's fault. We have to remember that we are testing the final product, the one which is stripped of "business logic" (i know that the behavior is business logic but I'm talking about of the business logic we hid in our classes), in this case we're experiencing the user environment and it's a harsh one. I develop for the web for about nine years and some problems in the user environment are really bizarre.

In my opinion Selenium is a excellent initiative and has much value, of course that is not the only testing you should  do. When using Selenium you are able to catch some very complex interactions that a simple unit testing will not, by the fact that "in pieces" the application behaves right but when the user go from one state to another and back again some missing parameter, a misplaced element on a page and etc, can bite you.

For who wrote such tests using LWP library in Perl and looking for elements using DOM parsers I think Selenium is great. Can be better? Of course! I had a difficult time in find complete examples and I think that the docs still need improvement but I've found my way through these and the faulty, sloppy made application can be tested and refactored  without noticing a break after weeks of development, and that's good for me. I can work more confident on this application then before, this is a good sign.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-3172047229434516580?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/3172047229434516580/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=3172047229434516580' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/3172047229434516580'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/3172047229434516580'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2008/07/is-selenium-testing-good-or-bad.html' title='Is Selenium testing good or bad?'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-4592679312598400609</id><published>2008-07-01T19:54:00.000-07:00</published><updated>2008-07-01T21:10:30.309-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='ignorance'/><category scheme='http://www.blogger.com/atom/ns#' term='patterns'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='software methodology'/><title type='text'>It's been a long time from my last post...</title><content type='html'>&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;... so let's talk: Are you smart?&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;In fact, I just read &lt;/span&gt;&lt;/span&gt;&lt;a href="http://steve-yegge.blogspot.com/2008/06/done-and-gets-things-smart.html"&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;this post&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; (lengthy post) by Steve Yegge and the funny thing was that I were just thinking about &lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;how &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-style: italic;"&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;not smart I am.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; (Note: Blogger shortcuts Ctrl+I,B,... not work on Safari on a Mac?). Watching his talk at &lt;/span&gt;&lt;/span&gt;&lt;a href="http://www.youtube.com/watch?v=BttI-y9VzXQ&amp;amp;feature=iv"&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Google I/O 2008&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; got me thinking "Uau, I'm really a low level developer", then I went to his &lt;/span&gt;&lt;/span&gt;&lt;a href="http://steve-yegge.blogspot.com/"&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;blog&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; and saw the article "&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 51);  font-weight: bold; line-height: 20px; "&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;Done, and Gets Things Smart". &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="color: rgb(51, 51, 51);  font-weight: bold; line-height: 20px;"&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 20px;"&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;In fact this is not a really bad felling, you know, if you get too confident you make mistakes, thats the way things are. It's the same when you judge your skills at some field, as a developer who always searches about the trends in my field I face the overwhelming amount of information that I don't have every day. Languages, frameworks, things that were good &lt;/span&gt;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Singleton_pattern"&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;patterns&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; and now are listed at &lt;/span&gt;&lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Anti-pattern"&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;anti-patterns,&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; new development tools, new debug techniques, new testing frameworks and so on.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 20px;"&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 20px;"&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;- I should make a parenthesis here about patterns. &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 20px;"&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 20px;"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;The overuse of about anything creates a bad thing&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;, like your plate at lunch. Nutritionists says the &lt;/span&gt;&lt;/span&gt;&lt;a href="http://www.ars.usda.gov/News/docs.htm?docid=10682"&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;tonal variance of your plate is a good sign.&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt; If fill up your code with patterns this is NOT a good sign. Patterns have a defined problem they try to solve, if you fill your code with patterns, after patterns, after patterns, in a simple view, you have problems, and problems, and problems at your code. A good way to approach a pattern use is: "Oh! How I gonna solve this problem? Maybe someone thought about it and came with a solution." And not "Oh! What patterns I should use to build my application?".&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 20px;"&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 20px;"&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;- Back to the main subject.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 20px;"&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 20px;"&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;After read hundreds of blog posts every day, articles, watch talks and so on, you should not (as I try too) get depressed. There two main reasons I can think of, the first is that your field is growing fast, this means jobs, money and space for everyone how likes technology. The second reason is that you are trying to keep with the wave, you are searching for improvement and surely you'll be a better professional tomorrow than you are today. Of course a filter should be applied in the enormous amount of info, but we learn how to choose the right information with time.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 20px;"&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 20px;"&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;The message is: Be smart in not being smart, do the things you know, what you don't know go outside and learn it. As the greek philosopher Socrates said "&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: rgb(69, 69, 69);   line-height: 19px; -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; "&gt;&lt;a href="http://www.quotationspage.com/quote/24175.html"&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;I know nothing except the fact of my ignorance&lt;/span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;" and the oracle of Delphi stated that he was the wisest man.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 20px;"&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="line-height: 20px;"&gt;&lt;span class="Apple-style-span" style="font-family: verdana;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;[]'s and keepcoding.&lt;/span&gt;&lt;/span&gt;&lt;/span&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/1598881393381863026-4592679312598400609?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/4592679312598400609/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=4592679312598400609' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/4592679312598400609'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/4592679312598400609'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2008/07/its-been-long-time-from-my-last-post.html' title='It&apos;s been a long time from my last post...'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-8797078048054205456</id><published>2008-03-06T17:44:00.000-08:00</published><updated>2008-03-06T18:15:02.342-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='i.t.'/><category scheme='http://www.blogger.com/atom/ns#' term='interview'/><title type='text'>One question worth asking in a interview.</title><content type='html'>There's a &lt;a href="http://www.joelonsoftware.com/articles/fog0000000073.html"&gt;lot&lt;/a&gt; &lt;a href="http://www.codinghorror.com/blog/archives/001042.html"&gt;references&lt;/a&gt; &lt;a href="http://blog.fragmental.com.br/2007/10/22/sobre-entrevistas/"&gt;how&lt;/a&gt; to do a I.T. &lt;a href="http://thedailywtf.com/Series/Tales_from_the_Interview.aspx"&gt;interviews&lt;/a&gt;, so of course will spend you of more about this topic except by one little thing, a little question that is, for me, a good one to fell how comfortable is the candidate with the technology of the job. &lt;div&gt;
&lt;/div&gt;&lt;div&gt;Say Java, ask something like: "What feature of Java annoy you?" or "What feature of Java that you don't like much and could be improved?". &lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;The point here is very simple, is easy to say the advantages but requires a lot more know how to no the problems.  The answer don't have to be perfect, sometimes we think that one thing is annoying without knowing that is the best. To change opinions is part of growth it's natural, but have a opinion is more important. &lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Answer this question is harder for someone that never thought how improve their processes, or took a technology as a final solution, or another things that annoys me as well.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-8797078048054205456?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/8797078048054205456/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=8797078048054205456' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/8797078048054205456'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/8797078048054205456'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2008/03/one-question-worth-asking-in-interview.html' title='One question worth asking in a interview.'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-7095670078603875082</id><published>2008-02-15T18:51:00.000-08:00</published><updated>2008-02-15T19:30:04.454-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='xp'/><category scheme='http://www.blogger.com/atom/ns#' term='cmmi'/><category scheme='http://www.blogger.com/atom/ns#' term='software methodology'/><category scheme='http://www.blogger.com/atom/ns#' term='itil'/><category scheme='http://www.blogger.com/atom/ns#' term='scrum'/><title type='text'>I.T. methodologies and religious paths.</title><content type='html'>&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Is not a big news to know that I.T. companies have problems with methodologies. They want them but for some reason they fail implement them, of course this don't prevent a big logo with &lt;a href="http://www.sei.cmu.edu/cmmi/"&gt;CMMi&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Information_Technology_Infrastructure_Library"&gt;ITIL&lt;/a&gt;, &lt;a href="http://www-306.ibm.com/software/awdtools/rup/"&gt;RUP&lt;/a&gt;, &lt;a href="http://www.extremeprogramming.org/"&gt;XP&lt;/a&gt;, &lt;a href="http://www.controlchaos.com/"&gt;Scrum&lt;/a&gt;, &lt;a href="http://iconixprocess.com/"&gt;ICONIX&lt;/a&gt; and etc to popup in your face. Jut hire some experts to give some presentations, put some docs and fancy names for these and you are ready.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;The impression I got is that competition and "everybody says is great" is the most compelling reason for this kind of behavior. A company should improve always so get some methodology is a improvement, get two is more improvement, mix the best of the two is better! Well, not. &lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;One big company said to me that they have a "kind of CMMi" they extracted some steps and used only what was the best about CMMi. What is the problem with get the best of? The problem is that there's no such thing as the best part of a methodology, you can't decide this, you shouldn't decide this.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Take religion, have you heard some people saying that they are Spiritualist, Catholic, Buddhist, Muslin and so on? That they think that some concepts of one religion are great but others not. Ok, everybody should analyze, think about, take conclusions but they have to remember that not all aspects are in our comfortable zone. If you want to call your self a Buddhist you should remember that implies not to drink beer. And this is not a silly rule that some monks thought about, there's a reason for it and sometimes you can't see the point.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;What I trying to say is that, companies are very naive thinking that they can point out what to adopt or not. The CMMi, as a example, is well thought and every aspect is there for some reason. When you try to decide what is the best for you is it certain that your comfort zone will drag you to rules and procedures that favors your zone, that's the big and real problem. &lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Do not try to mix to make it best just stick with one, if is not working try another, and another, but the mix don't improve your results, in fact can lead you to a false perception that methodologies do not work. I know that there's no perfect solution and after you have a methodology then you can tweak it around to fit your necessities.&lt;/div&gt;&lt;div&gt;
&lt;/div&gt;&lt;div&gt;Keep in mind that: "Simplicity is the shortest path between two points" - Bruce Lee.&lt;/div&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/1598881393381863026-7095670078603875082?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/7095670078603875082/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=7095670078603875082' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/7095670078603875082'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/7095670078603875082'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2008/02/it-methodologies-and-religious-paths.html' title='I.T. methodologies and religious paths.'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-3692712446375165561</id><published>2008-01-14T20:26:00.000-08:00</published><updated>2008-02-15T19:35:24.458-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='inteface design'/><category scheme='http://www.blogger.com/atom/ns#' term='uml'/><category scheme='http://www.blogger.com/atom/ns#' term='software development'/><category scheme='http://www.blogger.com/atom/ns#' term='extreme programming'/><category scheme='http://www.blogger.com/atom/ns#' term='paradox of choice'/><category scheme='http://www.blogger.com/atom/ns#' term='design'/><category scheme='http://www.blogger.com/atom/ns#' term='model'/><category scheme='http://www.blogger.com/atom/ns#' term='agile methods'/><category scheme='http://www.blogger.com/atom/ns#' term='analysis paralisys'/><category scheme='http://www.blogger.com/atom/ns#' term='xp'/><category scheme='http://www.blogger.com/atom/ns#' term='function point analysis'/><category scheme='http://www.blogger.com/atom/ns#' term='kiss principle'/><category scheme='http://www.blogger.com/atom/ns#' term='scrum'/><title type='text'>7 Things a developer should know to survive big companies</title><content type='html'>Not every company will embrace new technologies or methodologies, but you probably will be in charge to achieve a similar performance as companies that adopt new technologies and methodologies such as &lt;a href="http://en.wikipedia.org/wiki/Scrum_%28development%29"&gt;Scrum&lt;/a&gt; and &lt;a href="http://www.rubyonrails.org/"&gt;Rails&lt;/a&gt;. So, what you should know to get things done in a agile way but without a formal &lt;a href="http://agilemanifesto.org/"&gt;agile method&lt;/a&gt; inside your company? Here's some things that can save your time and health.

&lt;span style="font-size:130%;"&gt; Know what is: &lt;a href="http://video.google.com/videoplay?docid=6127548813950043200"&gt;Paradox of Choice&lt;/a&gt;&lt;/span&gt;

Users are not evil or dumb, they are humans. And humans who knows the problem you want to solve, even if they are evil or dumb, that's a fact. If you have to deal with users try to not block your mind to their presence, they have the key of your success. If you block them, then you have a good chance to deliver something that would not solve their problem. Software is all about users, right?

When talking to users always, I mean always, be aware of the Paradox of Choice. In companies that use the old &lt;a href="http://en.wikipedia.org/wiki/Waterfall_model"&gt;"Get all requirements -&gt; Some stuff -&gt; Put in production"&lt;/a&gt; flux, you probably will ask if the user want this or that, and as influenced by the Paradox of Choice he or she will want all you offer and more. You know were this ends, in a big multi-function software that forgets to solve the main problem in a good way.

&lt;span style="font-size:130%;"&gt;
Know this: &lt;a href="http://lesscode.org/2005/10/19/code-is-model/"&gt;If you can't model you can't build it&lt;/a&gt;.
&lt;/span&gt;
This quote is from &lt;a href="http://en.wikipedia.org/wiki/John_Walker_%28programmer%29"&gt;John Walker&lt;/a&gt;, and you should be aware of that. You should know ways to model your problem in a more formal way, maybe using &lt;a href="http://www.uml.org/"&gt;UML&lt;/a&gt;. The main thing here is to abstract a little before code anything, some simple diagrams can save your life, you can avoid wrong architectural choices if you draw your idea in a paper before start coding or writing a specification.

You don't have to master UML or &lt;a href="http://www.foruse.com/articles/abstractprototypes.htm"&gt;Canonical Abstract Prototyping&lt;/a&gt; , but you have to know the enough to represent your mind outside it. This helps to organize your thought and maybe  &lt;a href="http://en.wikipedia.org/wiki/Linguistic_determinism"&gt;linguistic determinism&lt;/a&gt; plays a hole in here. The constrains of a UML could save you from some traps, as the diagram gets confuse and clouded maybe you have to think a little more about the problem.

&lt;span style="font-size:130%;"&gt; Know this trap: &lt;a href="http://en.wikipedia.org/wiki/Analysis_paralysis"&gt;Analysis Paralysis&lt;/a&gt;&lt;/span&gt;

When you have too much worries in modeling you can be bitten by the "Analysis Paralysis" &lt;a href="http://c2.com/cgi/wiki?AntiPatternsCatalog"&gt;anti-pattern&lt;/a&gt;. As I said before you should model, modeling is good, modeling too much not. Some insecurity about the project can make you afraid to deliver your specifications until they are perfect. But what you have to keep in mind is that there's no such thing as a perfect specification. In fact I think that "specification" is not a good name because it's more like technical guidelines than a complete solution.

"&lt;a href="http://www.agilemodeling.com/principles.htm#SoftwareIsYourPrimaryGoal" name="SoftwareIsYourPrimaryGoal"&gt;Working Software Is Your Primary Goal&lt;/a&gt;", &lt;a href="http://www.ambysoft.com/scottAmbler.html"&gt;Scott W. Ambler&lt;/a&gt; wrote in "&lt;a href="http://www.ambysoft.com/books/agileModeling.html"&gt;Agile Modeling&lt;/a&gt;". That's it. If you try to model, or specify a perfect document you got it wrong, your final product is not a model. Note that a abstraction cannot be in same details of what is abstracted, if so, there's no abstraction at all. Experience will teach what is a &lt;a href="http://www.agilemodeling.com/essays/barelyGoodEnough.html"&gt;good enough model&lt;/a&gt;.

&lt;span style="font-size:130%;"&gt;Know what is: &lt;a href="http://en.wikipedia.org/wiki/KISS_principle"&gt;The KISS principle&lt;/a&gt;

&lt;/span&gt;Keep It Simple, Stupid. Some problems are complex, but shouldn't make them more complex. When trying to solve a problem try to be simple about it. In software you can design a solution that will take hundreds of lines of code, a bunch of classes and maybe solve the problem, that can be a problem. Software has this "soft" nature and people think if the goal is achieved then the solution is right, not quite.

I remember in my &lt;a href="http://en.wikipedia.org/wiki/Linear_algebra"&gt;Linear Algebra&lt;/a&gt; course in college when we got the right answers by the wrong methods the professor marked the question as wrong. "You answered right but you solved it wrong." that's harsh, but true. &lt;span style="font-weight: bold;"&gt;When you try to solve a problem think carefully how you are solving it, &lt;a href="http://www.nizkor.org/features/fallacies/"&gt;getting the right answer is not a indication that you solved it right&lt;/a&gt;. (&lt;a href="http://en.wikipedia.org/wiki/Design_by_contract"&gt;see this too&lt;/a&gt;)&lt;/span&gt;

&lt;a href="http://en.wikipedia.org/wiki/Occam%27s_Razor"&gt;Occams Razor&lt;/a&gt; is a good way to think about simple solutions, if is getting too complex, if the &lt;a href="http://c2.com/xp/CodeSmell.html"&gt;code start to smell&lt;/a&gt;, think about it again. I'm not saying that every problem has a &lt;a href="http://en.wikipedia.org/wiki/An_Exceptionally_Simple_Theory_of_Everything"&gt;simple solution&lt;/a&gt;, but when getting a to complex solution, make a review to be sure that your path is the more simple, even if it's a complex path.
&lt;span style="font-size:130%;"&gt;
Know the: &lt;a href="http://www.google.com/url?sa=t&amp;amp;ct=res&amp;amp;cd=1&amp;amp;url=http%3A%2F%2Fvideo.google.com%2Fvideoplay%3Fdocid%3D-7230144396191025011&amp;amp;ei=VXqNR8jnFpjceuCRyMAG&amp;amp;usg=AFQjCNE_pKZgxaGt_8-nUuqTiomZ1wZpXA&amp;amp;sig2=uahbvLFN4_mzb81ym_z_Bw"&gt;Scrums&lt;/a&gt; and &lt;a href="http://www.extremeprogramming.org/"&gt;XPs&lt;/a&gt; principles&lt;/span&gt;

As the introduction of this article said you can't use Scrum or XP in your company, but this is not excuse to not know Scrums and XPs principles and foundations.  Scrum and XP are methodologies that try to solve common problems in software development and some principles are applicable even if you can't use it explicitly.  Like the Scrum sprint, we can't ask the user to always refine priorities, but we can try to deliver a functional piece of the software every week or so. User stories of XP is a good way to organize requirements. Using some of the concepts and knowing the problems they try to solve can help you and your team to reach better results.
&lt;span style="font-size:130%;"&gt;
Know what is: &lt;a href="http://www.softwaremetrics.com/fpafund.htm"&gt;Function Point Analysis&lt;/a&gt;&lt;/span&gt;

Function Point Analysis (FPA) it's a metric for software. FPA is hard to do, takes time and if is not a procedure in your company you probably wont be granted the time to do it. But there's something about FPA that is very useful, the "User Perspective". FPA is all about how the user sees the system, every function the system is capable to do and the your knows about is subject to count. The key thing is, if the user asks for a "sort by name" in a column this will affect the complexity of your project.

So, before you say "yes" to something that seems simple, remember that even a little "sort by" adds cost to your project. You can make your user aware of this and construct a good relationship before start to promise things that you can't deliver. When you use FPA you get a notion of the impact of "little" things added, so even if you can't use a formal FPA approach try to make a little informal count (but don't cheat in the count) to see more clearly how "little" functions scale to big efforts.

&lt;span style="font-size:130%;"&gt; Really know about: &lt;a href="http://www.hcibib.org/"&gt;Human-Computer Interaction&lt;/a&gt;&lt;/span&gt;

That's tricky, but users need help to choose a interface that suits them. I've seem developers leave at the user the responsibility to transform a complex spreadsheet system in a new interface for the web, the "draw what you want" approach. Worse, one developer just copied the spreadsheet interface to a web interface. &lt;a href="http://www.codinghorror.com/blog/archives/000734.html"&gt;That's not the way to do it&lt;/a&gt;. Users are not aware of the possibilities of a alternative interface, and the developer who copy a interface probably is not helping the user at all, sometimes the propose of a new system is to avoid spreadsheet interface in the first place.

User generally has a idea of what he/she wants of the interface, some want fast input, some fast search, some want most info in one screen and others want a step by step, like wizards, to complete a process.  When you get this information you can draw screens that help the user but, do not let the user freely draw the screen, use a guideline to help you and the user, like &lt;a href="http://developer.apple.com/documentation/UserExperience/Conceptual/OSXHIGuidelines/XHIGIntro/chapter_1_section_1.html"&gt;Apple Human Interface Guidelines&lt;/a&gt;. Is not that you should write Apple like softwares but when you are familiar with some of the concepts, you get a better idea if a interface will work or not. Who never designed a interface which users keep making the same mistakes over and over again can throw the first stone. When this happens is a wrong designed interface not a dumb user.

&lt;span style="font-weight: bold;"&gt;If your users can't use your software &lt;/span&gt;&lt;a style="font-weight: bold;" href="http://www.codinghorror.com/blog/archives/001022.html"&gt;you are doomed&lt;/a&gt;, doesn't matter if you have the finest code that a programmer can ever produce. You be in a sad place where your users keep using a software that you think is a crap and not using your new top designed solution. Usability is something you should worry about, not knowing could kill your project.

That's it&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-3692712446375165561?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/3692712446375165561/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=3692712446375165561' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/3692712446375165561'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/3692712446375165561'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2008/01/7-things-developer-should-know-to.html' title='7 Things a developer should know to survive big companies'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-444779937802671512</id><published>2007-12-12T17:46:00.000-08:00</published><updated>2007-12-12T19:21:21.073-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='function point analysis'/><category scheme='http://www.blogger.com/atom/ns#' term='software sizing'/><title type='text'>Want a cake? My first question is...</title><content type='html'>...what should be the size of this cake?

I've began some &lt;a href="http://www.ifpug.org/"&gt;Function Point Analysis&lt;/a&gt; (FPA) with a new project in my work, so far this is what I got, but first let's talk about my cake.

The project is not a very complicated one, is more a &lt;span style="font-style: italic;"&gt;store and retrieve&lt;/span&gt; information of some sort. Since I'm working at a bank is basically numbers about a client and without much calculation, so it's  a simple project, nothing better to exercise my sizing methodology skills.

First impression: &lt;span style="font-weight: bold;"&gt;Function Point Analysis it's simple to understand.&lt;/span&gt;

Note that I've wrote &lt;span style="font-weight: bold;"&gt;to understand&lt;/span&gt; and not only &lt;span style="font-weight: bold;"&gt;it's simple&lt;/span&gt;, this is because I managed to get a function count but the implications of this number is still unknown  to me. I've looked at my &lt;a href="http://www.techwr-l.com/techwhirl/magazine/writing/softwarerequirementspecs.html"&gt;SRS document&lt;/a&gt; and applied the FPA rules and got a 354 FPs, this is greater than the example in &lt;a href="http://www.amazon.com/Practical-Software-Estimation-Insourced-Outsourced/dp/0321439104"&gt;the book I'm using&lt;/a&gt;, and the example seemed more complex at first. So I'm still a little puzzled.

Using a very simple extrapolation, a productivity of 10 FP People per month and a team with 5 people, I got a 7 months project. This is feasible?

Thinking a little about it this is feasible for me, if we're talking of the completed project, start to end. But a simple project with 7 months to get it done? Yes, here some reasons:
&lt;ul&gt;&lt;li&gt;The project will be &lt;a href="http://en.wikipedia.org/wiki/Outsourcing"&gt;outsourced&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;There's no clear methodology in use, RUP, Agile or else.
&lt;/li&gt;&lt;li&gt;It's not a single software, in fact is a extension for a web tool in production, requires integration.&lt;/li&gt;&lt;li&gt;It's a global tool two teams of different countries should work together.&lt;/li&gt;&lt;/ul&gt;Even a simple project can suffer a lot in these conditions, so 7 months it's not a surprise, but my FPA is right? Despite the presence of &lt;a href="http://www.softwaremetrics.com/fpafund.htm"&gt;GSC&lt;/a&gt; in a FPA to weight the environment requirements in a project it only count from the user view of the project, but my worries are about things that a user cannot see.

Well, my count is wrong? I'm sandboxing the schedule of the project? If the technical difficulties that worries me were removed the count would not change, what about the schedule?

Only time will tell, but I keep in mind that &lt;a href="http://virtualschool.edu/mon/SoftwareEngineering/BrooksNoSilverBullet.html"&gt;there's no silver bullet&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-444779937802671512?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/444779937802671512/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=444779937802671512' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/444779937802671512'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/444779937802671512'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2007/12/want-cake-my-first-question-is.html' title='Want a cake? My first question is...'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-3481245011443517618</id><published>2007-12-04T17:43:00.000-08:00</published><updated>2007-12-04T17:45:15.848-08:00</updated><title type='text'>If programmers have make a plane</title><content type='html'>You probably felted like &lt;a href="http://www.youtube.com/watch?v=UZq4sZz56qM"&gt;this&lt;/a&gt; before.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-3481245011443517618?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/3481245011443517618/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=3481245011443517618' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/3481245011443517618'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/3481245011443517618'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2007/12/if-programmers-have-make-plane.html' title='If programmers have make a plane'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-433502140248486051</id><published>2007-11-10T20:31:00.000-08:00</published><updated>2008-12-10T23:23:01.559-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='human-computer interface'/><category scheme='http://www.blogger.com/atom/ns#' term='touch-screen'/><category scheme='http://www.blogger.com/atom/ns#' term='future computing'/><category scheme='http://www.blogger.com/atom/ns#' term='two screens laptop'/><title type='text'>Two Screens Laptop</title><content type='html'>Couple days ago I was playing with a &lt;a href="http://www.navegadorguiaquatrorodas.com.br/demonstracao.php"&gt;simple GPS&lt;/a&gt; from my mother and I&lt;br /&gt;realized that in future, not so far away, touch-screens probably will&lt;br /&gt;be ubiquitous as mouses are. Well, in fact I discovered that a &lt;a href="http://www.hci-international.org/"&gt;lot of people are working on this&lt;/a&gt; and I have too some thoughts about how computers will interact with us in future.&lt;br /&gt;&lt;br /&gt;No all talking interface ("Computer do this, do that..."),  but certainly &lt;a href="http://link.brightcove.com/services/link/bcpid271543545/bctid422563006"&gt;touch-screens all around&lt;/a&gt; (see &lt;a href="http://naturalinteraction.org/index.php?d=22&amp;amp;m=10&amp;amp;y=07&amp;amp;category=3"&gt;this too&lt;/a&gt;).  You can see some movement in this direction with the new gadgets of Apple, the &lt;a href="http://www.apple.com/iphone/fingertips/"&gt;iPhone&lt;/a&gt; and &lt;a href="http://www.apple.com/ipodtouch/guidedtour/"&gt;iPod Touch&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Its fantastic how the desktop manipulation is getting better, be &lt;a href="http://www.youtube.com/watch?v=M0ODskdEPnQ"&gt;amazed&lt;/a&gt; with &lt;a href="http://bumptop.com/"&gt;BumpTop&lt;/a&gt;, now think about that kind of behavior with a touch-screen. Since my hypothesis is that will be only touch-screens lets see how a notebook will look in the future, this is a two screens laptop (a rough example below).&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_UFTS2NrETHg/RzaGfFGHWII/AAAAAAAAADk/ddz6g9Sudgs/s1600-h/MacBookPro.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_UFTS2NrETHg/RzaGfFGHWII/AAAAAAAAADk/ddz6g9Sudgs/s200/MacBookPro.jpg" alt="" id="BLOGGER_PHOTO_ID_5131436693937150082" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Note that we can think in a computer that will resemble a todays laptop but with a crucial difference, there is no keyboard. To get the idea think in one computer with another screen in the place of the keyboard. You can slide your finger and a "virtual keyboard" will appear and you type normally, another gesture and the keyboard goes away.&lt;br /&gt;&lt;br /&gt;As iPhone and iPod Touch, if you turn the computer like a book the screen turns too and the pages of your document takes both sides of the laptop and you can turn pages with a finger slide.&lt;br /&gt;&lt;br /&gt;This sounds like document oriented only, but how about applications? Well, see this two demonstrations of &lt;a href="http://www.novell.com/products/desktop/features/xgl/"&gt;XGL&lt;/a&gt; + Linux (&lt;a href="http://www.youtube.com/watch?v=Yx9FgLr9oTk"&gt;here&lt;/a&gt; and &lt;a href="http://www.youtube.com/watch?v=dQkSObRtw0o"&gt;here&lt;/a&gt;) and think about how this will work in a two screens laptop.&lt;br /&gt;&lt;br /&gt;With a two screens laptop we can use it like a real paper sheet notebook, you can turn it, get a pen and draw some diagrams, not write texts, I think keyboards are more useful for writing than pens on a touch-screen, but is possible too.&lt;br /&gt;&lt;br /&gt;The number of possibilities kind explode with a two screens laptop, some fancy controls can pop in the under screen like "virtual knobs" to raise the volume of your music, some very fun games and any stuff you can think of, making the desktop metaphor (after decades) more closely to the real desktop but very powerful.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-433502140248486051?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/433502140248486051/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=433502140248486051' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/433502140248486051'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/433502140248486051'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2007/11/human-computer-interface-future.html' title='Two Screens Laptop'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_UFTS2NrETHg/RzaGfFGHWII/AAAAAAAAADk/ddz6g9Sudgs/s72-c/MacBookPro.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-2674067814663469643</id><published>2007-10-30T19:29:00.000-07:00</published><updated>2007-10-30T20:02:49.119-07:00</updated><title type='text'>Sabe aquele software?</title><content type='html'>Pois é outro dia tive que lembrar de um software que utilizei para modelar tabelas no ORACLE e o nome do dito escapou da mente, felizmente consegui reproduzir uma busca e então o encontrei.

Foi nessa ocasião que percebi precisava criar um pequeno catálogo dos softwares que já utilizei, pois a memória já não está as melhores. Devo estar acumulando uns onze anos em frente a um computador, e já passei pelo &lt;a href="http://sillydog.org/narchive/full123.php"&gt;Netscape Gold&lt;/a&gt; (lembram-se dele?) até &lt;a href="http://www.apple.com/support/tiger/"&gt;Mac OS 10.4&lt;/a&gt; (meu OS atual).

Na verdade não é apenas manter um histórico mas sim uma tabela de referência, já que alguns softwares foram muito úteis e realmente merecem uma propaganda extra.

Graças ao Google a tabela pode ser acessada &lt;a href="http://spreadsheets.google.com/pub?key=pKz4yHuLxv3KUEV7YoC5kTQ"&gt;aqui&lt;/a&gt;, e prometo atualizá-la sempre.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-2674067814663469643?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/2674067814663469643/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=2674067814663469643' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/2674067814663469643'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/2674067814663469643'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2007/10/sabe-aquele-software.html' title='Sabe aquele software?'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-5109726746554155439</id><published>2007-10-06T17:19:00.000-07:00</published><updated>2008-12-10T23:23:01.714-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='latex'/><category scheme='http://www.blogger.com/atom/ns#' term='vim'/><category scheme='http://www.blogger.com/atom/ns#' term='tarefas repetitivas'/><category scheme='http://www.blogger.com/atom/ns#' term='noweb'/><title type='text'>Vim - Facilitando tarefas repetitivas (de noweb para PDF)</title><content type='html'>Eu sou um notório adepto do editor &lt;a href="http://www.vim.org/"&gt;Vim&lt;/a&gt;, carrego até uma &lt;a href="http://portablegvim.sourceforge.net/"&gt;versão portável&lt;/a&gt; em minha &lt;span style="font-style: italic;"&gt;Pen Drive&lt;/span&gt;. Neste &lt;span style="font-style: italic;"&gt;post&lt;/span&gt; vou mostrar como podemos automatizar algumas tarefas repetitivas, neste caso em particular a compilação de um documento &lt;a href="http://www.eecs.harvard.edu/%7Enr/noweb/"&gt;noweb&lt;/a&gt;.  Se você não está familiarizado com o conceito de &lt;a href="http://www.literateprogramming.com/"&gt;Literate Programming&lt;/a&gt;, &lt;a href="http://www-cs-faculty.stanford.edu/%7Eknuth/cweb.html"&gt;CWEB&lt;/a&gt; e &lt;a href="http://www.latex-project.org/"&gt;LaTeX&lt;/a&gt; não precisa se preocupar pois estes conceitos não são o foco deste post.&lt;br /&gt;&lt;br /&gt;E de qual tarefa repetitiva estamos falando? Bom, eis os comandos que eu tenho que executar para obter um documento em formato PDF a partir de um documento noweb.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Primeiro executar o noweb para criar um documento LaTeX:&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:courier new;"&gt;noweave -delay HelloWorld.nw &gt; HelloWorld.tex&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Executar o LaTeX para produzir um documento DVI:&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:courier new;"&gt;latex HelloWorld.tex&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Converter o documento DVI para PDF&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:courier new;"&gt;dvipdf HelloWorld.dvi HelloWorld.pdf&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Abrir o documento PDF para verificá-lo:&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-family:courier new;"&gt;open* HelloWorld.pdf&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;* este comando pertence ao Mac OS X, para outros sistemas você deverá alterar para o que for mais apropriado, por exemplo no Linux podemos utilizar &lt;span style="font-family:courier new;"&gt;acroread HelloWorld.pdf&lt;/span&gt;.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Como você deve ter percebido repetir isso dezenas de vezes enquanto escreve um documento é bastante entediante, e como todo programador é, ou deveria ser, &lt;a href="http://c2.com/cgi/wiki?LazinessImpatienceHubris"&gt;preguiçoso&lt;/a&gt; resolvi automatizar essa tarefa recorrente.&lt;br /&gt;&lt;br /&gt;Dentro do Vim é possível definir novos comandos e estes comandos podem chamar funções e é isso que faremos. Nosso novo comando &lt;span style="font-weight: bold;"&gt;Npdf&lt;/span&gt; irá fazer tudo isso para tal precisamos defini-lo no arquivo &lt;span style="font-weight: bold;"&gt;vimrc&lt;/span&gt; (se você não sabe o que o &lt;span style="font-weight: bold;"&gt;vimrc&lt;/span&gt; significa comece por &lt;a href="http://vimdoc.sourceforge.net/htmldoc/starting.html#vimrc"&gt;aqui&lt;/a&gt;) juntamente com uma a função que irá cuidar de nosso trabalho sujo.&lt;br /&gt;&lt;br /&gt;Meu Vim não reconhece a extensão  &lt;span style="font-weight: bold;"&gt;.nw&lt;/span&gt;, então primeiro vamos dizer a ele que estes arquivos deverão ser interpretados como &lt;span style="font-weight: bold;"&gt;cweb&lt;/span&gt;. Para isso no vimrc escreva:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 212);"&gt;" associa arquivos .nw ao tipo cweb&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;au&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(46, 139, 87);"&gt;&lt;b&gt;BufRead&lt;/b&gt;&lt;/span&gt;,&lt;span style="color: rgb(46, 139, 87);"&gt;&lt;b&gt;BufNewFile&lt;/b&gt;&lt;/span&gt; *.nw &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;set&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(160, 32, 240);"&gt;filetype&lt;/span&gt;=cweb&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Isso fará o Vim atribuir a sintaxe &lt;span style="font-weight: bold;"&gt;cweb&lt;/span&gt; para arquivos &lt;span style="font-weight: bold;"&gt;noweb&lt;/span&gt;. Agora faremos que, se acaso estamos num arquivo &lt;span style="font-weight: bold;"&gt;cweb&lt;/span&gt;, o Vim carregue comandos específicos para este tipo de arquivo, isso ajuda a separar um pouco os comandos por tipo de arquivo, assim podemos ter comandos com nomes iguais para arquivos diferentes. Para instruirmos o Vim a carregar os comandos escrevemos no &lt;span style="font-weight: bold;"&gt;vimrc&lt;/span&gt;:&lt;br /&gt;&lt;pre&gt;&lt;span style="color: rgb(0, 0, 212);"&gt;" Carrega os comandos para arquivos noweb&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;au&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(46, 139, 87);"&gt;&lt;b&gt;FileType&lt;/b&gt;&lt;/span&gt; cweb &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;call&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 0, 0);"&gt;LoadNowebCommands&lt;/span&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;()&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Este comando apenas chama a função &lt;span style="font-family:courier new;"&gt;LoadNowebCommands()&lt;/span&gt; e nela definimos qualquer comando para arquivos &lt;span style="font-weight: bold;"&gt;noweb&lt;/span&gt;. Esta função é bem pequena e simples:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 212);"&gt;"================&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 212);"&gt;" noweb&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 212);"&gt;"&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;function&lt;/b&gt;&lt;/span&gt; LoadNowebCommands&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;()&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 212);"&gt;    " comando que compila um noweb em PDF.&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;com&lt;/b&gt;&lt;/span&gt;! &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;-&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(160, 32, 240);"&gt;nargs&lt;/span&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;=&lt;/b&gt;&lt;/span&gt;&lt;span style="color: rgb(46, 139, 87);"&gt;&lt;b&gt;0&lt;/b&gt;&lt;/span&gt; Npdf &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;call&lt;/b&gt;&lt;/span&gt; &lt;span style="background-color: rgb(0, 0, 0);"&gt;&lt;span style="color: rgb(255, 255, 255);"&gt;Npdf&lt;/span&gt;&lt;/span&gt;(&lt;span style="color: rgb(0, 128, 128);"&gt;expand&lt;/span&gt;(&lt;span style="color: rgb(242, 8, 132);"&gt;"%"&lt;/span&gt;))&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;endfunction&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Dentro dela definimos, neste caso, apenas um comando chamado &lt;span style="font-weight: bold;"&gt;Npdf&lt;/span&gt; e o que ele faz é chamar uma função de mesmo nome que recebe como argumento o nome do arquivo que estamos editando. No Vim comandos e funções ocupam &lt;span style="font-style: italic;"&gt;namespaces&lt;/span&gt; diferentes e por essa razão podemos definir ambos com o mesmo nome.  A linha acima ainda menciona que este comando não aceitará argumentos (&lt;span style="font-family:courier new;"&gt;-nargs=0&lt;/span&gt;).&lt;br /&gt;&lt;br /&gt;Até agora o que fizemos é preparar o Vim, primeiro estabelecendo que os arquivos terminados em &lt;span style="font-weight: bold;"&gt;.nw&lt;/span&gt; deverão ser tratados como do tipo &lt;span style="font-weight: bold;"&gt;cweb&lt;/span&gt;. E se um arquivo for deste tipo, então ele deve chamar a função &lt;span style="font-family:courier new;"&gt;LoadNowebCommands()&lt;/span&gt;, e neste caso esta função define um comando chamado &lt;span style="font-weight: bold;"&gt;Npdf&lt;/span&gt;. E este, se executado, deverá chamar a função &lt;span style="font-family:courier new;"&gt;Npdf()&lt;/span&gt; e passar a ela o nome do arquivo atual. Complicado? Espero que não.&lt;br /&gt;&lt;br /&gt;Agora devemos definir a tão esperada função &lt;span style="font-family:courier new;"&gt;Npdf()&lt;/span&gt; que irá realmente facilitar nossa vida:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;function&lt;/b&gt;&lt;/span&gt; Npdf&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;(&lt;/b&gt;&lt;/span&gt;filename&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;)&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 212);"&gt;    " primeiro salvamos o arquivo&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;write&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;let&lt;/b&gt;&lt;/span&gt; nowebfile &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;=&lt;/b&gt;&lt;/span&gt; a:filename &lt;span style="color: rgb(0, 0, 212);"&gt;" arquivo noweb atual&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 212);"&gt;    " Agora é necessário definir os nomes dos outros arquivos&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 212);"&gt;    " que aparecerão durante o processo.&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;let&lt;/b&gt;&lt;/span&gt; latexfile &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 128, 128);"&gt;substitute&lt;/span&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;(&lt;/b&gt;&lt;/span&gt;nowebfile, &lt;span style="color: rgb(242, 8, 132);"&gt;'\.nw'&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;'.tex'&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;''&lt;/span&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;)&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 0, 212);"&gt;" HelloWorld.nw para HelloWorld.tex&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;let&lt;/b&gt;&lt;/span&gt; dvifile   &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 128, 128);"&gt;substitute&lt;/span&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;(&lt;/b&gt;&lt;/span&gt;nowebfile, &lt;span style="color: rgb(242, 8, 132);"&gt;'\.nw'&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;'.dvi'&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;''&lt;/span&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;)&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 0, 212);"&gt;" HelloWorld.nw para HelloWorld.dvi&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;let&lt;/b&gt;&lt;/span&gt; psfile    &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 128, 128);"&gt;substitute&lt;/span&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;(&lt;/b&gt;&lt;/span&gt;nowebfile, &lt;span style="color: rgb(242, 8, 132);"&gt;'\.nw'&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;'.ps'&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;''&lt;/span&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;)&lt;/b&gt;&lt;/span&gt;  &lt;span style="color: rgb(0, 0, 212);"&gt;" HelloWorld.nw para HelloWorld.ps&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;let&lt;/b&gt;&lt;/span&gt; pdffile   &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 128, 128);"&gt;substitute&lt;/span&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;(&lt;/b&gt;&lt;/span&gt;nowebfile, &lt;span style="color: rgb(242, 8, 132);"&gt;'\.nw'&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;'.pdf'&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;''&lt;/span&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;)&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 0, 212);"&gt;" HelloWorld.nw para HelloWorld.pdf&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 212);"&gt;    " executamos o noweave e checamos se houve algum&lt;/span&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 212);"&gt;    " problema reportado por ele, caso sim paramos por aqui.&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;exec&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(242, 8, 132);"&gt;"!noweave -latex -delay "&lt;/span&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;.&lt;/b&gt;&lt;/span&gt; nowebfile &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;.&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(242, 8, 132);"&gt;" &gt; "&lt;/span&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;.&lt;/b&gt;&lt;/span&gt; latexfile&lt;br /&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; v:shell_error &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;!=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(242, 8, 132);"&gt;""&lt;/span&gt;&lt;br /&gt;         &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;echo&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(242, 8, 132);"&gt;"Noweb error\n"&lt;/span&gt;&lt;br /&gt;         &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;endif&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 212);"&gt;    " executamos o latex...&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;exec&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(242, 8, 132);"&gt;"!latex "&lt;/span&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;.&lt;/b&gt;&lt;/span&gt; latexfile&lt;br /&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;if&lt;/b&gt;&lt;/span&gt; v:shell_error &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;!=&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(242, 8, 132);"&gt;""&lt;/span&gt;&lt;br /&gt;         &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;echo&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(242, 8, 132);"&gt;"LaTeX error\n"&lt;/span&gt;&lt;br /&gt;         &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;return&lt;/b&gt;&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;endif&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 212);"&gt;    " convertemos de dvi para pdf&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;exec&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(242, 8, 132);"&gt;"!dvipdf "&lt;/span&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;.&lt;/b&gt;&lt;/span&gt; dvifile &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;.&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(242, 8, 132);"&gt;" "&lt;/span&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;.&lt;/b&gt;&lt;/span&gt; pdffile&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 212);"&gt;    " e agora checamos nosso novo PDF.`&lt;/span&gt;&lt;br /&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;exec&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(242, 8, 132);"&gt;"!open "&lt;/span&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;.&lt;/b&gt;&lt;/span&gt; pdffile&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;endfunction&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;Esta função é bem simples, primeiro salva nosso arquivo e então determina os nomes dos arquivos envolvidos apenas substituindo suas extensões. E então executa os comandos entediantes que queremos evitar. Note que após o comando &lt;span style="font-weight: bold;"&gt;noweave&lt;/span&gt; e &lt;span style="font-weight: bold;"&gt;latex&lt;/span&gt; checamos se houve qualquer erro, se houver devemos parar o processo já que provavelmente não haverá output viável.&lt;br /&gt;&lt;br /&gt;Agora quando no Vim podemos apenas digitar &lt;span style="font-weight: bold;"&gt;:Npdf&lt;/span&gt; e ele compila, converte e nos mostra o arquivo PDF final.&lt;br /&gt;&lt;br /&gt;Observação: Este post foi atentamente revisado por um aspirante a programador (vide foto):&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_UFTS2NrETHg/RwhJReGV-YI/AAAAAAAAACg/QXcGrbnTj3Q/s1600-h/DSC00464.JPG"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_UFTS2NrETHg/RwhJReGV-YI/AAAAAAAAACg/QXcGrbnTj3Q/s200/DSC00464.JPG" alt="" id="BLOGGER_PHOTO_ID_5118421540992842114" border="0" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-5109726746554155439?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/5109726746554155439/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=5109726746554155439' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/5109726746554155439'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/5109726746554155439'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2007/10/vim-facilitando-tarefas-repetitivas-de.html' title='Vim - Facilitando tarefas repetitivas (de noweb para PDF)'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_UFTS2NrETHg/RwhJReGV-YI/AAAAAAAAACg/QXcGrbnTj3Q/s72-c/DSC00464.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-5666118566891765537</id><published>2007-09-25T21:15:00.000-07:00</published><updated>2007-09-26T14:57:14.438-07:00</updated><title type='text'>Observações sobre acesso a banco de dados.</title><content type='html'>A pouco iniciei minha incursão mais profundo no mundo &lt;a href="http://www.hibernate.org/"&gt;Hibernate&lt;/a&gt;, e eis algumas impressões sobre tal &lt;a href="http://pt.wikipedia.org/wiki/Pas%C3%A1rgada"&gt;Pasárgada&lt;/a&gt;.  Vale também notar que sou recém chegado, estas novas tecnologias podem guardar muitos mais segredos e tesouros do que a mera couraça espinhosa  da primeira impressão que recebi.

Minhas experiências com bancos de dados nunca foram um mar de rosas, houve tempos em que eu declarava repúdio claro a eles, mas hoje, os reconheço e os admiro em muitos pontos. No entanto todo programador sabe que dentro de pouco tempo em seu projeto, terá que escrever linhas de SQL, e não algumas, mas dezenas, senão centenas. Acabam-se criadas bibliotecas de acesso à banco de dados, no meu caso, essas bibliotecas sempre ficavam enormes.

Eis que figuraram-se problemas com esta estratégia, o primeiro e mais óbvio é o alterar de sistema de banco de dados, por exemplo de SQLServer para ORACLE. Apesar de padrão, o SQL não é padrão, por mais paradoxal que isto pareça e portanto alterar de sistema de banco de dados não é trivial. Outro problema é a tonelada de SQLs redundantes e &lt;span style="font-style: italic;"&gt;hardcoded &lt;/span&gt;nestas bibliotecas, algo bem cansativo e tedioso de fazer. Para solucionar estes problemas alguns criaram estratégias para &lt;a href="http://www.sommarskog.se/dynamic_sql.html"&gt;evitar a redundância&lt;/a&gt; e  outros resolveram que &lt;a href="http://blogs.iona.com/newcomer/archives/000048.html"&gt;SQL realmente é desnecessário&lt;/a&gt; (em parte).

Naturalmente se há um problema é esperado que apareçam "soluções", talvez neste momento a pergunta mais pertinente seja: &lt;span style="font-weight: bold;"&gt;Há algum problema?&lt;/span&gt;

Comento isso porque hoje ao ler este &lt;a href="http://worsethanfailure.com/Articles/The-Mythical-Business-Layer.aspx"&gt;artigo&lt;/a&gt; tive um sentimento de solidariedade, e isso porque estou em plena guerra com meu cérebro velho e viciado contra as novidades &lt;span style="font-weight: bold;"&gt;hibernantes&lt;/span&gt;. Prometeram-me o paraíso, e eis que escrevi em cima dele "&lt;a href="http://docs.jboss.org/ejb3/app-server/HibernateAnnotations/reference/en/html_single/index.html#d0e152"&gt;@Entity&lt;/a&gt;", mas ele não persistiu. Então comecei a explorar o que eu precisava fazer para que meus objetos sobrevivessem ao próximo &lt;a href="http://pt.wikipedia.org/wiki/Esc%C3%A2ndalo_do_apag%C3%A3o"&gt;apagão elétrico&lt;/a&gt;.

Descobri, a passos lentos, como persistir meus dados de forma simples e rápida, desde de que eles não estivessem chafurdados em hierarquias complexas e/ou relações "many-to-many". Cada vez mais o modelo orientado objeto não era uma correspondência leal ao modelo relacional, e sabemos que &lt;a href="http://www.agiledata.org/essays/impedanceMismatch.html"&gt;isso nunca foi verdade&lt;/a&gt;, estes modelos são &lt;span style="font-weight: bold;"&gt;diferentes por natureza&lt;/span&gt;. Mas, a princípio, as tecnologias para mapeamento Objeto-Relacional tentam nos "poupar" de pensar em como realizar esta correspondência. Fato é, três dias depois ainda não estou satisfeito, e mesmo com os progressos obtidos tenho aquele sentimento, lá no fundo, dizendo que isso deveria ser mais simples (&lt;a href="http://en.wikiquote.org/wiki/Alan_Kay"&gt;Simple things should be simple&lt;/a&gt;).

E neste momento que volto a cogitar as boas e velhas bibliotecas de acesso,  com SQL hardcoded, diversos métodos quase redundantes e etc. Mas uma coisa elas sabiam fazer bem, guardar os dados. A verdade é que eu desejo apenas salvar certas informações, e mais que isso, salvá-las corretamente quando falamos de modelo relacional, afinal de contas acoplar meu modelo relacional ao meu aplicativo também muito errado, neste caso eu fecharia as portas para qualquer outro acesso.

Há a refutação de troca de sistema, afinal de contas uma vez implementado para um sistema de banco de dados, se houver a necessidade de utilizar outro então teremos o trabalho de codificar uma nova biblioteca de acesso, mas nada extraordinariamente complexo.

O que me parece, é que devemos ter muito discernimento quanto as tecnologias que vamos utilizar, ora elas são adequadas, ora não. Neste caso em particular creio que a criação de bibliotecas com SQL hardcoded deveria ser a opção mais comum e não o oposto. Tais bibliotecas não são má prática (a não ser que mal codificadas), pelo menos eu não as considero desta forma. Talvez não sejam tão flexíveis, mas &lt;a href="http://worsethanfailure.com/Articles/Generic_Generics.aspx"&gt;flexibilidade demais&lt;/a&gt; pode ser estranho.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-5666118566891765537?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/5666118566891765537/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=5666118566891765537' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/5666118566891765537'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/5666118566891765537'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2007/09/observaes-sobre-acesso-banco-de-dados.html' title='Observações sobre acesso a banco de dados.'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-7619047257862809374</id><published>2007-08-17T19:54:00.000-07:00</published><updated>2007-10-06T20:01:33.912-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vim'/><category scheme='http://www.blogger.com/atom/ns#' term='formatacao'/><title type='text'>Formatando código para post em Blogs.</title><content type='html'>Eu estava lendo um &lt;a href="http://steve.yegge.googlepages.com/language-trickery-and-ejb"&gt;blog&lt;/a&gt; e uma das coisas que me chamaram a atenção no blog foi como o código estava bem formatado. Então procurei na internet uma maneira de formatar o código para posts de blogs.

A &lt;a href="http://aspadvice.com/blogs/jlovell/archive/2004/11/11/1998.aspx"&gt;primeira sugestão&lt;/a&gt; foi horrível! Quer dizer que então eu colo o código o Notepad e então executo um Find/Replace para substituir os tabs por espaços? Mas e as cores? E se eu não preceder o código com a tag PRE? Os espaços serão solenemente ignorados.

Então &lt;a href="http://blogs.msdn.com/brada/archive/2004/10/05/238427.aspx"&gt;alguém nos sugere&lt;/a&gt; colar o código no MS Word, nem terminei de ler o post.

Lembrei que o &lt;a href="http://www.vim.org/"&gt;Vim&lt;/a&gt; possui um conversor para HTML, e realizando uma busca simples encontrei &lt;a href="http://tips.webdesign10.com/how-to-convert-code-to-html-with-vim"&gt;:TOhtml&lt;/a&gt;, enfim temos (um pequeno e velho script):

&lt;pre&gt;&lt;span style="font-size:100%;"&gt;&lt;span style="color: rgb(160, 32, 240);"&gt;use strict&lt;/span&gt;;
&lt;span style="color: rgb(160, 32, 240);"&gt;use warnings&lt;/span&gt;;

&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;my&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 128, 128);"&gt;%desc&lt;/span&gt;;

&lt;span style="color: rgb(0, 128, 128);"&gt;$desc{&lt;/span&gt;&lt;span style="color: rgb(242, 8, 132);"&gt;568&lt;/span&gt;&lt;span style="color: rgb(0, 128, 128);"&gt;}&lt;/span&gt; = [&lt;span style="color: rgb(242, 8, 132);"&gt;0&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;0&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;3&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;4&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;3&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;3&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;3&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;0&lt;/span&gt;];
&lt;span style="color: rgb(0, 128, 128);"&gt;$desc{&lt;/span&gt;&lt;span style="color: rgb(242, 8, 132);"&gt;461&lt;/span&gt;&lt;span style="color: rgb(0, 128, 128);"&gt;}&lt;/span&gt; = [&lt;span style="color: rgb(242, 8, 132);"&gt;0&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;0&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;3&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;4&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;3&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;4&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;3&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;3&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;4&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;0&lt;/span&gt;];
&lt;span style="color: rgb(0, 128, 128);"&gt;$desc{&lt;/span&gt;&lt;span style="color: rgb(242, 8, 132);"&gt;567&lt;/span&gt;&lt;span style="color: rgb(0, 128, 128);"&gt;}&lt;/span&gt; = [&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;0&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;3&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;0&lt;/span&gt;];
&lt;span style="color: rgb(0, 128, 128);"&gt;$desc{&lt;/span&gt;&lt;span style="color: rgb(242, 8, 132);"&gt;572&lt;/span&gt;&lt;span style="color: rgb(0, 128, 128);"&gt;}&lt;/span&gt; = [&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;3&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;0&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;0&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;0&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;0&lt;/span&gt;];
&lt;span style="color: rgb(0, 128, 128);"&gt;$desc{&lt;/span&gt;&lt;span style="color: rgb(242, 8, 132);"&gt;566&lt;/span&gt;&lt;span style="color: rgb(0, 128, 128);"&gt;}&lt;/span&gt; = [&lt;span style="color: rgb(242, 8, 132);"&gt;0&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;3&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;0&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;0&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;0&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;0&lt;/span&gt;];
&lt;span style="color: rgb(0, 128, 128);"&gt;$desc{&lt;/span&gt;&lt;span style="color: rgb(242, 8, 132);"&gt;570&lt;/span&gt;&lt;span style="color: rgb(0, 128, 128);"&gt;}&lt;/span&gt; = [&lt;span style="color: rgb(242, 8, 132);"&gt;0&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;0&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;0&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;0&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;0&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;0&lt;/span&gt;];
&lt;span style="color: rgb(0, 128, 128);"&gt;$desc{&lt;/span&gt;&lt;span style="color: rgb(242, 8, 132);"&gt;571&lt;/span&gt;&lt;span style="color: rgb(0, 128, 128);"&gt;}&lt;/span&gt; = [&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;4&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;4&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;3&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;2&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;4&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt;,&lt;span style="color: rgb(242, 8, 132);"&gt;0&lt;/span&gt;];

&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;foreach&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;my&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 128, 128);"&gt;$loja&lt;/span&gt; (&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;keys&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 128, 128);"&gt;%desc&lt;/span&gt;) {

&lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;foreach&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;my&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 128, 128);"&gt;$day&lt;/span&gt; (&lt;span style="color: rgb(242, 8, 132);"&gt;1&lt;/span&gt; .. &lt;span style="color: rgb(242, 8, 132);"&gt;7&lt;/span&gt;) {

   &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;my&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 128, 128);"&gt;$count&lt;/span&gt; = &lt;span style="color: rgb(242, 8, 132);"&gt;0&lt;/span&gt;;

   &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;foreach&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;my&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(0, 128, 128);"&gt;$h&lt;/span&gt; (&lt;span style="color: rgb(242, 8, 132);"&gt;8&lt;/span&gt; .. &lt;span style="color: rgb(242, 8, 132);"&gt;22&lt;/span&gt;) {

       &lt;span style="color: rgb(128, 64, 64);"&gt;&lt;b&gt;print&lt;/b&gt;&lt;/span&gt; &lt;span style="color: rgb(242, 8, 132);"&gt;"&lt;/span&gt;&lt;span style="color: rgb(242, 8, 132);"&gt;insert into cliente_desconto_passagens
(cliente_id, semana_dia_id, hora, desconto )
values (&lt;/span&gt;&lt;span style="color: rgb(0, 128, 128);"&gt;$loja&lt;/span&gt;&lt;span style="color: rgb(242, 8, 132);"&gt;, &lt;/span&gt;&lt;span style="color: rgb(0, 128, 128);"&gt;$day&lt;/span&gt;&lt;span style="color: rgb(242, 8, 132);"&gt;, &lt;/span&gt;&lt;span style="color: rgb(0, 128, 128);"&gt;$h&lt;/span&gt;&lt;span style="color: rgb(242, 8, 132);"&gt;, &lt;/span&gt;&lt;span style="color: rgb(0, 128, 128);"&gt;$desc{$loja}[$count]&lt;/span&gt;&lt;span style="color: rgb(242, 8, 132);"&gt;); &lt;/span&gt;&lt;span style="color: rgb(106, 90, 205);"&gt;\n&lt;/span&gt;&lt;span style="color: rgb(242, 8, 132);"&gt;"&lt;/span&gt;;

       &lt;span style="color: rgb(0, 128, 128);"&gt;$count&lt;/span&gt;++;
   }
}
}

&lt;/span&gt;&lt;/pre&gt;O que para mim está de bom e prático o suficiente.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-7619047257862809374?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/7619047257862809374/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=7619047257862809374' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/7619047257862809374'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/7619047257862809374'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2007/08/formatando-cdigo-para-post-em-blogs.html' title='Formatando código para post em Blogs.'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-3045422901513798879</id><published>2007-07-14T02:20:00.000-07:00</published><updated>2007-10-06T20:02:15.633-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='zero esquerda'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><category scheme='http://www.blogger.com/atom/ns#' term='formatar'/><title type='text'>Colocando zeros à esquerda em Java</title><content type='html'>Eu sou um velho programador Perl tentando sobreviver no mundo Java, é assim que me sinto às vezes, principalmente hoje que resolvi colocar zeros à esquerda de um número  qualquer.

O que eu fiz a muito tempo atrás em Perl está desta maneira:
&lt;span style="color: rgb(128, 160, 248);"&gt;&lt;span style="font-family:monospace;"&gt;
&lt;/span&gt;&lt;span style="color: rgb(255, 0, 0);"&gt;&lt;/span&gt;&lt;/span&gt;&lt;pre style="color: rgb(255, 0, 0);"&gt;&lt;span style="font-family:courier new;"&gt;my $contig = '12';&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;$contig = '0' x (5-length($contig)). $contig;&lt;/span&gt;
&lt;span style="font-family:courier new;"&gt;print "$contig\n";&lt;/span&gt;
&lt;/pre&gt;
Ou seja, eu preciso de um número de comprimento fixo de 5 dígitos, e caso este número não tenha este comprimento ele deve ser preenchido com zeros, com certeza essa não foi a melhor maneira de implementar mas isso é um outro problema, eu era jovem. No entanto como implementar zeros à esquerda em Java?

Bom eu esperava mais linhas mas não &lt;a href="http://www.imasters.com.br/artigo/5421/java/preencha_a_esquerda_com_zero_ou_a_direita_com_branco_em_java/"&gt;isso&lt;/a&gt; (excesso de abstração! e pior, ele usa Java 5 para fazer essa confusão!) e menos ainda &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/Formatter.html"&gt;passear por aqui&lt;/a&gt; sem encontrar exemplos suficientes  (mal de javadoc). Felizmente encontrei &lt;a href="http://www.particle.kth.se/%7Elindsey/JavaCourse/Book/Part1/Tech/Chapter05/formatterPrintf.html"&gt;este site&lt;/a&gt; que coloca um pouco de luz sobre o &lt;a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/Formatter.html"&gt;Formatter&lt;/a&gt; e a solução ficou como eu gostaria, simples e direta:

&lt;pre&gt;
&lt;span style="color: rgb(0, 153, 0);font-family:courier new;" &gt;private String wrapPageNumber(int page) {&lt;/span&gt;
&lt;span style="color: rgb(0, 153, 0);font-family:courier new;" &gt;    return String.format("%03d", Integer.valueOf(page));&lt;/span&gt;
&lt;span style="color: rgb(0, 153, 0);font-family:courier new;" &gt;}&lt;/span&gt;
&lt;/pre&gt;

Eu apenas passo o número da página, um inteiro neste caso, e então recebo o número formatado corretamente com os zeros à esquerda.

"Simple things should be simple."


* OBS: &lt;span style="color: rgb(0, 153, 0);font-family:arial;" &gt;&lt;span style="font-family:courier new;"&gt;Integer.valueOf&lt;/span&gt;  &lt;/span&gt;poderia ser omitido o que resultaria em (mais simples ainda):

&lt;span style="color: rgb(0, 153, 0);font-family:courier new;" &gt;return String.format("%03d", page);&lt;/span&gt;

Mas eu sou do time que possui reservas com o uso de autoboxing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-3045422901513798879?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/3045422901513798879/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=3045422901513798879' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/3045422901513798879'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/3045422901513798879'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2007/07/colocando-zeros-esquerda-em-java.html' title='Colocando zeros à esquerda em Java'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-7195613727358719381</id><published>2007-07-04T19:28:00.000-07:00</published><updated>2007-10-06T20:02:55.133-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='cpan'/><category scheme='http://www.blogger.com/atom/ns#' term='perl'/><title type='text'>Complicações e simplificações</title><content type='html'>Não é para levantar qualquer guerra religiosa que escrevo este post. No entanto eu gostaria de fazer algumas considerações sobre simplicidade e complexidade.

 Primeiramente gostaria de lembrar um ditado do mundo Perl "Simple things should be simple, hard things should be possible." (Coisas simples devem ser simples, coisas complicadas devem ser possíveis). Este dizer é, para mim, de extrema importância em diversas áreas mas principalmente no desenvolvimento de software. Fico bastante impressionado quando tenho que atualizar o projeto em que estou envolvido, com Struts e um JBoss, e qualquer mudança, por mais simples, deve ser muito bem feita e levando em consideração todas as variantes destes frameworks. Mais interessante é o movimento POJO, que não passa de um clamor pela simplicidade das coisas simples.

A linguagem Java é simples, qualquer programador Java poderia confirmar isso, mas talvez não o faça se ele estiver envolvido num projeto com EJBs, JPA, JTA, JMX, J..., J..., J... Mas a língua é simples a linguagem (aqui digo sobre as especificações) é que é complexa.  Não sou um especialista em todas as especificações e problemas endereçados pela J2EE mas tenho a impressão que talvez, somente talvez, algumas coisas poderiam ser mais simples.

 A alguns anos atrás estive envolvido num projeto de integração, em nosso projeto implementamos comunicação de objetos distribuídos e mais um pequeno framework para a web. Naquela época eu apenas trabalhava com Perl e pouco sabíamos sobre MVC, IOC e Dependency Injection, sabíamos que precisávamos integrar nossas informações, linearizar nossas interfaces e tudo isso com o mínimo de esforço. A boa coisa é que, não foi fácil, mas conseguimos atingir um meio-termo entre novas regras e velhos códigos, e assim nossa framework foi ao ar.

 Nessa pequena framework caseira as complexidades de separar "Visão" de "Modelo" apareceram e sim, não foram tão simples de resolver, mas mesmo assim parecem mais simples do que as soluções atuais. Mais uma vez, era uma solução caseira, no entanto parece-me que uma solução profissional deveria ser mais simples, mas não foi a realidade.

 Alguns meses depois de conhecer o Struts fui apresentado ao VRaptor um framework peso leve, e então me senti mais aliviado, pois coisas simples deveriam ser simples. Isso foi ótimo, pois senti-me localizado mais uma vez.

 Talvez os esforços em tratar as complexidades do mundo corporativo foram muito afundo nos problemas, ou seja, endereçando de maneira robusta estes problemas.  O problema é que robustez normalmente vai na contra-mão da simplicidade. E agora o movimento POJO procura manter a robustez no entanto simplificando seu uso, as "anotações" em Java deram uma boa ajuda neste quesito.

 Agora sinto falta do CPAN (Comprehensive Perl Archive Network) para Java. Já vi iniciativas neste sentido, como CJAN e o JJar. E o que tem o CPAN de tão interessante ao mundo Java? A resposta deve variar, mas minha visão está focada na unicidade de função, ou seja, fazer algo uma única vez e bem. Claro, isso é reuso de código!

 A grande vantagem do CPAN é a centralização do código, se você pretende fazer algo um pouco mais complicado em Perl antes de abrir seu editor você deve buscar no CPAN, assim é muito provável que alguém já tenha solucionado parte ou totalidade do seu problema. Caso contrário você pode criar seu módulo e publicá-lo no CPAN, mas há algo muito importante nisso. Antes de tentar criar seu próprio módulo há uma recomendação no CPAN, antes de criar seu módulo há um parecido que pode ser melhorado ou estendido? E isso eu acho uma ótima política, força os desenvolvedores uma nova análise do código atual e a colaboração entre si. Enquanto escrevo este post o CPAN informa que há 11830 módulos cadastrados, o que dá um pouco a dimensão da gama de problemas já solucionados, mas onde procurar quando estamos falando de Java?

Eis a sugestão, ou melhor, a necessidade que Java enfrenta hoje, uma comunidade como o CPAN. E como Audrey Tang coloca bem "Perl" é a sintaxe e "CPAN" é a linguagem. Já possuímos a sintaxe no mundo Java, agora precisamos criar a linguagem.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-7195613727358719381?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/7195613727358719381/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=7195613727358719381' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/7195613727358719381'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/7195613727358719381'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2007/07/complicaes-e-simplificaes.html' title='Complicações e simplificações'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-11360654559570708</id><published>2007-06-27T23:05:00.000-07:00</published><updated>2007-06-27T23:41:12.910-07:00</updated><title type='text'>Kathy Sierra afasta-se da net devido ameaças</title><content type='html'>Hoje em dia estou bem menos sensível, talvez todos nós, é uma pena mas nos adaptamos para sobreviver. Uma avalanche de informações nos atinge todos os dias e grande parte delas, creio que todos concordam, não são boas notícias. Talvez a velha retórica da "Ignorância é uma bênção" volte às nossas mentes, um desejo antigo e ingênuo de nos livrarmos das angústias de nosso moderno mundo.

 Enfim, a introdução pomposa é apenas para lembrar o que por vezes esquecemos. Mas qual a relação com computação? Bom, tardiamente notei que o blog da &lt;span style="font-weight: bold;"&gt;Kathy Sierra&lt;/span&gt; não era atualizado e fui buscar as razões. Foi uma experiência muito triste descobrir que o blog não era atualizado porque alguém à ameaçava sexualmente e a sua vida. Fiquei estarrecido, como poderia uma pessoa como a Kathy ser intimidada para fora da internet?

 Para aqueles que não sabem quem Kathy Sierra é pode começar por uma busca no Google, logo vai perceber que ela é um expoente na área da programação e da educação na mesma área. E atualmente estou lendo um livro dela, &lt;span style="font-style: italic;"&gt;Head First - EJB&lt;/span&gt;. Pelo que pude ler as ameaças foram muito graves e realmente não deixaram outra opção a ela a não ser isolar-se, pelo menos durante algum período.

  Algumas discussões foram levantadas como a revolta da presença de uma mulher num campo dominado por homens, uma ignorância sem tamanho que nos remete a todo preconceito existente. E qualquer preconceito deve ser combatido viementemente.

 Só posso lamentar o acontecido,  esperar que Kathy se recupere do susto e que possa em um futuro breve voltar a nos informar e ensinar com maestria.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-11360654559570708?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/11360654559570708/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=11360654559570708' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/11360654559570708'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/11360654559570708'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2007/06/kathy-sierra-afasta-se-da-net-devido.html' title='Kathy Sierra afasta-se da net devido ameaças'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-5803468007050614864</id><published>2007-06-10T19:57:00.000-07:00</published><updated>2007-06-10T20:11:00.055-07:00</updated><title type='text'>"The Promise, The Limits, The Beauty of Software"</title><content type='html'>&lt;a href="http://video.yahoo.com/video/play?ei=UTF-8&amp;b=2&amp;amp;vid=577305&amp;amp;gid=133414"&gt;Essa palestra&lt;/a&gt; dada por &lt;a href="http://en.wikipedia.org/wiki/Grady_Booch"&gt;Grady Booch&lt;/a&gt; é ótima, fazia tempo que eu não ouvia sobre software de uma pessoa com tanta experiência e entusiasmo.

Creio que não seja uma palestra para iniciantes, pois muitas considerações são observações da experiência, ou seja, padrões e problemas bastante comuns no desenvolvimento de software. Também é uma excelente oportunidade para relembrar o prazer que é ser programador e estar envolvido nesta área tão complexa e tão necessária ao nosso modo de vida.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-5803468007050614864?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/5803468007050614864/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=5803468007050614864' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/5803468007050614864'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/5803468007050614864'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2007/06/promise-limits-beauty-of-software.html' title='&quot;The Promise, The Limits, The Beauty of Software&quot;'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-4804021207365964841</id><published>2007-06-10T14:20:00.000-07:00</published><updated>2007-06-10T14:29:38.724-07:00</updated><title type='text'>Todo programador Java ruim que eu conheço...</title><content type='html'>Esse tópico foi sugerido no &lt;a href="http://www.guj.com.br/posts/list/61615.java"&gt;GUJ&lt;/a&gt; e das respostas dadas (daquelas que li dentre as várias postadas), a que eu concordo em todos aspectos é do &lt;span style="font-weight: bold;"&gt;Fabio Kung&lt;/span&gt; (professor da Caelum):

"Todo programador Java ruim que eu conheço só sabe Java."

Mantendo em mente:
&lt;blockquote&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;blockquote&gt;&lt;blockquote&gt;    "Learn at least one new [programming] language every year.    Different languages solve the same problems in different ways.  By    learning several different approaches, you can help broaden your    thinking and avoid getting stuck in a rut."&lt;/blockquote&gt;    --- &lt;a href="http://www.pragmaticprogrammer.com/ppbook/"&gt;&lt;i&gt;The Pragmatic Programmer&lt;/i&gt;&lt;/a&gt;&lt;/blockquote&gt;&lt;a href="http://www.pragmaticprogrammer.com/ppbook/index.shtml"&gt;&lt;i&gt;&lt;/i&gt;&lt;/a&gt;&lt;blockquote&gt;&lt;/blockquote&gt;&lt;a href="http://www.pragmaticprogrammer.com/ppbook/index.shtml"&gt;&lt;i&gt;&lt;/i&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-4804021207365964841?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/4804021207365964841/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=4804021207365964841' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/4804021207365964841'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/4804021207365964841'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2007/06/todo-programador-java-ruim-que-eu.html' title='Todo programador Java ruim que eu conheço...'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-1582958370090403027</id><published>2007-06-05T19:10:00.000-07:00</published><updated>2008-12-10T23:23:02.290-08:00</updated><title type='text'>SCJP5 = SCJP5 + 1;</title><content type='html'>&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_UFTS2NrETHg/RmYYFlKHU2I/AAAAAAAAABA/co9TPYGvr1o/s1600-h/scjp5.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; cursor: pointer;" src="http://2.bp.blogspot.com/_UFTS2NrETHg/RmYYFlKHU2I/AAAAAAAAABA/co9TPYGvr1o/s320/scjp5.jpg" alt="" id="BLOGGER_PHOTO_ID_5072768514432389986" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Eis o resultado de uma verdadeira saga! Enfim consegui obter meu pedigree, agora sou um Programador Java 5 certificado.&lt;br /&gt;&lt;br /&gt;Já não basta o stress de uma prova de certificação, tive as seguintes confusões como um bônus:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Uma greve das Lotações; fiquei uma hora preso na Rebouças sem qualquer chance de chegar no horário para fazer a prova. Tive que parar o carro e ir de carona na moto de um grande amigo (Consegui chegar no horário).&lt;/li&gt;&lt;li&gt;Durante a prova houve uma queda na rede e parou tudo! Fiquei 20 minutos esperando para saber o que iria ser das minhas 30 questões respondidas, felizmente o software volta do ponto que parou e trocaram meu computador.&lt;/li&gt;&lt;li&gt;Depois da troca, prossegui com a prova até descobrir que as questões de "Drag and Drop" não funcionavam neste novo computador. Tempo correndo, chamei o técnico e a pessoa responsável pelo teste, e obtive a seguinte resposta: "É verdade alguns alunos reclamaram disso mesmo! É problema no software da Prometric, pule a questão...", perguntei se eu poderia voltar ao outro computador, cujo o software funcionada, e então: "Vixe, não vai dar não, tem outro aluno usando e a prova dele demora umas 4 horas." Prefiro não contar o resto do diálogo, enquanto os meus últimos 20 minutos de teste passavam durante toda a argumentação.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Ao final da prova um comprovante deve ser impresso, foi? Claro que não, tive que esperar o técnico configurar outra impressora. Por fim, entrei às 11:30 para fazer uma prova de 3 horas, sai lá pelas 16:10!&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Ah, era meu rodízio, quando cheguei ao carro eu não podia sair, tive que ir ao Shopping Eldorado esperar até as 20:00, pegar um táxi de volta pro carro e então voltar para casa.&lt;/li&gt;&lt;/ul&gt;Enfim, Niels Bohr disse: "Qualquer predição é arriscada, principalmente sobre o futuro.", ok mas não precisava exagerar!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-1582958370090403027?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/1582958370090403027/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=1582958370090403027' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/1582958370090403027'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/1582958370090403027'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2007/06/scjp5-scjp5-1.html' title='SCJP5 = SCJP5 + 1;'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_UFTS2NrETHg/RmYYFlKHU2I/AAAAAAAAABA/co9TPYGvr1o/s72-c/scjp5.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-4762834711927379392</id><published>2007-05-13T14:41:00.000-07:00</published><updated>2007-05-13T14:47:39.598-07:00</updated><title type='text'>The Role of Programming</title><content type='html'>Não deixe que a brevidade desta &lt;a href="http://video.google.com/videoplay?docid=-2726904509434151616"&gt;exposição feita por Gerald Jay Sussman&lt;/a&gt; mascare a enorme quantidade de conhecimento embutida.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-4762834711927379392?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/4762834711927379392/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=4762834711927379392' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/4762834711927379392'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/4762834711927379392'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2007/05/role-of-programming.html' title='The Role of Programming'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-554827217213565492</id><published>2007-03-21T18:55:00.000-07:00</published><updated>2007-03-22T08:34:36.520-07:00</updated><title type='text'>Perl 6, onde está você?</title><content type='html'>Pode ser uma guerra de egos, talvez tão intensa quanto as guerras por motivos religiosos, times de futebol e partidos políticos. Mas querendo ou não, Perl é uma linguagem que tem seu espaço.

Desenvolvo em Perl desde 1999 e posso listar algumas dos maiores mal entendidos sobre essa liguangem.
&lt;ul&gt;&lt;li&gt;Perl é uma linguagem voltada a CGI&lt;/li&gt;&lt;/ul&gt;Esse é um engano tanto quanto interessante, talvez porque a alguns anos muito do dinamismo em websites era fornecido por um script em Perl rodando como CGI num servidor Apache. É interessante porque a Perl não foi concebida como uma linguagem voltada a geração de páginas da web e sim como uma linguagem para &lt;a href="http://www.isc.org/sources/devel/lang/perl.txt"&gt;processar e extrair relatórios&lt;/a&gt;, seu nome já diz isso PERL - &lt;span style="font-style: italic;"&gt;Pratical Extraction and Report Language&lt;/span&gt;.  O que eu posso concordar é que lidar com CGI, também é lidar com processamento de texto, principalmente inputs de usuários e etc, mas ao contrário de outras linguagens como PHP, a Perl não foi criada com esse objetivo em mente, pelo menos não explicitamente.
&lt;ul&gt;&lt;li&gt;Perl não é uma linguagem para sistemas robustos, grandes, comerciais e etc.&lt;/li&gt;&lt;/ul&gt;Esse argumento é bastante complicado de se refutar. Primeiramente o que faz uma linguagem adequada para tais tarefas? Minha experiência com sistemas comerciais é pequena, mas há projetos em Perl muito sérios e robustos, um exemplo é o &lt;a href="http://www.ensembl.org/"&gt;Ensembl&lt;/a&gt; um visualisador de genomas, implementado sobre a famosa &lt;a href="http://bioperl.org/"&gt;BioPerl&lt;/a&gt;. Para saber mais vale o artigo do admirável Lincoln Stein - &lt;a style="font-style: italic;" href="http://www.bioperl.org/wiki/How_Perl_saved_human_genome"&gt;&lt;span style="font-size:100%;"&gt;How Perl saved human genome.&lt;/span&gt;&lt;/a&gt; Por fim, as opiniões podem variar, mas creio que o Projeto Genoma Humano é um projeto sério e grande e merece respeito. Até hoje Perl é extensamente utilizada na pesquisa em Bioinformática, e para uma referência final talvez uma olhada nas &lt;a href="http://www.oreillynet.com/pub/a/oreilly/perl/news/success_stories.html"&gt;Perl success histories&lt;/a&gt;.
&lt;ul&gt;&lt;li&gt;Perl é uma linguagem estranha e sua sintaxe é ilegível.&lt;/li&gt;&lt;/ul&gt;A mim isso não é argumento, &lt;a href="http://en.wikipedia.org/wiki/Lisp_programming_language"&gt;LISP&lt;/a&gt; tem uma sintaxe talvez mais estranha e é uma linguagem levada a sério. E mais de uma vez quando deparo com outras linguagens devo tirar um tempo para me adaptar à sintaxe da linguagem. Na verdade até Java pode ser escrita de maneira confusa e ilegível, e pela minha experiência não é a sintaxe da linguagem, ou seja, as instruções  que a tornam ilegível e sim o programador. Utilizar recursos obscuros da linguagem, mesmo quando não são necessários, é uma contradição a mais de uma das recomendações do livro &lt;a href="http://en.wikipedia.org/wiki/The_Elements_of_Programming_Style_%28book%29"&gt;Elements of Programming Style&lt;/a&gt;, veja este &lt;a href="http://beta.blogger.com/cs.boisestate.edu/%7Eamit/teaching/handouts/style.pdf"&gt;(PDF)&lt;/a&gt; para um pequeno resumo. E finalmente a melhor maneira de refutar este argumento é citar o &lt;a href="http://www.ioccc.org/main.html"&gt;&lt;span style="font-size:100%;"&gt;&lt;i&gt;The International Obfuscated C Code Contest&lt;/i&gt;&lt;/span&gt;&lt;/a&gt;, oras apesar deste concurso podemos citar a linguagem C utilizada em grandes projetos, portanto não é a legibilidade de um programa que define a qualidade da linguagem em que está escrito, ao menos para casos normais, para outros casos que tal &lt;a href="http://www.lscheffer.com/malbolge.shtml"&gt;Malbolge?&lt;/a&gt; E Perl também teve o seu &lt;a href="http://en.wikipedia.org/wiki/Obfuscated_Perl_contest"&gt;&lt;span style="font-style: italic;"&gt;Obfuscated Perl Contest&lt;/span&gt;&lt;/a&gt; para os curiosos.
&lt;ul&gt;&lt;li&gt;Perl falha no paradigma Orientado Objeto.&lt;/li&gt;&lt;/ul&gt;Este argumento já é pronunciado por pessoas com um pouco mais deconhecimento em Perl e realmente pega num ponto "fraco" da Perl. Coloco a palavra fraco entre aspas porque Perl realmente não é uma linguagem concebida como orientada a objetos (OO de agora em diante), mas isso aparentemente não é um problema, e porque não? Bom, ao ler o livro &lt;a href="http://www.manning.com/conway/"&gt;&lt;span style="font-size:100%;"&gt;Object Oriented Perl&lt;/span&gt;&lt;/a&gt; de Damian Conway você se surpreenderá de como Perl pode ser utilizada dentro do paradigma OO com muita flexibilidade e integridade. Projetos como a BioPerl (citada acima) são todos implementados utilizando a Perl em OO, quase todos os&lt;span style="font-weight: normal;font-size:100%;" &gt; 11348&lt;/span&gt; (em 21/03/2007)  módulos hospedados no &lt;a href="http://www.cpan.org/"&gt;CPAN&lt;/a&gt; possuem uma interface OO. Sim, Perl não é nativamente OO, mas isso não parece ser algo tão grave assim, há &lt;a href="http://search.cpan.org/search?m=module&amp;q=Class"&gt;vários módulos&lt;/a&gt;  que tornam a Perl mais OO. No entanto vale o lembrete que OO é um paradigma  e não uma linguagem específica, ou implementação de uma linguagem, é uma maneira de se trabalhar e pensar! Visto que a Perl nos dá maneiras de codificar de acordo com este paradigma, então basta disciplina, veja a entrevista de &lt;a href="http://www.literateprogramming.com/clb93.pdf"&gt;Donald Knuth onde ele cita exatamente isso&lt;/a&gt;.

Mas porque qual é a razão deste artigo? O título dele faz referência à Perl6, e quem é a Perl6? A Perl6 é uma grande promessa, é a reescrita da Perl (formalmente conhecida como Perl5) pela comunidade de desenvolvedores ("&lt;a href="http://use.perl.org/articles/00/07/19/161217.shtml"&gt;Perl 5 was my rewrite of perl... I think this should be the community's rewrite of perl, and the community's rewrite of the community.&lt;/a&gt;"), note a data do artigo 19/07/2000.

Dentro das novas especificações da Perl6 há:
&lt;ul&gt;&lt;li&gt;Tipagem forte&lt;/li&gt;&lt;li&gt;Metadados em variáveis, valores, subrotinas...&lt;/li&gt;&lt;li&gt;Expressões regulares em Streams&lt;/li&gt;&lt;li&gt;Argumentos nomeados&lt;/li&gt;&lt;/ul&gt;E muito mais, para aqueles que não sofrem do coração os &lt;a href="http://dev.perl.org/perl6/doc/apocalypse.html"&gt;Apocalypse Docs&lt;/a&gt; podem ser um lugar bom para se perder. E mais, a Perl6 irá fazer uso do &lt;a href="http://www.parrotcode.org/"&gt;Parrot,&lt;/a&gt; uma Virtual Machine capaz de executar o código da Perl6. Ops?! Virtual Machine para Perl? Onde mais ouvimos falar de Virtual Machine? Sim, Java! Java faz uso de uma Virtual Machine e logo a Perl também o fará.

Enfim, minha &lt;a href="http://use.perl.org/comments.pl?sid=5394&amp;amp;cid=8340"&gt;ansiedade pelo release 1 da Perl6&lt;/a&gt; é muito grande. Dadas tantas novidades e tanta potencialidade eu sinto que a Perl6 pode muito bem ocupar um lugar de distinção no meio comercial. Pois neste caso, ela estará de acordo com algumas exigências como tipagem, bytecode, virtual machine e etc, que são utilizadas para refutar o uso da Perl nestes ambientes.

Apesar de ainda não existir um release oficial da Perl6 há uma implementação teste, projeto iniciado por &lt;a href="http://en.wikipedia.org/wiki/Audrey_Tang"&gt;&lt;span style="font-size:100%;"&gt;Audrey Tang&lt;/span&gt;&lt;/a&gt;, chamada &lt;a href="http://www.pugscode.org/"&gt;Pugs&lt;/a&gt;, que não é nada mais que a Perl6 implementada em Haskell&lt;a href="http://en.wikipedia.org/wiki/Audrey_Tang"&gt;&lt;span style="font-size:100%;"&gt;&lt;/span&gt;&lt;/a&gt;. Eu pessoalmente não tive opurtunidade de utilizar o Pugs da maneira que gostaria, mas recomendo a todos um teste drive, afinal de contas não há mal em experimentar novas linguagens, já foi dito que um &lt;a href="http://www.pragmaticprogrammer.com/loty/"&gt;programador pragmático aprende uma nova linguagem por ano&lt;/a&gt;.

Não deveria ser novidade que depois de tanta promessa eu exclame "&lt;span style="font-weight: bold;"&gt;Perl6, onde está você?&lt;/span&gt;"

Keep Coding
Marco.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-554827217213565492?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/554827217213565492/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=554827217213565492' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/554827217213565492'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/554827217213565492'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2007/03/perl-6-onde-est-voc.html' title='Perl 6, onde está você?'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-1598881393381863026.post-5335804195400515495</id><published>2007-03-12T21:55:00.000-07:00</published><updated>2007-03-18T17:14:33.092-07:00</updated><title type='text'>Modelando o mundo</title><content type='html'>Fica aqui o início deste blog. Nada mais que YAB (Yet Another Blog) sobre Programação. Creio que os posts mostrarão os objetivos e os leitores definirão os rumos.

Keep Coding.
[]' s Marco&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/1598881393381863026-5335804195400515495?l=keepcoding.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://keepcoding.blogspot.com/feeds/5335804195400515495/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=1598881393381863026&amp;postID=5335804195400515495' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/5335804195400515495'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/1598881393381863026/posts/default/5335804195400515495'/><link rel='alternate' type='text/html' href='http://keepcoding.blogspot.com/2007/03/modelando-o-mundo.html' title='Modelando o mundo'/><author><name>Marco Valtas</name><uri>http://www.blogger.com/profile/01063443965255367262</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='21' src='http://4.bp.blogspot.com/_UFTS2NrETHg/SZDqLtr79JI/AAAAAAAAAJ4/m3XPiXg-GwQ/S220/camera_itself_small.jpg'/></author><thr:total>0</thr:total></entry></feed>
