<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;CEcCRHg9eyp7ImA9WhVVFU8.&quot;"><id>tag:blogger.com,1999:blog-7870515310189033933</id><updated>2012-05-08T21:07:45.663-03:00</updated><category term="ruby" /><category term="qcon" /><category term="gnip" /><category term="sonar" /><category term="user centered design" /><category term="design process" /><category term="scale" /><category term="javascript" /><category term="java" /><category term="patterns" /><category term="greenscript" /><category term="programming" /><category term="iso" /><category term="software design" /><category term="github" /><category term="about" /><category term="open source" /><category term="gnip4j" /><category term="conference" /><category term="object oriented programming" /><category term="blogger" /><category term="eat" /><category term="welcome" /><category term="agile" /><category term="securesocial" /><category term="plugin" /><category term="metrics" /><category term="firehose" /><category term="enterprise" /><category term="twitter" /><category term="poirot" /><category term="play" /><category term="acomerla" /><category term="OOP" /><category term="unit testing" /><category term="nosql" /><category term="quality" /><category term="zauber" /><category term="anemic domain model" /><category term="bootstrap" /><category term="playframework" /><category term="code" /><category term="framework" /><category term="architecture" /><category term="usability" /><category term="backup" /><category term="presentations" /><title>Zauber Code</title><subtitle type="html">This blog is written by &lt;a href="http://www.zaubersoftware.com"&gt;Zauber's people&lt;/a&gt;, to spread new thoughts and ideas related to the technologies we use.</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://engineering.zauberlabs.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://engineering.zauberlabs.com/" /><author><name>Andres Moratti</name><uri>http://www.blogger.com/profile/15739551346117367586</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>17</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/ZauberCode" /><feedburner:info uri="zaubercode" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;CkYNQnc6fyp7ImA9WhVSFkk.&quot;"><id>tag:blogger.com,1999:blog-7870515310189033933.post-1304496109830773313</id><published>2012-03-13T09:03:00.001-03:00</published><updated>2012-03-13T09:03:13.917-03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-03-13T09:03:13.917-03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="quality" /><category scheme="http://www.blogger.com/atom/ns#" term="enterprise" /><category scheme="http://www.blogger.com/atom/ns#" term="backup" /><category scheme="http://www.blogger.com/atom/ns#" term="github" /><title>Github @ the Enterprise: Backups</title><content type="html">&lt;br /&gt;
&lt;br class="Apple-interchange-newline" /&gt;Whenever you work on an enterprise and you have processes, quality specifications, and all that kind of stuff. One thing that will surely come up is&amp;nbsp;&lt;b&gt;backups&lt;/b&gt;. You must have backups of all your critical data. This is a good advice for everyone, not only enterprises.&lt;br /&gt;
&lt;br /&gt;
So, what happens when you start working with third party providers, such as Google Apps, Github, Pivotal Tracker or others? They will probably provide you with SLAs, that include data recovery, backups, and other security consideration. Still you are never too careful.&amp;nbsp;You never know when the next nuclear war is coming, when the internet is going down or whatever&amp;nbsp;apocalypse&amp;nbsp;scenery you want to imagine. So, we want to have backups near, reachable, in the case everything else fails.&lt;br /&gt;
&lt;br /&gt;
We have recently started using github as our main git repository for our projects: private or public. We use &amp;nbsp;the git repository, and also Wiki and Issues services.&lt;br /&gt;
&lt;br /&gt;
Getting a backup of a git repository it's easy: clone and fetch it once a day. And luckily, the wikis at github are also git repositories. Github issues is a little more complicated. You can access the github API and obtain all the issues, then you need to serialize and store all those issues. Luckily, git is a great tool to store versioned data.&lt;br /&gt;
&lt;br /&gt;
In order to solve our problem, we have built a little gem to do the hard work. It creates a directory for each project and there it stores 3 git repositories: source code, wiki, issues. For issues, it creates a json representation of each.&lt;br /&gt;
&lt;br /&gt;
You can find the source code at&amp;nbsp;&lt;a href="https://github.com/zauberlabs/backup-github"&gt;github&lt;/a&gt;&amp;nbsp;and follow the instructions&amp;nbsp;&lt;a href="https://github.com/zauberlabs/backup-github/blob/master/README.md"&gt;there&lt;/a&gt;. It's also available as a ruby gem so a: gem install backup-github would suffice.&lt;br /&gt;
&lt;br /&gt;
We hope you'll find it useful!&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7870515310189033933-1304496109830773313?l=engineering.zauberlabs.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://engineering.zauberlabs.com/feeds/1304496109830773313/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://engineering.zauberlabs.com/2012/03/github-enterprise-backups.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/1304496109830773313?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/1304496109830773313?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ZauberCode/~3/gojvy_IfTIY/github-enterprise-backups.html" title="Github @ the Enterprise: Backups" /><author><name>Mariano Cortesi</name><uri>http://www.blogger.com/profile/10586265951332907018</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://engineering.zauberlabs.com/2012/03/github-enterprise-backups.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkcGQ385eCp7ImA9WhRUGUg.&quot;"><id>tag:blogger.com,1999:blog-7870515310189033933.post-7413951801113443017</id><published>2012-01-30T14:15:00.001-03:00</published><updated>2012-01-30T16:00:22.120-03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-30T16:00:22.120-03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="acomerla" /><category scheme="http://www.blogger.com/atom/ns#" term="greenscript" /><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="eat" /><category scheme="http://www.blogger.com/atom/ns#" term="twitter" /><category scheme="http://www.blogger.com/atom/ns#" term="playframework" /><category scheme="http://www.blogger.com/atom/ns#" term="play" /><category scheme="http://www.blogger.com/atom/ns#" term="bootstrap" /><category scheme="http://www.blogger.com/atom/ns#" term="framework" /><category scheme="http://www.blogger.com/atom/ns#" term="securesocial" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><category scheme="http://www.blogger.com/atom/ns#" term="architecture" /><category scheme="http://www.blogger.com/atom/ns#" term="zauber" /><title>Play! Framework Hackaton</title><content type="html">&lt;div&gt;
&lt;table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-PTh0p82Zk9M/Tw8VDP43WmI/AAAAAAAAAMs/RyrbwnnqR80/s1600/P1120974.JPG" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" height="150" src="http://1.bp.blogspot.com/-PTh0p82Zk9M/Tw8VDP43WmI/AAAAAAAAAMs/RyrbwnnqR80/s200/P1120974.JPG" width="200" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Zauber team working&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
Zauber Software encourages employees to research new technologies in order to perform better and improve ourselves each day. So as to do this, we have Hackatons very often at Zauber in which we investigate different technologies .&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;
In one of this Hackatons, we decided to test &lt;a href="http://www.playframework.org/"&gt;Play! Framework&lt;/a&gt;. The Play framework’s goal is to ease web applications development while sticking with Java. Its idea is pretty similar to Rails's idea.&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;
We thought that the best way to test the framework would be creating an application that we'd use here at Zauber every day. In that moment, we started thinking about "A comerla!".&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;
Everyday we call a lot of restaurants in order to have our meal delivered to the office. Right now, It's very complicated for us to know how much each meal costs, which is the total of the order, who's going to call the restaurant, who's going to collect the money to pay and when the order will be placed. "A Comerla" is the solution to this and the excuse to try Play!.&lt;br /&gt;
&lt;br /&gt;
We also tried several Play! modules with this app. We used the recent developed &lt;a href="https://github.com/jaliss/securesocial"&gt;Secure Social&lt;/a&gt;&amp;nbsp;module for the Google Login. We also used &lt;a href="https://github.com/greenlaw110/greenscript"&gt;Greenscript&lt;/a&gt; module&amp;nbsp;minify the CSS and JS, to create dependencies between the JS files and to be able to use less files, among other things. In order to make the app more beautiful we used&amp;nbsp;&lt;a href="http://twitter.github.com/bootstrap/"&gt;Twitter Bootstrap&lt;/a&gt;&amp;nbsp;which makes it easy to style any web site. Furthermore,&amp;nbsp;We heard that Heroku had native support for Play! Framework, so we decided to upload it there. You may see the app deployed at&amp;nbsp;&lt;a href="http://a-comerla.herokuapp.com/"&gt;http://a-comerla.herokuapp.com/&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;
We've open sourced the application so that anyone can access it. The url for the Github repository is&amp;nbsp;&lt;a href="https://github.com/zauberlabs/a-comerla"&gt;https://github.com/zauberlabs/a-comerla&lt;/a&gt;. There, you'll find the&amp;nbsp;instructions on how to deploy this in your own business.&amp;nbsp;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;
It was a really great experience and it's an awesome framework. We'll continue to test new technologies and post them here in the future.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7870515310189033933-7413951801113443017?l=engineering.zauberlabs.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://engineering.zauberlabs.com/feeds/7413951801113443017/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://engineering.zauberlabs.com/2012/01/play-framework-hackaton.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/7413951801113443017?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/7413951801113443017?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ZauberCode/~3/b-1tiKHUKS8/play-framework-hackaton.html" title="Play! Framework Hackaton" /><author><name>Gonto</name><uri>http://www.blogger.com/profile/14561697390369408722</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-PTh0p82Zk9M/Tw8VDP43WmI/AAAAAAAAAMs/RyrbwnnqR80/s72-c/P1120974.JPG" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://engineering.zauberlabs.com/2012/01/play-framework-hackaton.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0UMQHoycSp7ImA9WhRVEU8.&quot;"><id>tag:blogger.com,1999:blog-7870515310189033933.post-4808812590107943548</id><published>2012-01-09T12:20:00.000-03:00</published><updated>2012-01-09T13:08:01.499-03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2012-01-09T13:08:01.499-03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="presentations" /><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="agile" /><category scheme="http://www.blogger.com/atom/ns#" term="conference" /><title>2011 Tech Conferences Sum Up</title><content type="html">In our eternal seek for knowledge, 2011 found us travelling to San Francisco, Portland and Sao Pablo to keep learning about technology. This is a late sum up of the conferences we attended.&lt;br /&gt;
&lt;h3&gt;



  JQueryCon (April - San Francisco)&lt;/h3&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-K6I8YfC2Lso/TwdZxXCP-FI/AAAAAAAAABU/XwL4daL9qJg/s1600/P1070254.JPG" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="150" src="http://4.bp.blogspot.com/-K6I8YfC2Lso/TwdZxXCP-FI/AAAAAAAAABU/XwL4daL9qJg/s200/P1070254.JPG" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;
A business trip turned into an educational one when we registered ourselves at the jquery conference. Two days of javascript, html5, jquery and all kind of frontend related stuff. &lt;a href="http://ar.linkedin.com/in/gbanos" target="_blank"&gt;Gabriel Baños&lt;/a&gt; and &lt;a href="http://ar.linkedin.com/in/mcortesi" target="_blank"&gt;Mariano Cortesi&lt;/a&gt; went to this one. All the slides can be found &lt;a href="http://events.jquery.org/2011/sf-bay-area/schedule/" target="_blank"&gt;here&lt;/a&gt;.&lt;br /&gt;
They are maybe a little old right now, but still, we recommend checking these talks:&lt;br /&gt;
&lt;ul class="lista"&gt;
&lt;li&gt;&lt;strong&gt;Mobile Performance&lt;/strong&gt; by Steve Souders (&lt;a href="http://stevesouders.com/docs/jqcon-20110416.pptx" target="_blank"&gt;slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Progressive Enhancement 2.0: Because the Web isn't Print&lt;/strong&gt; by Nicholas Sackas (&lt;a href="http://www.slideshare.net/nzakas/progressive-enhancement-20" target="_blank"&gt;slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;jQuery + Popcorn.js = Interactive, Immersive HTML5 Video Experiences&lt;/strong&gt; by Rick Waldron (&lt;a href="http://code.bocoup.com/popcorn.js/jqcon/" target="_blank"&gt;slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Deferreds - Putting Laziness to Work&lt;/strong&gt; by Dan Heberden (&lt;a href="http://danheberden.com/presentations/deferreds-putting-laziness-to-work/" target="_blank"&gt;slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Filling the HTML5 &amp;amp; CSS3 Gaps with Polyfills and Shims&lt;/strong&gt; by Rey Bango (&lt;a href="http://dl.dropbox.com/u/99696/jqcon/HTML5%20-%20Polyfills%20and%20Shims%20-%20v2.ppt" target="_blank"&gt;slides&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;



  OSCon'11 (July -  Portland)&lt;/h3&gt;
&lt;a href="http://3.bp.blogspot.com/-1SUunLCHiyg/TwdZ4SZzS5I/AAAAAAAAABc/3n5qcr-1e-Q/s1600/IMG_20110725_170242.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="240" src="http://3.bp.blogspot.com/-1SUunLCHiyg/TwdZ4SZzS5I/AAAAAAAAABc/3n5qcr-1e-Q/s320/IMG_20110725_170242.jpg" width="320" /&gt;&lt;/a&gt;Great technology conference organized by &lt;strong&gt;O'Reilly&lt;/strong&gt;, with a focus on Open Source. &lt;a href="http://ar.linkedin.com/in/jcodagnone" target="_blank"&gt;Juan Codagnone&lt;/a&gt;, our open source advocate, attended. All decks &amp;amp; some presentation videos are already available &lt;a href="http://www.oscon.com/oscon2011/public/schedule/proceedings" target="_blank"&gt;here&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
We recommend:&lt;br /&gt;
&lt;ul class="lista"&gt;
&lt;li&gt;&lt;strong&gt;What Would You Do With Your Own Google?&lt;/strong&gt; by Steve Yegge (&lt;a href="http://www.oscon.com/oscon2011/public/schedule/detail/20417" target="_blank"&gt;details and video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;4 Practical Uses for Domain Specific Languages&lt;/strong&gt; by Neal Ford (&lt;a href="http://www.oscon.com/oscon2011/public/schedule/detail/19930" target="_blank"&gt;details&lt;/a&gt; and &lt;a href="http://nealford.com/downloads/conferences/4_Practical_Uses_for_DSLs(Neal_Ford).pdf" target="_blank"&gt;slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Java: The Good, Bad, and Ugly Parts&lt;/strong&gt; by Josh Bloch. (&lt;a href="http://www.oscon.com/oscon2011/public/schedule/detail/21074" target="_blank"&gt;details and video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Expressiveness of Go&lt;/strong&gt; by Rob Pike (&lt;a href="http://www.oscon.com/oscon2011/public/schedule/detail/18653" target="_blank"&gt;details and slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What Every Data Programmer Needs to Know About Disks&lt;/strong&gt; by Ted Dziuba (&lt;a href="http://www.oscon.com/oscon2011/public/schedule/detail/20137" target="_blank"&gt;details and slides&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;



  QCon SP (September - Sao Pablo)&lt;/h3&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-A9l6U-NGLiI/Twr9qjKoImI/AAAAAAAAABk/OOaQniv9cCc/s1600/QCON-SP-john-marce-chris-fer.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="150" src="http://1.bp.blogspot.com/-A9l6U-NGLiI/Twr9qjKoImI/AAAAAAAAABk/OOaQniv9cCc/s200/QCON-SP-john-marce-chris-fer.jpg" width="200" /&gt;&lt;/a&gt;&lt;/div&gt;
Second edition of qcon conference in Brazil. A Zauber crowd went to this event, our representatives were &lt;a href="http://ar.linkedin.com/in/jcodagnone" target="_blank"&gt;Juan Codagnone&lt;/a&gt;, &lt;a href="http://ar.linkedin.com/in/fernandozunino" target="_blank"&gt;Fernando Zunino&lt;/a&gt;, &lt;a href="http://ar.linkedin.com/in/christiannardi" target="_blank"&gt;Christian Nardi&lt;/a&gt; and &lt;a href="http://ar.linkedin.com/in/marceloturrin" target="_blank"&gt;Marcelo Turrin&lt;/a&gt;. The conference was organized by our friends at &lt;a href="http://www.caelum.com.br/" target="_blank"&gt;Caelum&lt;/a&gt;. Most of the slides from the presentations are now available &lt;a href="http://blog.caelum.com.br/qcon-2011-como-foi-a-segunda-edicao-do-principal-evento-de-arquitetos-e-desenvolvedores-no-brasil/" target="_blank"&gt;here&lt;/a&gt;.  &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
We recommend:&lt;br /&gt;
&lt;ul class="lista"&gt;
&lt;li&gt;&lt;strong&gt;Performance Oriented Design&lt;/strong&gt; by Rodrigo Albani de Campos (&lt;a href="http://www.slideshare.net/xinu/performance-oriented-design" target="_blank"&gt;slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Divida Tecnica&lt;/strong&gt; by Alexandre Freire (&lt;a href="http://www.slideshare.net/alexandrefreire/dvida-tecnica-precisando-de-crdito-quo-fundo-entrar-e-como-evitar-que-o-cobrador-bata-na-sua-porta" target="_blank"&gt;slides&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;



  LatAm Con on Agile Methodologies (October - Buenos Aires)&lt;/h3&gt;
In our beloved city, an agile methodologies conference. &lt;a href="http://ar.linkedin.com/in/ceciliahagge/en" target="_blank"&gt;Cecilia Hagge&lt;/a&gt; went there to represent Zauber. Lots of talks and workshops by local and international agile experts. Subjects as Story Writing, Estimation and Continuous Delivery where the stars. You can find a complete &lt;a href="http://blog.code.zaubersoftware.com/2011/12/zauber-2011-latin-american-conference.html" target="_blank"&gt;post&lt;/a&gt; on this conference on our blog.&lt;br /&gt;
&lt;h3&gt;



  RubyCon AR (November - Buenos Aires)&lt;/h3&gt;
This one didn't require much travel, maybe a metro or bus ticket. Nevertheless, it was really interesting to make the first steps onto the ruby community in Argentina. Zauber has been for some time know mostly java centric, but this year we started learning new languages and platforms such as Scala, Groovy and, in this case Ruby. We hope to learn much more about it in 2012, we already have several ruby enthusiasts at the office. &lt;a href="http://ar.linkedin.com/in/jcodagnone" target="_blank"&gt;Juan Codagnone&lt;/a&gt;, &lt;a href="http://ar.linkedin.com/in/fernandozunino" target="_blank"&gt;Fernando Zunino&lt;/a&gt; and &lt;a href="http://ar.linkedin.com/in/juanpabloroyo" target="_blank"&gt;Juan Pablo Royo&lt;/a&gt; attended the conference.&lt;br /&gt;
We recommend:&lt;br /&gt;
&lt;ul class="lista"&gt;
&lt;li&gt;&lt;strong&gt;Optimizing for Happiness&lt;/strong&gt; by Tom Preston-Werner (&lt;a href="http://speakerdeck.com/u/mojombo/p/optimizing-for-happiness" target="_blank"&gt;slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Un Cuento de Tres Árboles&lt;/strong&gt; by Scott Chacon (&lt;a href="http://speakerdeck.com/u/schacon/p/un-cuento-de-tres-arboles" target="_blank"&gt;slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Who Makes the Best Asado?&lt;/strong&gt; by Aaron Patterson (&lt;a href="http://www.slideshare.net/tenderlove/rubyconf-argentina-2011" target="_blank"&gt;slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Monitoring with Syslog and Event Machine&lt;/strong&gt; by Patrick Huesler (&lt;a href="http://www.slideshare.net/wooga/monitoring-with-syslog-and-eventmachine" target="_blank"&gt;slides&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Embrace NoSQL and Eventual Consistency with Ripple&lt;/strong&gt; by Sean Cribbs (&lt;a href="http://www.slideshare.net/seancribbs/embrace-nosql-and-eventual-consistency-with-ripple" target="_blank"&gt;slides&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;



  AnDevCon II (November - San Francisco)&lt;/h3&gt;
&lt;a href="http://2.bp.blogspot.com/-PKcJSWWJlaE/TwdZScghswI/AAAAAAAAABE/buuXBBSpxF4/s1600/IMG_0438.JPG" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"&gt;&lt;img border="0" height="212" src="http://2.bp.blogspot.com/-PKcJSWWJlaE/TwdZScghswI/AAAAAAAAABE/buuXBBSpxF4/s320/IMG_0438.JPG" width="320" /&gt;&lt;/a&gt;Our first android conference. &lt;a href="http://ar.linkedin.com/in/mcortesi" target="_blank"&gt;Mariano Cortesi&lt;/a&gt; and &lt;a href="http://ar.linkedin.com/in/amoratti" target="_blank"&gt;Andrés Moratti&lt;/a&gt; went to San Francisco to represent Argentina in this event. We really enjoyed getting to know the people in the android community. Some really interesting talks took place at the conference. The presentation decks are now available &lt;a href="http://www.andevcon.com/AnDevCon_II/presentations.html" target="_blank"&gt;here&lt;/a&gt;.&lt;br /&gt;
Some talks we recommend:&lt;br /&gt;
&lt;ul class="lista"&gt;
&lt;li&gt;&lt;strong&gt;Deep Drive into Android Security&lt;/strong&gt; by Aleksandar Gargenta (&lt;a href="http://www.andevcon.com/AnDevCon_II/downloadpresentation.aspx?aid=Deep_Dive_Into_Android_Security_pdf.zip&amp;amp;sid=2" target="_blank"&gt;deck&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Pragmatic Android Layouts&lt;/strong&gt; by Kirill Grouchnikov (&lt;a href="http://www.andevcon.com/AnDevCon_II/downloadpresentation.aspx?aid=Pragmatic_Android_Layouts_pdf.zip&amp;amp;sid=2" target="_blank"&gt;deck&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RoboGuice&lt;/strong&gt; by Michael Burton (&lt;a href="http://www.andevcon.com/AndevCon_II/downloadpresentation.aspx?aid=RoboGuice__Dependency_Injection_for_Android__Part_One_pdf.zip&amp;amp;sid=2" target="_blank"&gt;deck1&lt;/a&gt; , &lt;a href="http://www.andevcon.com/AndevCon_II/downloadpresentation.aspx?aid=RoboGuice__Dependency_Injection_for_Android__Part_Two_pdf.zip&amp;amp;sid=2" target="_blank"&gt;deck2&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tunning Android Applications&lt;/strong&gt; (&lt;a href="http://www.andevcon.com/AndevCon_II/downloadpresentation.aspx?aid=Tuning_Android_Applications__Part_One_pdf.zip&amp;amp;sid=2" target="_blank"&gt;deck1&lt;/a&gt;, &lt;a href="http://www.andevcon.com/AndevCon_II/downloadpresentation.aspx?aid=Tuning_Android_Applications__Part_Two_pdf.zip&amp;amp;sid=2" target="_blank"&gt;deck2&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;



  QCon SF (November - San Franciso)&lt;/h3&gt;
&lt;a href="http://1.bp.blogspot.com/-OFHLo0kGUck/TwdZf96s6CI/AAAAAAAAABM/gTUAU0Ua8pQ/s1600/IMG_0069.JPG" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="200" src="http://1.bp.blogspot.com/-OFHLo0kGUck/TwdZf96s6CI/AAAAAAAAABM/gTUAU0Ua8pQ/s200/IMG_0069.JPG" width="150" /&gt;&lt;/a&gt;Final but not last, another big conference. Quite a classic in San Francisco, the QCon. A Conference organized by the guys at &lt;a href="http://www.infoq.com/" target="_blank"&gt;InfoQ&lt;/a&gt;, with a focus on architecture solutions, java, startups, and emerging technologies. &lt;a href="http://ar.linkedin.com/in/mcortesi" target="_blank"&gt;Mariano Cortesi&lt;/a&gt; and &lt;a href="http://ar.linkedin.com/in/amoratti" target="_blank"&gt;Andrés Moratti&lt;/a&gt; represented Zauber at this conference. Videos for all the talks will appear an &lt;a href="http://www.infoq.com/" target="_blank"&gt;InfoQ&lt;/a&gt; along the next months, you can check the schedule &lt;a href="http://qconsf.com/sf2011/video/" target="_blank"&gt;here&lt;/a&gt;. If you can't wait, you can check the slides for all presentation at the &lt;a href="http://qconsf.com/sf2011/schedule/wednesday.jsp" target="_blank"&gt;qconsf site&lt;/a&gt;. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Some talks we recommend:&lt;br /&gt;
&lt;ul class="lista"&gt;
&lt;li&gt;&lt;a href="http://qconsf.com/sf2011/presentation/Software+Naturalism+-+Embracing+the+Real+Behind+the+Ideal" target="_blank"&gt;Software Naturalism - Embracing the Real Behind the Ideal&lt;/a&gt; by Michael Feathers (&lt;a href="http://qconsf.com/dl/qcon-sanfran-2011/slides/MichaelFeathers_SoftwareNaturalismEmbracingTheRealBehindTheIdeal.pdf" target="_blank"&gt;deck&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://qconsf.com/sf2011/presentation/JVM+performance+optimizations+at+Twitter%27s+scale" target="_blank"&gt;JVM Performance optimizations at Twitter's scale&lt;/a&gt; by Attila Szegedi (&lt;a href="http://qconsf.com/dl/qcon-sanfran-2011/slides/AttilaSzegedi_JVMPerformanceOptimizationsAtTwittersScale.pdf" target="_blank"&gt;deck&lt;/a&gt; and &lt;a href="http://www.infoq.com/presentations/JVM-Performance-Tuning-twitter" target="_blank"&gt;video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://qconsf.com/sf2011/presentation/Product+Engineering" target="_blank"&gt;Product Engineering&lt;/a&gt; by Mike Lee (&lt;a href="http://qconsf.com/dl/qcon-sanfran-2011/slides/MikeLee_ProductEngineering.pdf" target="_blank"&gt;deck&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://qconsf.com/sf2011/presentation/What+the+Heck+is+an+API+Platform+Anyway%3F" target="_blank"&gt;What the Heck is an API Platform Anyway?&lt;/a&gt; by Gregory Brail (&lt;a href="http://qconsf.com/dl/qcon-sanfran-2011/slides/GregoryBrail_WhatTheHeckIsAnAPIPlatformAnyway.pdf" target="_blank"&gt;deck&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://qconsf.com/sf2011/presentation/Building+a+Great+Web+API" target="_blank"&gt;Building a Great Web API&lt;/a&gt; by Evan Cooke (&lt;a href="http://qconsf.com/dl/qcon-sanfran-2011/slides/EvanCooke_BuildingAGreatWebAPI.pdf" target="_blank"&gt;deck&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://qconsf.com/sf2011/presentation/Dart+in+Depth" target="_blank"&gt;Dart in Depth&lt;/a&gt; by Gilad Bracha (&lt;a href="http://qconsf.com/dl/qcon-sanfran-2011/slides/GiladBracha_DartInDepth.pdf" target="_blank"&gt;deck&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://qconsf.com/sf2011/presentation/Objects%2C+Anomalies%2C+and+Actors%3A+The+Next+Revolution" target="_blank"&gt;Objects, Anomalies, and Actors: The Next Revolution&lt;/a&gt; by Steve Vinosky (&lt;a href="http://qconsf.com/dl/qcon-sanfran-2011/slides/SteveVinoski_ObjectsAnomaliesAndActorsTheNextRevolution.pdf" target="_blank"&gt;deck&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://qconsf.com/sf2011/presentation/Things+I+Wish+I%27d+Known" target="_blank"&gt;Things I Wish I'd know&lt;/a&gt; by Rod Johnson (&lt;a href="http://qconsf.com/dl/qcon-sanfran-2011/slides/RodJohnson_ThingsIWishIdKnown.pdf" target="_blank"&gt;deck&lt;/a&gt; and &lt;a href="http://www.infoq.com/presentations/Things-I-Wish-I-d-Known" target="_blank"&gt;video&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://qconsf.com/sf2011/presentation/Techniques+for+Scaling+the+Netflix+API+in+the+Cloud" target="_blank"&gt;Techniques for Scaling the Netflix API in the Cloud&lt;/a&gt; by Daniel Jacobson (&lt;a href="http://qconsf.com/dl/qcon-sanfran-2011/slides/DanielJacobson_TechniquesForScalingTheNetflixAPIInTheCloud.pdf" target="_blank"&gt;deck&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;br /&gt;
That's all for 2011! We can add to the mix &lt;a href="http://www.barcamp.com.ar/"&gt;Barcamp&lt;/a&gt;, which we sponsored in BA, and then several people in Zauber went to Rosario and Parana to participate of the other Barcamps; also the Google Dev Day here en Buenos Aires.&lt;br /&gt;
&lt;br /&gt;
Now 2012 has started and we are already planning which conferences we will attend! So if you have been to these conferences and want to add other talks that we missed, please comment!&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7870515310189033933-4808812590107943548?l=engineering.zauberlabs.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://engineering.zauberlabs.com/feeds/4808812590107943548/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://engineering.zauberlabs.com/2012/01/2011-tech-conferences-sum-up.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/4808812590107943548?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/4808812590107943548?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ZauberCode/~3/DiYO1DnzoAc/2011-tech-conferences-sum-up.html" title="2011 Tech Conferences Sum Up" /><author><name>Mariano Cortesi</name><uri>http://www.blogger.com/profile/10586265951332907018</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-K6I8YfC2Lso/TwdZxXCP-FI/AAAAAAAAABU/XwL4daL9qJg/s72-c/P1070254.JPG" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://engineering.zauberlabs.com/2012/01/2011-tech-conferences-sum-up.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0UFRHY_fyp7ImA9WhRQGUs.&quot;"><id>tag:blogger.com,1999:blog-7870515310189033933.post-3615437908468212697</id><published>2011-12-15T12:07:00.006-03:00</published><updated>2011-12-15T13:06:55.847-03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-12-15T13:06:55.847-03:00</app:edited><title>Some thoughts on Agile Development</title><content type="html">&lt;p&gt;Last October we attended to the &lt;a href="http://agiles2011.agiles.org/en"&gt;4th Latin American Conference on Agile Methodologies&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This event involved over more than 20 talks and workshops per day delivered by local, regional and international experts.&lt;/p&gt;

&lt;p&gt;Here I focus on the main subjects treated and give you some tips you should not miss. Hope you find them interesting and useful!&lt;/p&gt;

&lt;h3&gt;Story Writing&lt;/h3&gt;

&lt;p&gt;Sessions in general were focused on determining a better product design figuring out the &lt;em&gt;“why and who”&lt;/em&gt; is interested in a particular story.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://twitter.com/#%21/jeffpatton"&gt;Jeff Patton&lt;/a&gt;, who was in charge of the first keynote in the event, explained a technique used behind this concept: &lt;a href="http://agileproductdesign.com/"&gt;Story Mapping&lt;/a&gt;. Fortunately, and besides the amount of people who wanted to participate, we were able to attend to his workshop and gain some practical experience.&lt;/p&gt;

&lt;img alt="" id="BLOGGER_PHOTO_ID_5681272207349762306" src="http://3.bp.blogspot.com/-kLeYj6Yrx88/Ttfu-M9hyQI/AAAAAAAAAAo/M9Md0HQNcuk/s200/photo.JPG" style="cursor: pointer; float: right; height: 150px; margin-bottom: 10px; margin-left: 10px; margin-right: 0px; margin-top: 0px; width: 200px;" border="0" /&gt;

&lt;p&gt;Jeff's vision about Scrum and Agile Methodologies in general is that they tend to enforce “output” during a project, i.e. deliver the biggest amount of functionality in a time-boxed period and finish stories already predicted in the backlog for that sprint. Nevertheless, he points out that's not the mean of a successful project. The goal is to satisfy the client (or the co-worker as he wants to call him/her) resolving the first needs that led him/her to actually desiring the product. The only way to accomplish this is by focusing on the project's ‘outcome’. In order to build the best product according to clients' expectations, it's necessary to work on a good release plan, understand the business and break the client role into the different stakeholders that will be taking part in the product.&lt;/p&gt;

&lt;img alt="" id="BLOGGER_PHOTO_ID_5681270673487362562" src="http://3.bp.blogspot.com/-2ndiPG0xVFc/Ttftk64O-gI/AAAAAAAAAAc/ZYDiiXxY2yw/s320/photo2.JPG" style="cursor: pointer; float: left; height: 100px; margin: 0px 10px 10px 0px; width: 133px;" border="0" /&gt;

&lt;p&gt; Story Mapping consists in building a business flow, identify more detailed steps in the flow and establish a hierarchy between the more global steps which are going to become stories and their detailed tasks or sub-stories. Finally, the goal is to assign sub-stories to each release, mapping them with each stakeholder profile for whom the release is planned. Jeff emphasized on how important is the visual, self-organized and cooperative way of working with this technique, especially when human understanding is involved.&lt;/p&gt;

&lt;img alt="" id="BLOGGER_PHOTO_ID_5681273118608755426" src="http://4.bp.blogspot.com/-hK6V0LOkBU0/TtfvzPqmiuI/AAAAAAAAABA/2VtPJDqJhyc/s200/photo3.JPG" style="cursor: pointer; float: right; height: 150px; margin-bottom: 10px; margin-left: 10px; margin-right: 0px; margin-top: 0px; width: 200px;" border="0" /&gt;

&lt;p&gt;In my opinion, you should apply this technique in case you have the opportunity to decide on the product design. This happens in every software factory but outsourcing is not as far as you may think. If you have the chance, it's only about taking the initiative to participate and making the difference.&lt;/p&gt;

&lt;p&gt;Regarding Zauber, it's good to confirm that we follow the right approach, getting involved together with our clients in product design and definition, acting not only as a development team, but also as product managers.&lt;/p&gt;

&lt;h3&gt;Estimation&lt;/h3&gt;

&lt;p&gt;There were some workshops introducing well known estimation techniques such as &lt;a href="http://en.wikipedia.org/wiki/Program_Evaluation_and_Review_Technique" title="Program Evaluation and Review Technique, Wikipedia article"&gt;PERT&lt;/a&gt; applied effectively at enterprise level. Beyond the method itself, it is actually a good practice to think about 3 possible estimations for each story: the optimistic, the pessimistic and the realistic one. This is hard to incorporate but it would help a lot not only to achieve more precise estimations reducing the chance of sub and over estimation but also to identify the very true risks of the story itself.&lt;/p&gt;

&lt;p&gt;On the other hand, there were discouraging talks about estimation. These theories are based on the new mixed methodology &lt;a href="http://leansoftwareengineering.com/ksse/scrum-ban/"&gt;Scrum-ban&lt;/a&gt; which is the combination of both Scrum and Kanban. The new concept, following the story-points idea, is to estimate in stories' complexity or size and build a sprint according to the already known velocity team and the number of stories that can be delivered, without considering the usual hourly-men or ideal days unit. Even though this is a good approximation for reducing projects deviation and leading to a more comfortable work environment, I can't still figure out a way to apply it because clients are not yet prepared for this vision. People in general are used to work with time as their unit measure and it takes a long time to change from one paradigm to another. However, this is a nice theory to follow up and keep in mind.&lt;/p&gt;

&lt;h3&gt;Continuous Delivery&lt;/h3&gt;

&lt;p&gt;The talk exposed a truly typical problem concerning a complex and distributed architecture with frequently deploys. Features were easy to develop but integration tests and deployment consumed proportionally a lot more time leading to client’s upset and late delivery of functionality.&lt;/p&gt;

&lt;p&gt;The team in charge decided to carry out an automatic system for test and deployment. It took them 1 month development and let them reduce their 10hs delivery time to some remarkable 20 minutes. During the talk, they explained the most important features to take into account when using continuous delivery and finally showed a demo.&lt;/p&gt;

&lt;p&gt;The technology used for the project was: Jenkins + &lt;a href="https://wiki.jenkins-ci.org/display/JENKINS/Promoted+Builds+Plugin"&gt;Plugin Promoted&lt;/a&gt; + Amazon. They casually mentioned they hadn't had good results with Cargo (another known plugin for Jenkins).&lt;/p&gt;

&lt;p&gt;There was also an introduction to &lt;a href="http://en.wikipedia.org/wiki/Platform_as_a_service"&gt;PAAS&lt;/a&gt; (Platform as a service), in particular they showed a little bit of &lt;a href="http://www.heroku.com/"&gt;Heroku&lt;/a&gt; and its main differences with Amazon.&lt;/p&gt;

&lt;p&gt;Our advice is that, if you are about to develop or you're already maintaining a big project, you should adopt continuous delivery and choose the most suitable infrastructure between all the alternatives the market brings, taking into account your non-functional requirements.&lt;/p&gt;

&lt;p&gt;I hope you've found this review interesting. If you want to know more about how we build software in an Agile way at Zauber, you can check &lt;a href="http://www.zaubersoftware.com/en/process/"&gt;Agile Software Development&lt;/a&gt;&lt;/p&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7870515310189033933-3615437908468212697?l=engineering.zauberlabs.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://engineering.zauberlabs.com/feeds/3615437908468212697/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://engineering.zauberlabs.com/2011/12/zauber-2011-latin-american-conference.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/3615437908468212697?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/3615437908468212697?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ZauberCode/~3/8wdbrmmpXRQ/zauber-2011-latin-american-conference.html" title="Some thoughts on Agile Development" /><author><name>Cecilia Hagge</name><uri>http://www.blogger.com/profile/17048945399760780664</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/-kLeYj6Yrx88/Ttfu-M9hyQI/AAAAAAAAAAo/M9Md0HQNcuk/s72-c/photo.JPG" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://engineering.zauberlabs.com/2011/12/zauber-2011-latin-american-conference.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0QCQnw9cCp7ImA9WhZVGEs.&quot;"><id>tag:blogger.com,1999:blog-7870515310189033933.post-4605394115276098950</id><published>2011-05-30T11:10:00.011-03:00</published><updated>2011-05-31T16:16:03.268-03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-05-31T16:16:03.268-03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="open source" /><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="gnip" /><category scheme="http://www.blogger.com/atom/ns#" term="firehose" /><category scheme="http://www.blogger.com/atom/ns#" term="twitter" /><category scheme="http://www.blogger.com/atom/ns#" term="gnip4j" /><title>Gnip4j: our open source Java library for Gnip</title><content type="html">&lt;p&gt;
We are happy to announce the public release of &lt;a href="http://code.zaubersoftware.com/gnip4j/"&gt;Gnip4j&lt;/a&gt;, a new Open Source project developed at &lt;a href="http://www.zaubersoftware.com"&gt;Zauber&lt;/a&gt; and released under the ASFL 2.0.
&lt;/p&gt;
&lt;p&gt;
&lt;a href="http://code.zaubersoftware.com/gnip4j/"&gt;Gnip4j&lt;/a&gt; is a Java library to access &lt;a href="http://gnip.com/twitter"&gt;Twitter premium feeds&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
For more than a year, we've been developing real-time interactive data visualizations, based on social media, gathered mainly from Twitter. We have developed projects for the &lt;a href="http://blog.zaubersoftware.com/2010/07/world-cup-social-project-for-coca-cola.html"&gt;World Cup&lt;/a&gt;, the &lt;a href="http://blog.zaubersoftware.com/2010/10/twitter-visualization-for-brazilian.html"&gt;Brazilian Elections&lt;/a&gt;, to track the &lt;a href="http://blogs.aljazeera.net/twitter-dashboard"&gt;uprisings in Middle East&lt;/a&gt; and more. So far, we always used Twitter Streaming API with granted access to the Gardenhose. 
&lt;/p&gt;
&lt;p&gt;
But the requirements of new projects and our ambition to create even more complex and accurate visualizations and real-time dashboards, made us start considering new data feeds. That's why we are now working with &lt;a href="http://code.zaubersoftware.com/gnip4j/"&gt;Gnip4j&lt;/a&gt; and using their premium feeds to take advantage of Twitter firehose to process 100% of tweets. 
&lt;/p&gt;
&lt;p&gt;
Our &lt;a href="http://code.zaubersoftware.com/gnip4j/"&gt;Gnip4j&lt;/a&gt; library is the result of our work using Gnip services and we are happy to contribute it as Open Source software, looking forward that other developers can use it and contribute back.
&lt;/p&gt;
&lt;p&gt;
You can get involved by following the instructions &lt;a href="http://code.zaubersoftware.com/gnip4j/"&gt;here&lt;/a&gt;.
&lt;/p&gt;
&lt;p&gt;
Please give us your feedback and feel free to contribute back.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7870515310189033933-4605394115276098950?l=engineering.zauberlabs.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://engineering.zauberlabs.com/feeds/4605394115276098950/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://engineering.zauberlabs.com/2011/05/gnip4j-our-open-source-java-library-for.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/4605394115276098950?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/4605394115276098950?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ZauberCode/~3/JuV5g8e0-Fs/gnip4j-our-open-source-java-library-for.html" title="Gnip4j: our open source Java library for Gnip" /><author><name>Gabriel Baños</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="24" height="32" src="http://2.bp.blogspot.com/_Rz9xbUK0X8I/SX4khr7jmoI/AAAAAAAAAAM/LKhAYEWfxkQ/S220/gabi.jpg" /></author><thr:total>0</thr:total><feedburner:origLink>http://engineering.zauberlabs.com/2011/05/gnip4j-our-open-source-java-library-for.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUMFRXs6cCp7ImA9Wx9TF0w.&quot;"><id>tag:blogger.com,1999:blog-7870515310189033933.post-4138539037168213649</id><published>2010-11-25T16:27:00.002-03:00</published><updated>2010-11-25T16:30:14.518-03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-11-25T16:30:14.518-03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="usability" /><category scheme="http://www.blogger.com/atom/ns#" term="design process" /><category scheme="http://www.blogger.com/atom/ns#" term="user centered design" /><title>Getting started with Usability and User Centered Design - Part II</title><content type="html">&lt;p&gt;&lt;a href="http://blog.code.zaubersoftware.com/2010/07/getting-started-with-usability-and-user.html"&gt;Some time ago&lt;/a&gt; we detailed the first steps to start including User-Centered Design in your software development process, presenting to you the most easy-to-integrate techniques, but there is more than that if you want to get the best out of User-Centered Design&lt;/p&gt;

&lt;h3&gt;User research&lt;/h3&gt;
&lt;p&gt;Doing user research is the core of User-Centered design because it's the best way to understand the user goals, needs and context. It's hard to integrate it into a company's design &amp; development process, but once you get started paying attention to your application's users, guidelines are not enough: you need to know better your audience, and the best way to do it is through a research process.&lt;/p&gt;
&lt;dl&gt;
   &lt;dt&gt;Ethnographic Interviews:&lt;/dt&gt;
   &lt;dd&gt;explore your user's world from an anthropologic point of view. Make interviews registering the context around them, so you can learn about their daily life, how they use their workspace, their problems and needs, how they think about technology, how they use similar and related products. It's very enlightening to learn about real problems of your potential users, once you have do it, you'll probably start thinking in possible solutions and design directions. But first you need to systematize what you've learned&lt;/dd&gt;
   &lt;dt&gt;Personas construction:&lt;/dt&gt;
   &lt;dd&gt;summarizing what you've learned in &lt;a href="http://www.zaubersoftware.com/en/services/design/#personas"&gt;Personas &lt;/a&gt; will help you to communicate easier your findings about your potential users and their different needs and goals. It's a design tool: all the team can benefit from having fictional users extracted from the interviews. With Personas, people working on the project start talking about well-known characters instead of talking about "the user" without knowing who he is.&lt;/dd&gt;
   &lt;dt&gt;Scenarios building:&lt;/dt&gt; 
   &lt;dd&gt;to build an escenario is to put your Personas in action, narrating the situations in which they will use your product. It's a creative task that helps designers to see the process from the user's perspective (with their goals, needs, and context) and to improve it as well. It also helps them to see the big picture and to be focused in the most relevant tasks. This tasks could also be split into user stories to integrate this phase with the &lt;a href="http://www.zaubersoftware.com/en/process/"&gt;scrum process&lt;/a&gt;&lt;/dd&gt;
   &lt;dt&gt;Requirements and Use Cases:&lt;/dt&gt;
   &lt;dd&gt;Based on the scenarios you can start extracting the most important requirements and building Use Cases. The main difference with other processes is that you have a clear path to follow based on your research.&lt;/dd&gt;
   &lt;dt&gt;Usability tests:&lt;/dt&gt;
   &lt;dd&gt;once you've designed some screens,  you can conduct this kind of tests by asking some potential users to follow a set of predefined tasks in your application or site. You''ll be able to find problems and concerns they might have by observing them while they execute the tasks you asked for. This technique helps you to known better how real users understand your site and what sections of your product needs to be improved or changed.
   &lt;dt&gt;Card Sorting:&lt;/dt&gt;
   &lt;dd&gt;This technique can be useful to give an structure to your site that reflects the way your potential users think about it. You simply need to ask them to organize a bunch of labeled post-its, in a way that makes sense to them. Then you can compare the different answers to find coincidences. &lt;/dd&gt;
   &lt;dt&gt;A/B tests:&lt;/dt&gt;
   &lt;dd&gt;A/B tests are useful to optimize a section of your application by testing two or more different design options against a large number of users. Then you can know which one works better by analyzing conversion statistics.&lt;/dd&gt;
&lt;/dl&gt;
&lt;h3&gt;Recommended reading&lt;/h3&gt;
&lt;p&gt;After this short introduction to User Centered Design, you can keep on learning by reading some of the most important books on this subject&lt;/p&gt;
&lt;ul class="lista"&gt;
   &lt;li&gt;&lt;em&gt;Design of Everyday Things&lt;/em&gt;, by Donald Norman, is about the philosophy and basic rules of Usability. Actually, Don Norman isn't a designer, he is a psychologist, and the first edition of this book was called "Psychology of Everyday Things" [&lt;a href="http://www.amazon.com/Design-Everyday-Things-Donald-Norman/dp/0465067107"&gt;Amazon&lt;/a&gt;]&lt;/li&gt;
   &lt;li&gt;&lt;em&gt;Don't Make Me Think&lt;/em&gt;, by Steve Krug. Althought it's a bit old, this book explains in a very practical and easy way how to design a site thinking of users. [&lt;a href="http://www.amazon.com/Dont-Make-Me-Think-Usability/dp/0321344758"&gt;Amazon&lt;/a&gt;]&lt;/li&gt;
   &lt;li&gt;&lt;em&gt;About Face 3&lt;/em&gt;, by Alan Cooper, is one of the most detailed books about the whole process of designing an usable product. [&lt;a href="http://www.amazon.com/About-Face-Essentials-Interaction-Design/dp/0470084111/"&gt;Amazon&lt;/a&gt;]&lt;/li&gt;
   &lt;li&gt;&lt;em&gt;Emotional Design&lt;/em&gt;, by Don Norman, is a book about how emotions and aesthetics can be part of Usability that is a very rational approach to design. [&lt;a href="http://www.amazon.com/Emotional-Design-Love-Everyday-Things/dp/0465051367/"&gt;Amazon&lt;/a&gt;]&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Staying in touch with the community&lt;/h3&gt;
&lt;p&gt;It's better if you have someone who can guide you through this process, but... how to know specialists in this area? &lt;a href="http://www.ixda.org/"&gt;IxDA&lt;/a&gt; is a global community of interaction designers who take care of usability (among other very related subjects like information architecture, interaction design, user experience and accesibility). It has a lot of local branches that organize events and can help you through your process. We are assisting to events organized by&lt;a href="http://www.ixda.com.ar/"&gt; IxDA Buenos Aires&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;
If you want to know more about this subject, you could also visit our &lt;a href="http://www.zaubersoftware.com/en/services/design/"&gt;User Centered Design section&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7870515310189033933-4138539037168213649?l=engineering.zauberlabs.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://engineering.zauberlabs.com/feeds/4138539037168213649/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://engineering.zauberlabs.com/2010/11/getting-started-with-usability-and-user.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/4138539037168213649?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/4138539037168213649?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ZauberCode/~3/gXNq4ugU8E4/getting-started-with-usability-and-user.html" title="Getting started with Usability and User Centered Design - Part II" /><author><name>Damian Calderon</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="31" src="http://4.bp.blogspot.com/_toYKT_ESrww/SX4g1RhqORI/AAAAAAAAAAc/9sz9UDtOnUY/S220/damian_mini.png" /></author><thr:total>0</thr:total><feedburner:origLink>http://engineering.zauberlabs.com/2010/11/getting-started-with-usability-and-user.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0AAQXw7cCp7ImA9Wx9TEUU.&quot;"><id>tag:blogger.com,1999:blog-7870515310189033933.post-2685421413065687702</id><published>2010-11-19T09:00:00.008-03:00</published><updated>2010-11-19T12:49:00.208-03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-11-19T12:49:00.208-03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="conference" /><category scheme="http://www.blogger.com/atom/ns#" term="patterns" /><category scheme="http://www.blogger.com/atom/ns#" term="nosql" /><category scheme="http://www.blogger.com/atom/ns#" term="architecture" /><category scheme="http://www.blogger.com/atom/ns#" term="scale" /><category scheme="http://www.blogger.com/atom/ns#" term="qcon" /><title>Zauber @ QCon San Francisco 2010</title><content type="html">&lt;p&gt;This month we participated in the 4th annual &lt;a href="http://qconsf.com/"&gt;QCon San Francisco&lt;/a&gt;. This conference is held by &lt;a href="http://www.infoq.com/"&gt;InfoQ&lt;/a&gt; in several cities all over the world, and the SF edition was a meeting point for over 80 speakers and 500 attendees. It included several tracks related to software architectures, agile software development, IT operations, NoSQL, applications security and more. &lt;/p&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_H1TYkiIk3Os/TOXNb8sArsI/AAAAAAAAAVo/IQBuEhBSamE/s1600/qcon.jpg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 200px; height: 196px;" src="http://3.bp.blogspot.com/_H1TYkiIk3Os/TOXNb8sArsI/AAAAAAAAAVo/IQBuEhBSamE/s200/qcon.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5541060796580146882" /&gt;&lt;/a&gt;
&lt;p&gt;It was really hard to choose between 5 different tracks at the same time, mostly because they were all interesting.&lt;/p&gt;


&lt;p&gt;You could find people from all over the world, most of them highly technical developers who wanted to learn state of the art techniques. It was amazing to find out about architectural solutions from Facebook, Twitter, Netflix, eBay to keep their systems up serving millions and millions of users.&lt;/p&gt;
&lt;p&gt;I chose most of the software architectures and NoSQL talks and I wanted to share some highlights about them:&lt;/p&gt;

&lt;ul class="lista"&gt;&lt;li&gt;Twitter has many problems scaling data, so they went through a series or incremental iterations until they found a &lt;a href="http://qconsf.com/sf2010/file?path=/qcon-sanfran-2010/slides/NickKallen_DataArchitectureAtTwitterScale.pdf"&gt;good solution&lt;/a&gt; using MySQL with partition + replication + indexes + memcache. Also they are currently &lt;a href="http://nosql.mypopescu.com/post/407159447/cassandra-twitter-an-interview-with-ryan-king"&gt;using NoSQL&lt;/a&gt; for data mining, geo indexing and real time analytics. As Ryan King suggested in his talk, there is no database that fills all the gaps, because they tried to use NoSQL to store tweets and they didn't succeed. Ryan also talked about some ad hoc frameworks developed by twitter, like &lt;a href="http://engineering.twitter.com/2010/04/introducing-gizzard-framework-for.html"&gt;Gizzard&lt;/a&gt;, Haplo, Rainbird, Cuckoo and &lt;a href="http://engineering.twitter.com/2010/06/announcing-snowflake.html"&gt;Snowflake&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Facebook showed how they scale their social graph using MySQL and PHP. Their secret is using MySQL not as a RDBMs but as a schema-less key/value datastore, and compiling PHP to C++ (yes!) for better performance.&lt;/li&gt;&lt;li&gt;eBay has several systems and thousands of machines running their business. Randy Shoup&lt;a href="http://qconsf.com/sf2010/file?path=/qcon-sanfran-2010/slides/RandyShoup_MoreBestPracticesForLargeScaleWebSitesLessonsFromEBay.pdf"&gt; explained many good practices&lt;/a&gt; for addressing problems at that scale like partition everything, asynchronous connections everywhere and incremental system change.&lt;/li&gt;&lt;li&gt;Netflix is running almost all their infrastructure in the cloud. That was a big shift in their paradigm because they moved from a company that rents DVDs to a company that streams content. &lt;a href="http://qconsf.com/sf2010/file?path=/qcon-sanfran-2010/slides/AdrianCockcroft_RunningNetflixInTheCloud.pdf"&gt;Adrian Cockcroft said&lt;/a&gt; they are working close to Amazon because they are pushing AWS to its limits!. He also suggested several "cloud patterns" like no sticky session, no chatty protocols (use Apache Avro) and NoSQL.&lt;/li&gt;&lt;li&gt;Jason McHugh from Amazon S3 demoed how they can &lt;a href="http://qconsf.com/sf2010/file?path=/qcon-sanfran-2010/slides/JasonMcHugh_AmazonS3ArchitectingForResiliencyInTheFaceOfMassiveLoad.pdf"&gt;handle 30000 request per second&lt;/a&gt; on S3. His solution includes distributed hash tables and two level caches, one in webservers and the other over storage, both communicated using a protocol that allows high traffic distribution in order to avoid hot spots. All these solutions were described as resiliency techniques.&lt;/li&gt;&lt;li&gt;Ryan Dahl, node.js developer, gave a great talk about &lt;a href="http://qconsf.com/sf2010/file?path=/qcon-sanfran-2010/slides/RyanDahl_NodeJsAsynchronousPurityLeadsToFasterDevelopment.pdf"&gt;server performance and asynchronous purity&lt;/a&gt; to build scalable network programs.&lt;/li&gt;&lt;li&gt;Erik Meijer blow up our minds demonstrating that SQL is equivalent to NoSQL. This was the first time he talked about this out of his lab, so it was an inspiring moment.
&lt;br /&gt;&lt;br /&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_H1TYkiIk3Os/TOaM-7ovujI/AAAAAAAAAWA/dsA0FFdvH2w/s1600/nosql-sql.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px;" src="http://3.bp.blogspot.com/_H1TYkiIk3Os/TOaM-7ovujI/AAAAAAAAAWA/dsA0FFdvH2w/s320/nosql-sql.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5541271404314343986" /&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;LMAX described how they can &lt;a href="http://qconsf.com/sf2010/file?path=/qcon-sanfran-2010/slides/MartinThompson_and_MichaelBarker_LMAXHowToDoOver100KConcurrentTransactionsPerSecondAtLessThan1msLatency.pdf"&gt;handle over 100k concurrent transactions&lt;/a&gt; per second with less than 1ms latency. They even optimized code so it can be stored efficiently in CPU caches, and worked with ring buffers for processing huge amounts of transactions. Other techniques included reducing I/O, removing concerns from code and designing a perfect object model.&lt;/li&gt;&lt;li&gt;Ron Bodkin from Quancast described how they can &lt;a href="http://qconsf.com/sf2010/file?path=/qcon-sanfran-2010/slides/RonBodkin_LargeScaleMapreduceDataProcessingAtQuantcast.pdf"&gt;process 300 billion events per month&lt;/a&gt; using Hadoop + Map/Reduce. After that they do data mining with Greenplum. Also he gave a good piece of advice: "start with small datasets so you can understand what is going on, then scale"&lt;/li&gt;&lt;li&gt;Ralph Johnson, one of the famous "&lt;a href="http://en.wikipedia.org/wiki/Design_Patterns_(book)"&gt;Gang of Four&lt;/a&gt;", gave a talk about &lt;a href="http://qconsf.com/sf2010/file?path=/qcon-sanfran-2010/slides/RalphJohnson_ParallelProgrammingPatternsDataParallelism.pdf"&gt;Parallel Programming Patterns&lt;/a&gt;. He talked about Fork-Join (hopefully deterministic, no I/O, no locks), Data Parallelism (deterministic, i.e. Map/Reduce) and Actors (not deterministic, good for I/O)&lt;/li&gt;&lt;li&gt;Java 8 is going to include &lt;a href="http://openjdk.java.net/projects/lambda/"&gt;project lambda&lt;/a&gt;, so Alex Buckley from Oracle explained how Java is going to take advantage of multiple cores.&lt;/li&gt;&lt;/ul&gt;

&lt;br/&gt;
&lt;p&gt;Also there were four keynotes:&lt;/p&gt;
&lt;ul class="lista"&gt;
&lt;li&gt;Patrick Copeland (Google Director of Engineering): this keynote was really inspiring. Patrick talked about the &lt;a href="http://qconsf.com/sf2010/file?path=/qcon-sanfran-2010/slides/PatrickCopeland_OpeningKeynoteInnovationAtGoogle.pdf"&gt;innovation culture at Google&lt;/a&gt; and how they develop products. All his ideas are expressed in the &lt;a href="http://www.pretotyping.org/"&gt;Pretotyping Manifesto&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Daniel_Henry_Holmes_Ingalls,_Jr."&gt;Dan Ingalls&lt;/a&gt; (Principal Architect of Smalltalk): Dan taught us how you can do incredible things and have fun developing software. It was a pleasure to see one of the founders of software as we know it.&lt;/li&gt;&lt;li&gt;Randy Shoup (eBay Chief Engineer): in this keynote we learnt best practices on &lt;a href="http://qconsf.com/sf2010/file?path=/qcon-sanfran-2010/slides/RandyShoup_BeingElasticEvolvingProgrammingForTheCloud.pdf"&gt;being elastic in the cloud&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Martin Fowler (Chief Scientist at ThoughtWorks): He started talking about his most recent research: &lt;a href="http://www.martinfowler.com/bliki/DomainSpecificLanguage.html"&gt;DSL&lt;/a&gt;. After that he talked about two of his most well known patterns: &lt;a href="http://www.martinfowler.com/articles/continuousIntegration.html"&gt;Continuous Integration&lt;/a&gt; and &lt;a href="http://martinfowler.com/eaaDev/EventSourcing.html"&gt;Event Sourcing&lt;/a&gt;. Martin is a great speaker and engaged the audience with his huge experience and anecdotes.
&lt;/li&gt;&lt;/ul&gt;

&lt;br/&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_H1TYkiIk3Os/TOaNcOSe7DI/AAAAAAAAAWI/5cR1DPiLtyU/s1600/photo%2B4.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 555px;" src="http://3.bp.blogspot.com/_H1TYkiIk3Os/TOaNcOSe7DI/AAAAAAAAAWI/5cR1DPiLtyU/s640/photo%2B4.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5541271907537447986" /&gt;&lt;/a&gt;

&lt;br/&gt;
&lt;p&gt;As a conclusion, I found some recurrent themes in many talks:&lt;/p&gt;
&lt;ul class="lista"&gt;&lt;li&gt;&lt;b&gt;Using the right tool for the job&lt;/b&gt;: at high scale projects you have to try and try different solutions, keep your mind open and choose the right tool. Here is where engineering shines and you can find state of the art solutions.&lt;/li&gt;&lt;li&gt;&lt;b&gt;Eventual consistency&lt;/b&gt;: almost in every talk I heard that phrase. New data models are arising and consumer are multiplying everywhere, thus the web is pushing databases to its limits and here is the price we have to pay. I predict exciting times ahead related to NoSQL vs. SQL and distributed data processing.&lt;/li&gt;&lt;/ul&gt;

&lt;p&gt;Being part of QCon SF 2010 was an incredible experience. Congratulations to InfoQ and QCon for this great event. Zauber will be there again next year for sure!&lt;/p&gt;

&lt;br/&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_H1TYkiIk3Os/TOaMBKaINRI/AAAAAAAAAV4/I7nS839arWM/s1600/photo.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 555px;" src="http://1.bp.blogspot.com/_H1TYkiIk3Os/TOaMBKaINRI/AAAAAAAAAV4/I7nS839arWM/s640/photo.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5541270343127676178" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7870515310189033933-2685421413065687702?l=engineering.zauberlabs.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://engineering.zauberlabs.com/feeds/2685421413065687702/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://engineering.zauberlabs.com/2010/11/zauber-qcon-san-francisco-2010.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/2685421413065687702?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/2685421413065687702?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ZauberCode/~3/UMBkPBSLizY/zauber-qcon-san-francisco-2010.html" title="Zauber @ QCon San Francisco 2010" /><author><name>Andres Moratti</name><uri>http://www.blogger.com/profile/15739551346117367586</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_H1TYkiIk3Os/TOXNb8sArsI/AAAAAAAAAVo/IQBuEhBSamE/s72-c/qcon.jpg" height="72" width="72" /><thr:total>3</thr:total><feedburner:origLink>http://engineering.zauberlabs.com/2010/11/zauber-qcon-san-francisco-2010.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0cAR3c8fCp7ImA9Wx9TF0w.&quot;"><id>tag:blogger.com,1999:blog-7870515310189033933.post-3308624771626772806</id><published>2010-07-28T11:45:00.007-03:00</published><updated>2010-11-25T15:50:46.974-03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-11-25T15:50:46.974-03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="usability" /><category scheme="http://www.blogger.com/atom/ns#" term="design process" /><category scheme="http://www.blogger.com/atom/ns#" term="user centered design" /><title>Getting started with Usability and User Centered Design - Part I</title><content type="html">Last week, we &lt;a href="http://blog.zauber.com.ar/2010/07/our-new-design-usability-area-at-zauber.html"&gt;officially launched&lt;/a&gt; our &lt;a href="http://www.zaubersoftware.com/en/services/design/"&gt;&lt;span style="font-weight:bold"&gt;User-Centered Design services&lt;/span&gt;&lt;/a&gt; area at Zauber, together with an internal presentation for the whole company.
Our presentation intended to tell developers why they all take part (consciously or not) of the design process, and how we can develop our design awareness and integrate it with &lt;a href="http://www.zaubersoftware.com/en/process/"&gt;our software development process&lt;/a&gt;.

&lt;dl&gt;
&lt;dt&gt;Why choosing User-Centered Design as a design framework?&lt;/dt&gt;

&lt;dd&gt;&lt;span style="font-weight: bold;"&gt;User-Centered Design&lt;/span&gt; is about &lt;span style="font-weight: bold;"&gt;optimizing a product&lt;/span&gt; by thinking in&lt;span style="font-weight: bold;"&gt; specific goals of an specific group of people in a specific context of use&lt;/span&gt;. It's at the same time a very rational philosophy about design and a set of very useful techniques (some of them really scientific). It makes sense to design for human beings, trying to know better their goals and problems. After all, we're building products for people, and if the product helps their purposes and they can understand it intuitively, their productivity and satisfaction by using it increases.
&lt;/dd&gt;

&lt;dt&gt;Getting started with User-Centered Design&lt;/dt&gt;
&lt;dd&gt;
&lt;p&gt;Some UCD techniques require some effort to learn and integrate to a defined process, but some of them can be more easily adopted.&lt;/p&gt;

&lt;strong style="font-weight:bold"&gt;Iterate the design process&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_toYKT_ESrww/TFBD7vEJASI/AAAAAAAAACI/7-hSmkPOk1E/s1600/iterate.png"&gt;&lt;img style="cursor:pointer; cursor:hand;height:162px;width:590px;" src="http://2.bp.blogspot.com/_toYKT_ESrww/TFBD7vEJASI/AAAAAAAAACI/7-hSmkPOk1E/s600/iterate.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5498969838544552226" /&gt;&lt;/a&gt;
&lt;br /&gt;

&lt;p&gt;You shouldn't think about design as an activity that just takes place at the beginning or at the end of the development process. User-Centered Design is about finding solutions to interaction problems, thus the best way to solve a problem is by approaching it in an iterative way, in order to understand it better and find the most suitable solutions. The best way to make it work is to start working on the more crucial functions and then expand your key decisions to the rest of the features.&lt;/p&gt;

&lt;strong style="font-weight:bold"&gt;Make sketches and wireframes&lt;/strong&gt;
&lt;p&gt;Everytime you think about a screen or visual component, it's a good practice to begin with quick sketches trying to figure out which visual components will be more understandable for your potential users. It's really helpful to validate your work with your project partners and even with people who don't know about the project, previously explaining to them the main goal of the user facing that screen or component. This will also help you to iterate and go over your work.&lt;/p&gt;

&lt;strong style="font-weight:bold"&gt;Learn about some basic laws&lt;/strong&gt;
&lt;ul class="lista"&gt;
   &lt;li&gt;&lt;strong&gt;Fitts Law&lt;/strong&gt;: proximity to the mouse's cursor and size of page elements may increase or decrease the ability of a user to interact with it. In a nutshell, you have to make the clickable area bigger for main actions. To learn more, there's a &lt;a href="http://en.wikipedia.org/wiki/Fitts%27s_law"&gt;Wikipedia article about Fitts' Law&lt;/a&gt; and you can also check &lt;a href="http://www.usabilityfirst.com.foraker.com/glossary/fitts-law/"&gt;Usability First's definition&lt;/a&gt;.&lt;/li&gt;
   &lt;li&gt;&lt;strong&gt;Hick Law&lt;/strong&gt;: when the user is taking a decision, it's making a cognitive effort. The more options he has to consider, the harder it will be for him to make the choice. You've to keep a clear, default path of decisions and to make the rest of possibilities available but with less visual hierarchy. To learn more, you can check &lt;a href="http://www.usabilityfirst.com/glossary/hicks-law/"&gt;Usability First's definition about Hick's Law&lt;/a&gt;.&lt;/li&gt;
   &lt;li&gt;&lt;strong&gt;KLM-GOMS&lt;/strong&gt;: each operation we demand from the user implies a cognitive effort for him/her. KLM-GOMS is a model that quantifies basic operations with a computer, such us clicking, pressing a key, alternating between mouse and keyboard, etc. It's useful to optimize data input actions reducing the effort needed for each of them. &lt;a href="http://www.cs.umd.edu/class/fall2002/cmsc838s/tichi/printer/goms.html"&gt;To learn more about KLM-GOMS, you can check this article&lt;/a&gt; from The Department of Computer Science, University of Maryland.&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;strong style="font-weight:bold"&gt;Use Interaction Design patterns&lt;/strong&gt;
&lt;p&gt;There are very useful libraries you can consider each time you're about to select interactive components for your screens. If you're a developer, you probably know the benefits of using Design Patterns. We recommend &lt;a href="http://www.welie.com/patterns/"&gt;http://www.welie.com/patterns/&lt;/a&gt; and &lt;a href="http://quince.infragistics.com/UX-Design-Patterns.aspx"&gt;http://quince.infragistics.com/UX-Design-Patterns.aspx&lt;/a&gt;.&lt;/p&gt;

&lt;strong style="font-weight:bold"&gt;Use Jakob Nielsen's Heuristic Guidelines&lt;/strong&gt;
&lt;p&gt;Heuristic guidelines are a set of important rules to have in mind when designing to increase intuitiveness, ease of use and consistency of your product. They can also help you to evaluate the application you are building and make new iterations over it once you are in an intermediate instance of the design. To learn in detail about these guidelines, you can &lt;a href="http://www.useit.com/papers/heuristic/heuristic_list.html"&gt;check the original article at useit.com&lt;/a&gt;. There's also a good list of examples of heuristic guidelines applied to web applications at &lt;a href="http://designingwebinterfaces.com/6-tips-for-a-great-flex-ux-part-5"&gt;http://designingwebinterfaces.com/6-tips-for-a-great-flex-ux-part-5&lt;/a&gt;&lt;/p&gt;
&lt;/dd&gt;

&lt;dt&gt;Next steps&lt;/dt&gt;
&lt;dd&gt;
&lt;p&gt;
In the next weeks, we will be covering in detail different research techniques, books and more. Stay tuned and give us feedback!
&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7870515310189033933-3308624771626772806?l=engineering.zauberlabs.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://engineering.zauberlabs.com/feeds/3308624771626772806/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://engineering.zauberlabs.com/2010/07/getting-started-with-usability-and-user.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/3308624771626772806?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/3308624771626772806?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ZauberCode/~3/yyNsrQUk5-M/getting-started-with-usability-and-user.html" title="Getting started with Usability and User Centered Design - Part I" /><author><name>Damian Calderon</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="31" src="http://4.bp.blogspot.com/_toYKT_ESrww/SX4g1RhqORI/AAAAAAAAAAc/9sz9UDtOnUY/S220/damian_mini.png" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_toYKT_ESrww/TFBD7vEJASI/AAAAAAAAACI/7-hSmkPOk1E/s72-c/iterate.png" height="72" width="72" /><thr:total>0</thr:total><feedburner:origLink>http://engineering.zauberlabs.com/2010/07/getting-started-with-usability-and-user.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0AFQX49fCp7ImA9WxFbFE4.&quot;"><id>tag:blogger.com,1999:blog-7870515310189033933.post-3999620843496019800</id><published>2010-06-25T10:41:00.003-03:00</published><updated>2010-07-06T15:08:30.064-03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2010-07-06T15:08:30.064-03:00</app:edited><title>HTTP Content negociation; Spring Framework and Webkit (Chrome/Safari) Bug</title><content type="html">&lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html"&gt;HTTP&lt;/a&gt;,&amp;nbsp;the protocol used to serve most web pages allows  &lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec12.html#sec12"&gt;Content Negotiation&lt;/a&gt;. For example an external application would prefer an XML representation of the content, instead a human would prefer a HTML representation.
&lt;br /&gt;
This negotiation is accomplished this way:
&lt;br /&gt;
&lt;ul class="lista"&gt;
&lt;li&gt;The User Agent sends the request with the &lt;a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html"&gt;Accept Header&lt;/a&gt;. For example, a User Agent could send the header &lt;em&gt;Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8&lt;/em&gt;; preferring first html, then xml, and then any other representation.&lt;/li&gt;
&lt;li&gt;The server parses the Accept header and determines the representation that should be employed.&lt;/li&gt;
&lt;/ul&gt;
&lt;a href="http://www.springsource.org/about"&gt;Spring MVC&lt;/a&gt; lets web developers make use of content negotiation very easily with the  &lt;a href="http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/servlet/view/ContentNegotiatingViewResolver.html"&gt;ContentNegotiatingViewResolver&lt;/a&gt; view resolver.
&lt;br /&gt;
Sadly, content negotiation doest not always works fine in every browser since Chrome/Safari (or any other browser based on &lt;a href="http://webkit.org/"&gt;WebKit&lt;/a&gt;) use a &lt;a href="http://www.gethifi.com/blog/webkit-team-admits-accept-header-error"&gt;wrong accept header&lt;/a&gt;&amp;nbsp;(&lt;a href="https://bugs.webkit.org/show_bug.cgi?id=27267"&gt;Issue #: 27267&lt;/a&gt;). So, if an application wanted to depend on the accept header (something allowed by the protocol) to display its content appropriately, it wouldn't work. There are some workarounds such as using different file extension or URIs for different formats; but none of them follows the REST essence and some applications can't rely on them, because actually there is no Content Negotiation.&lt;br /&gt;
To solve this problem in Java Servlet applications we have developed a  &lt;tt&gt;javax.servlet.Filter&lt;/tt&gt; named &lt;a href="https://code.zauber.com.ar/repos/sandbox/components/commons/code/trunk/web/utils/src/main/java/ar/com/zauber/commons/web/filter/webkit/WebKitContentTypeFilter.java"&gt;WebKitContentTypeFilter&lt;/a&gt; that recognizes &amp;nbsp;Webkits requests and modifies their Accept Header allowing content to be displayed correctly by using&amp;nbsp;&lt;a href="http://static.springsource.org/spring/docs/3.0.x/javadoc-api/org/springframework/web/servlet/view/ContentNegotiatingViewResolver.html"&gt;ContentNegotiatingViewResolver&lt;/a&gt;&amp;nbsp;&amp;nbsp;correctly.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;dt&gt;What do you need to use it?&lt;/dt&gt;
&lt;br /&gt;
&lt;ul class="lista"&gt;
&lt;li&gt;Java&lt;/li&gt;
&lt;li&gt;Spring 3.0+&lt;/li&gt;
&lt;li&gt;Maven 2.2+&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;dt&gt;How to use it?&lt;/dt&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;Change your pom.xml and add the following lines:
&lt;br /&gt;
&lt;pre class="xml" name="code"&gt;    &lt;repositories&gt;
     &lt;repository&gt;
       &lt;releases&gt;&lt;enabled&gt;true&lt;/enabled&gt;&lt;/releases&gt;
       &lt;snapshots&gt;&lt;enabled&gt;false&lt;/enabled&gt;&lt;/snapshots&gt;
       &lt;id&gt;zauber-code-releases&lt;/id&gt;
       &lt;name&gt;Zauber Code Releases&lt;/name&gt;
       &lt;url&gt;https://repo1.zaubersoftware.com/zauber/code/releases/&lt;/url&gt;
     &lt;/repository&gt;
     ...
    &lt;/repositories&gt;
    ...
    &lt;dependency&gt;
      &lt;artifactid&gt;commons-web-utils&lt;/artifactid&gt;
      &lt;groupid&gt;ar.com.zauber.commons.web&lt;/groupid&gt;
      &lt;version&gt;3.33&lt;/version&gt;
    &lt;/dependency&gt;
&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;add this to your web.xml:&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="xml" name="code"&gt;    &lt;filter&gt;
        &lt;filter-name&gt;webkitContentType&lt;/filter-name&gt;
        &lt;filter-class&gt; ar.com.zauber.commons.web.filter.webkit.WebKitContentTypeFilter &lt;/filter-class&gt;
    &lt;/filter&gt;
    ...
    &lt;filter-mapping&gt;
        &lt;filter-name&gt;webkitContentType&lt;/filter-name&gt;
        ...
   &lt;/filter-mapping&gt;
&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7870515310189033933-3999620843496019800?l=engineering.zauberlabs.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://engineering.zauberlabs.com/feeds/3999620843496019800/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://engineering.zauberlabs.com/2010/06/http-content-negociation-spring.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/3999620843496019800?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/3999620843496019800?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ZauberCode/~3/LcwMEs9ejc0/http-content-negociation-spring.html" title="HTTP Content negociation; Spring Framework and Webkit (Chrome/Safari) Bug" /><author><name>Mariano Semelman</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="21" src="http://3.bp.blogspot.com/-a2Qt4LC6uNQ/TkC7hIP0cPI/AAAAAAAACvY/TTsYYGlJLfE/s220/DSC_2275.JPG" /></author><thr:total>2</thr:total><feedburner:origLink>http://engineering.zauberlabs.com/2010/06/http-content-negociation-spring.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkYERH4zfyp7ImA9WxNbFEs.&quot;"><id>tag:blogger.com,1999:blog-7870515310189033933.post-9046267037702619175</id><published>2009-11-17T10:10:00.009-03:00</published><updated>2009-11-17T10:21:45.087-03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-11-17T10:21:45.087-03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="quality" /><category scheme="http://www.blogger.com/atom/ns#" term="agile" /><category scheme="http://www.blogger.com/atom/ns#" term="metrics" /><category scheme="http://www.blogger.com/atom/ns#" term="sonar" /><category scheme="http://www.blogger.com/atom/ns#" term="poirot" /><category scheme="http://www.blogger.com/atom/ns#" term="plugin" /><category scheme="http://www.blogger.com/atom/ns#" term="iso" /><title>Creating a Sonar Plugin for software development metrics</title><content type="html">&lt;p&gt;As you know, at &lt;a href="http://www.zauber.com.ar/"&gt;Zauber&lt;/a&gt; we follow high quality standards, that's why &lt;a href="http://blog.zauber.com.ar/2009/06/iso-90012008-quality-certification.html"&gt;we have obtained an ISO 9001:2008 Quality Certification&lt;/a&gt;. Part of following these standards implies measuring the performance of our company, getting metrics. Obtaining metrics from our development process allow us to understand our current situation, compare it with previous ones and set new objectives for the future.&lt;/p&gt;
&lt;p&gt;Until now, we had three main applications which allowed us to collect information about our projects:
  &lt;ul class="lista"&gt;
  &lt;li&gt;&lt;a href="http://www.zauber.com.ar/en/process/tools/#crono"&gt;Crono&lt;/a&gt;, our time-tracking tool&lt;/li&gt; 
  &lt;li&gt;&lt;a href="http://www.mantisbt.org/"&gt;Mantis Tracker&lt;/a&gt;, an open source issue tracker&lt;/li&gt;
  &lt;li&gt;&lt;a href="http://hudson-ci.org/"&gt;Hudson&lt;/a&gt; a Continuous Integration engine.&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;
&lt;p&gt;However, there was a problem, these applications didn't show us the metrics in a way that they could be studied through time, and Mantis was too dependent on developers' input, not always enforcing us to provide detailed information about the issues we were working on.(e.g.: sometimes people forget to fill in the 'worked hours' field for a certain issue).&lt;/p&gt;
&lt;dt&gt;Where to start?&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;We decided to start using &lt;a href="http://sonar.codehaus.org/"&gt;Sonar&lt;/a&gt;, a quality management platform that allows analyzing and measuring our projects in a continuous way, displaying our metrics in a very fancy way. To cope with the flaws we mentioned of Mantis, we also developed an application that queries our issue tracker database finding incomplete issues that make references to bugs, reporting them to who may be responsible of them, as well as projects managers.&lt;/p&gt;
&lt;p&gt;This way, &lt;a href="http://sonar.codehaus.org/"&gt;Sonar&lt;/a&gt; became our software metrics dashboard, but we also wanted to include custom metrics collected by our own tool Crono and from Mantis. To achiveve this, we implemented a Sonar plug-in using the &lt;a href="http://docs.codehaus.org/display/SONAR/Documentation"&gt;Sonar API&lt;/a&gt;. But many obstacles flourished on the road while we were implementing this plug-in, the main one was that the Sonar API is vaguely documented or not documented at all, so we had to check out how other plug-ins where implemented, so after studying other plugin’s implementations here is what we've learned &lt;/p&gt;


&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_U8y3Br-Rj18/SwKhJVRFfqI/AAAAAAAAByQ/EjyRWwJpAAs/s1600/poirot-workflow2.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 331px;" src="http://3.bp.blogspot.com/_U8y3Br-Rj18/SwKhJVRFfqI/AAAAAAAAByQ/EjyRWwJpAAs/s400/poirot-workflow2.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5405059684497718946" /&gt;&lt;/a&gt;
&lt;p&gt;As you can see sonar is somehow similar to the MVC pattern, except that we don't have much access to the logic beneath it. There are some classes you must use in order to make the plugin work &lt;/p&gt;
&lt;ul class="lista"&gt;
&lt;li&gt;The 'Plugin' class which tells the server all the classes this plugin will use.&lt;/li&gt;
&lt;li&gt;The 'Metric' class which is a list with all the new ways to measure each project, also it references all the information that the view may show&lt;/li&gt;
&lt;li&gt;The 'Widget' class in this case 'RubyRailsWidget' just gives the location of the Ruby template made on &lt;a href="http://www.modruby.net/en/index.rbx"&gt;eRuby&lt;/a&gt; to render in the sonar page&lt;/li&gt;
&lt;li&gt;The 'Sensor' and the 'Decorator' are the classes used to gather and process
all the previous  metrics, the difference between the Sensor and the Decorator is that the Sensor mainly collects information but has no access to what other plugins may collect. On the other side, the Decorator should be responsible for analyzing the information obtained and make cross reference to other information from other plugins.&lt;/li&gt;
&lt;li&gt;The data that the sensor and the decorator gather is sent to the server through the 'context', which is similar to a "command" class in Spring MVC.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; Except for the Sensor and the Decorator, the processes run on the &lt;a href="http://sonar.codehaus.org/"&gt;Sonar&lt;/a&gt; server. The workflow is the following: First, the Plugin class tells Sonar which classes it uses. Then, when you access the project page, the server calls the widgets classes to obtain the template to render the data on the database. When &lt;a href="http://hudson-ci.org/"&gt;Hudson&lt;/a&gt;  runs maven, the latter runs the Sonar plugins, which analyze the project with all the sonar plugins currently installed. Then, the Sensor and the Decorator do their job, saving the metrics information through the Context (the Context will hold a measure for each metric in the class Metric).&lt;/p&gt;&lt;/dd&gt;
&lt;dt&gt;What we did&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;We developed a plugin that uses the previously explained API and Crono REST API.  When running it against a project it calculates the total amount of worked hours obtained from Crono, the total amount of rework hours taken from Mantis, and some other information (quantity and category of issues grouped by status). But it is necessary to configure certain settings before obtaining that information. There are two kinds of settings: global settings such as Mantis database URL, Mantis username, Crono URL, username, etc. These can be configured from the plugin settings in the sonar server,
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_U8y3Br-Rj18/SwKhJoTM7fI/AAAAAAAAByY/l_EuhcrL5jc/s1600/sonar-settings.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 298px;" src="http://3.bp.blogspot.com/_U8y3Br-Rj18/SwKhJoTM7fI/AAAAAAAAByY/l_EuhcrL5jc/s400/sonar-settings.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5405059689606868466" /&gt;&lt;/a&gt;
and project related settings, such as the project id in the Mantis database or the Crono project unixname in Crono, which are configured in each project maven's pom like these:&lt;/p&gt;
&lt;pre name="code" class="xhtml"&gt;
&lt;sonar.mantis.id&gt;52&lt;/sonar.mantis.id&gt;
&lt;crono.organization.name&gt;zauber&lt;/crono.organization.name&gt;
&lt;crono.project.name&gt;zauber-crono&lt;/crono.project.name&gt;
&lt;crono.start.date&gt;2009-10-5&lt;/crono.start.date&gt;
&lt;/pre&gt;
&lt;p&gt;Where the start date means when the project started in &lt;a href="http://en.wikipedia.org/wiki/ISO_8601"&gt;ISO format&lt;/a&gt;.
Once configured, when sonar analyzes a project, this plugin connects to Mantis and Crono, gets all the necessary information and stores it on the sonar server. After that, when we access a project page, the widget from our plugin is rendered and "voilá": we have our plugin results being displayed like this:&lt;/p&gt;
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_U8y3Br-Rj18/SwKiRH0hoMI/AAAAAAAAByw/C4Wgx-g3r3E/s1600/sonar-widget.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 261px; height: 400px;" src="http://2.bp.blogspot.com/_U8y3Br-Rj18/SwKiRH0hoMI/AAAAAAAAByw/C4Wgx-g3r3E/s400/sonar-widget.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5405060917838848194" /&gt;&lt;/a&gt;
&lt;dt&gt;How will this help in the future?&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;We find this application very useful, because it gives us a complete software metrics dashboard for every project at a glance.&lt;p&gt;
Main Dashboard, a quick view of every project (red column provided by our plugin).
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_U8y3Br-Rj18/SwKhJIaKLZI/AAAAAAAAByI/VEWlMSBwzrQ/s1600/dash.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 400px;" src="http://3.bp.blogspot.com/_U8y3Br-Rj18/SwKhJIaKLZI/AAAAAAAAByI/VEWlMSBwzrQ/s1600/dash.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5405059681046113682" /&gt;&lt;/a&gt;
Tree-map: a tool that works perfectly when comparing projects on a specific subject.
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_U8y3Br-Rj18/SwKifO_JKzI/AAAAAAAABy4/hf6FO3x39q4/s1600/sonar-tree-map.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 285px; height: 373px;" src="http://2.bp.blogspot.com/_U8y3Br-Rj18/SwKifO_JKzI/AAAAAAAABy4/hf6FO3x39q4/s400/sonar-tree-map.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5405061160280599346" /&gt;&lt;/a&gt;


Timeline: a tool that lets you graphically see how the project evolves through time.
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_U8y3Br-Rj18/SwKhJy0NpTI/AAAAAAAAByg/yAxlC6uWhDE/s1600/sonar+timeline.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 600px; height: 350px;" src="http://1.bp.blogspot.com/_U8y3Br-Rj18/SwKhJy0NpTI/AAAAAAAAByg/yAxlC6uWhDE/s1600/sonar+timeline.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5405059692429681970" /&gt;&lt;/a&gt;
&lt;p&gt;We hope that you found this article as useful as developing this plugin was for us. Feel free to &lt;a href="http://www.zauber.com.ar/en/contact"&gt;contact us&lt;/a&gt; if you have any questions.   &lt;/p&gt;&lt;/dd&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7870515310189033933-9046267037702619175?l=engineering.zauberlabs.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://engineering.zauberlabs.com/feeds/9046267037702619175/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://engineering.zauberlabs.com/2009/11/creating-sonar-plugin-for-software.html#comment-form" title="4 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/9046267037702619175?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/9046267037702619175?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ZauberCode/~3/4pq2uXC7k-A/creating-sonar-plugin-for-software.html" title="Creating a Sonar Plugin for software development metrics" /><author><name>Mariano Semelman</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="21" src="http://3.bp.blogspot.com/-a2Qt4LC6uNQ/TkC7hIP0cPI/AAAAAAAACvY/TTsYYGlJLfE/s220/DSC_2275.JPG" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_U8y3Br-Rj18/SwKhJVRFfqI/AAAAAAAAByQ/EjyRWwJpAAs/s72-c/poirot-workflow2.jpg" height="72" width="72" /><thr:total>4</thr:total><feedburner:origLink>http://engineering.zauberlabs.com/2009/11/creating-sonar-plugin-for-software.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0cFR3k7eSp7ImA9WxJUFko.&quot;"><id>tag:blogger.com,1999:blog-7870515310189033933.post-6241292615049109755</id><published>2009-07-14T16:33:00.010-03:00</published><updated>2009-07-15T12:16:56.701-03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-07-15T12:16:56.701-03:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="javascript" /><category scheme="http://www.blogger.com/atom/ns#" term="unit testing" /><category scheme="http://www.blogger.com/atom/ns#" term="programming" /><title>Stay green: Javascript Unit Testing</title><content type="html">&lt;p&gt;With the improvement of our source code quality as a constant goal, we decided to find a way to write Unit Tests for our Javascript code.
&lt;a href="https://code.zauber.com.ar/repos/sandbox/components/javascript/validate/code/releases/0.2/"&gt;Our implementation&lt;/a&gt; of &lt;a href="http://commons.apache.org/lang/apidocs/org/apache/commons/lang/Validate.html"&gt;Apache Commons Lang Validate&lt;/a&gt; for Javascript was our first step to build more solid applications, but an important part was missing until now: unit testing.
We found a way to integrate JS unit tests with &lt;a href="http://maven.apache.org/"&gt;Maven&lt;/a&gt;, &lt;a href="http://eclipse.org/"&gt;Eclipse&lt;/a&gt;, and the continuous integration server &lt;a href="https://hudson.dev.java.net/"&gt;Hudson&lt;/a&gt;.&lt;/p&gt;

&lt;dl&gt;
 &lt;dt&gt;Zauber Javascript Validation Utils&lt;/dt&gt;
 &lt;dd&gt;
  Is an open source library inspired on &lt;a href="http://commons.apache.org/lang/apidocs/org/apache/commons/lang/Validate.html"&gt;org.apache.commons.lang.Validate&lt;/a&gt; written by Zauber and published under the &lt;a href="http://www.apache.org/licenses/LICENSE-2.0.html"&gt;Apache License v2.0&lt;/a&gt;.
  You can download it from 
&lt;li&gt;&lt;a href="https://code.zauber.com.ar/repos/sandbox/components/javascript/validate/code/releases/0.2/"&gt;https://code.zauber.com.ar/repos/sandbox/components/javascript/validate/code/releases/0.2/&lt;/a&gt;&lt;/li&gt;
  &lt;/dd&gt;
&lt;/dl&gt;

&lt;dl&gt;
 &lt;dt&gt;How we test javascript code?&lt;/dt&gt;
 &lt;dd&gt;
 We use an open source framework called &lt;a href="http://jsunit.berlios.de/"&gt;JSUnit1.3&lt;/a&gt;, a port of &lt;a href="http://www.junit.org/"&gt;JUnit&lt;/a&gt;.
 There are two frameworks with the same name (JSUnit), the one we are using, JSUnit1.3, uses &lt;a href="http://www.mozilla.org/rhino/"&gt;Rhino&lt;/a&gt; to run the tests. 
 The second one, &lt;a href="http://www.jsunit.net/"&gt;JSUnit2&lt;/a&gt;, uses a HTML file called &lt;a href="http://www.jsunit.net/runner/testRunner.html"&gt;testRunner.html&lt;/a&gt; to run the tests on multiple browsers from client-side. This is great to do cross-browser compatibility tests, but for the moment we are just validating Javascript syntax and logic using the first toolkit.
 &lt;/dd&gt;
&lt;/dl&gt;

&lt;dl&gt;
 &lt;dt&gt;Project structure&lt;/dt&gt;
 &lt;dd&gt;The main idea is to respect Maven's conventions, so our project
 structure looks like this:&lt;/dd&gt;
 &lt;dd&gt;
 &lt;pre name="code" class="xml"&gt;
   /app
      /src
       * /main
           o /java
           o /javascript
               + validate.js (the library)
           o /resources
       * /test
           o /java
           o /javascript
               + validateTest.js (tests for validate.js written in JavaScript)
           o /resources
       * /target
           o /surefire-reports
               + TEST-JS-Validate.xml
       * pom.xml
 &lt;/pre&gt;
 &lt;/dd&gt;
&lt;/dl&gt;

&lt;dl&gt;
 &lt;dt&gt;Configuration - pom.xml&lt;/dt&gt;
 &lt;dd&gt;This file is the key for a successful configuration, you should
 declare the junit plugin for maven2, something like this:&lt;/dd&gt;
   &lt;pre name="code" class="xml"&gt;
   &amp;lt;plugin&amp;gt;
       &amp;lt;groupId&amp;gt;de.berlios.jsunit&amp;lt;/groupId&amp;gt;
       &amp;lt;artifactId&amp;gt;jsunit-maven2-plugin&amp;lt;/artifactId&amp;gt;
       &amp;lt;version&amp;gt;1.3&amp;lt;/version&amp;gt;
       &amp;lt;extensions&amp;gt;true&amp;lt;/extensions&amp;gt;
   &amp;lt;/plugin&amp;gt;
   &lt;/pre&gt;

 &lt;dd&gt;and then configure your tests, for example:&lt;/dd&gt;
   &lt;pre name="code" class="xml"&gt;
   &amp;lt;executions&amp;gt;
        &amp;lt;execution&amp;gt;
          &amp;lt;phase&amp;gt;test&amp;lt;/phase&amp;gt;
          &amp;lt;goals&amp;gt;
            &amp;lt;goal&amp;gt;jsunit-test&amp;lt;/goal&amp;gt;
          &amp;lt;/goals&amp;gt;
          &amp;lt;configuration&amp;gt;
         
             &amp;lt;!-- src --&amp;gt;
             &amp;lt;sourceDirectory&amp;gt;src/main/javascript&amp;lt;/sourceDirectory&amp;gt;
             &amp;lt;sources&amp;gt;
               &amp;lt;source&amp;gt;validate.js&amp;lt;/source&amp;gt;
             &amp;lt;/sources&amp;gt;
             
             &amp;lt;!-- test --&amp;gt;
             &amp;lt;testSourceDirectory&amp;gt;src/test/javascript&amp;lt;/testSourceDirectory&amp;gt;
             &amp;lt;testSuites&amp;gt;
               &amp;lt;testSuite&amp;gt;
                 &amp;lt;name&amp;gt;JS-Validate&amp;lt;/name&amp;gt;
               &amp;lt;/testSuite&amp;gt;
             &amp;lt;/testSuites&amp;gt;
            
             &amp;lt;!-- report --&amp;gt;
             &amp;lt;reportsDirectory&amp;gt;target/surefire-reports&amp;lt;/reportsDirectory&amp;gt;
           &amp;lt;/configuration&amp;gt;
         &amp;lt;/execution&amp;gt;
   &amp;lt;/executions&amp;gt;
   &lt;/pre&gt;

 &lt;dd&gt;That's all, you can now run your JS test just calling maven
 as usual (ie. &lt;tt&gt;mvn test&lt;/tt&gt;).&lt;/dd&gt;

&lt;pre name="code" class="xml"&gt;
$ mvn test
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Building Validation Utils
[INFO]    task-segment: [test]
[INFO] ------------------------------------------------------------------------
[INFO] [resources:resources]
[INFO] Copying 0 resource
[INFO] [compiler:compile]
[INFO] Nothing to compile - all classes are up to date
[INFO] [resources:testResources]
[INFO] Copying 0 resource
[INFO] [compiler:testCompile]
[INFO] Compiling 1 source file to: target/test-classes
[INFO] [surefire:test]
[INFO] Surefire report directory: target/surefire-reports
------------------------------------------------------
T E S T S
-------------------------------------------------------
There are no tests to run.

Results :
Tests run: 0, Failures: 0, Errors: 0, Skipped: 0

[INFO] [jsunit2:jsunit-test {execution: default}]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 8 seconds
[INFO] Finished at: Tue Jul 14 10:43:00 ART 2009
[INFO] Final Memory: 18M/148M
[INFO] ------------------------------------------------------------------------
&lt;/pre&gt;
 &lt;dd&gt;Note that maven says &lt;em&gt;There are no tests to run&lt;/em&gt; but
 jsunit-test is being called.&lt;/dd&gt;
&lt;/dl&gt;

&lt;dl&gt;
 &lt;dt&gt;Configuration - Eclipse&lt;/dt&gt;

 &lt;dd&gt;There is also another way to run your tests: calling them from
 Eclipse just like you do with regular Java tests. To do that, you
 could write your own implementation or include a module from 
 &lt;a href="https://code.zauber.com.ar/repos/sandbox/components/commons/code/releases/3.16/"&gt;
 Zauber Commons 3.16&lt;/a&gt; called &lt;tt&gt;commons-javascript-test&lt;/tt&gt;. 
 We use the class &lt;a href="https://code.zauber.com.ar/repos/sandbox/components/commons/code/releases/3.16/test/javascript/src/main/java/ar/com/zauber/commons/test/javascript/JsTestCase.java"&gt;ar.com.zauber.commons.test.javascript.JsTestCase&lt;/a&gt;. 
 This class extends from JUnit &lt;a href="http://junit.org/apidocs/junit/framework/TestCase.html"&gt;TestCase&lt;/a&gt;, so it can be used just like a regular test case.&lt;/dd&gt;

 &lt;dd&gt;So, how can we run it from Eclipse? A very simple example,
 step by step:&lt;/dd&gt;
 &lt;dd&gt;
 &lt;ol class="lista"&gt;

   &lt;li&gt;write some Javascript code, like we did in &lt;em&gt;validate.js&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;write some tests for that code, you should follow this prototype
   &lt;pre name="code" class="js"&gt;
      function ValidateTest(name) {
          TestCase.call( this, name );
      }
      
      ValidateTest.prototype = new TestCase();
      
      //"import" validate class
      Validate = validate.Validate;
      
      /** 
       * this function tests Validate.notNull with many valid values and a null value 
       */
      ValidateTest.prototype.testNotNull = function(){
         var valids = new Array(0, 1, true, false, 'text', new Object(), 
                 new Array(1,2), function(){});
         var invalid = null;
      
         for(i in valids){ // tests all valid values
             try{ 
                 Validate.notNull(valids[i]); // testing a not null value, shoudn't fail.
             }catch(e){
                 fail("notNull shouldn't raise an exception with value:" + valids[i] + " (type: " + typeof(valids[i]) + ").");    
             }
         }
      
         try{
             Validate.notNull(invalid); // testing a null value, should fail.
             fail("notNull should raise an exception with a null value.");
         }catch(e){
             //notNull is working correctly
         }
      }
   &lt;/pre&gt;
   &lt;p&gt;Here you can use the code written in step one by "importing" it, just like
   we do in this example.&lt;/p&gt;
   &lt;/li&gt;

   &lt;li&gt;Write a Java Class extending from &lt;tt&gt;JsTestCase&lt;/tt&gt;, it will force
   you to implement a method called &lt;tt&gt;getIncludes()&lt;/tt&gt;. That method returns
   a &lt;tt&gt;String array&lt;/tt&gt; with the path for all files to be included in the
   test context, and all files that actually contain the tests. There
   is an important point here, and it is the name of this Java class.
   Normally you don't want this class to be executed by maven, so the
   class name should not end with &lt;em&gt;Test&lt;/em&gt;, any other name will work, for
   example, we like to use &lt;em&gt;Driver&lt;/em&gt;:
   &lt;pre name="code" class="java"&gt;
    public class ValidateDriver extends JsTestCase {
   
     /** @see JsTestCase#getIncludes() */
     @Override
     protected final String[] getIncludes() {
         return new String[] {
             "src/main/javascript/validate.js",
             "src/test/javascript/ValidateTest.js"
         };
     }
   &lt;/pre&gt;
   &lt;/li&gt;
   &lt;li&gt;Now, just click on Run As JUnit Test and you will see
   your tests running.&lt;/li&gt;
   &lt;li&gt;Optionally, you can check the test reports on standard
   output. This can be achieved over all your tests by passing the following
   argument to the JVM: &lt;tt&gt;-Djavascript.test.showdetails=true&lt;/tt&gt; or over an
   individual test by overriding the method &lt;tt&gt;showDetails()&lt;/tt&gt; to return
   true.&lt;/li&gt;
 &lt;/ol&gt;
 &lt;/dd&gt;
&lt;/dl&gt;

&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_xHN21ztrTuY/SlyYMSn9wyI/AAAAAAAAAAM/qI2zxaHYTFg/s1600-h/ValidateDriver.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 220px;" src="http://1.bp.blogspot.com/_xHN21ztrTuY/SlyYMSn9wyI/AAAAAAAAAAM/qI2zxaHYTFg/s320/ValidateDriver.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5358324993589363490" /&gt;&lt;/a&gt;

&lt;dl&gt;
 &lt;dt&gt;A working example&lt;/dt&gt;
 &lt;dd&gt;You can checkout this project from our svn repository at
 &lt;a href="https://code.zauber.com.ar/repos/sandbox/components/javascript/validate/code/releases/0.2/"&gt;
 https://code.zauber.com.ar/repos/sandbox/components/javascript/validate/code/releases/0.2/&lt;/a&gt;
 &lt;/dd&gt;
&lt;/dl&gt;

&lt;p&gt;We hope you like it and use it ! Any feedback is always welcome.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7870515310189033933-6241292615049109755?l=engineering.zauberlabs.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://engineering.zauberlabs.com/feeds/6241292615049109755/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://engineering.zauberlabs.com/2009/07/stay-green-javascript-unit-testing.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/6241292615049109755?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/6241292615049109755?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ZauberCode/~3/dcaxxLUrm5M/stay-green-javascript-unit-testing.html" title="Stay green: Javascript Unit Testing" /><author><name>Pablo Grigolatto</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_xHN21ztrTuY/SlyYMSn9wyI/AAAAAAAAAAM/qI2zxaHYTFg/s72-c/ValidateDriver.png" height="72" width="72" /><thr:total>1</thr:total><feedburner:origLink>http://engineering.zauberlabs.com/2009/07/stay-green-javascript-unit-testing.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEcMQXk4fyp7ImA9WxVaF0k.&quot;"><id>tag:blogger.com,1999:blog-7870515310189033933.post-300651632325198540</id><published>2009-04-14T17:37:00.002-03:00</published><updated>2009-04-14T17:48:00.737-03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-14T17:48:00.737-03:00</app:edited><title>ControlFreak: Python Inversion of Control</title><content type="html">&lt;p&gt;Back in 2007 I started programming in python. At first, the goal was
to learn how to write programs the &lt;em&gt;pythonic way&lt;/em&gt;, being my background a
Java Enterprise programmer, I wanted to avoid programming java-like
in python.&lt;/p&gt;

&lt;p&gt;We started building a web application, using &lt;a href="http://pylonshq.com/"&gt;Pylons&lt;/a&gt;, &lt;a href="http://www.sqlalchemy.org/"&gt;SQLAlchemy&lt;/a&gt; andp
&lt;a href="http://www.makotemplates.org/"&gt;Mako&lt;/a&gt; as the base frameworks. At first we struggled with poor
documentation (we were used to have lots of books about each
framework in java), but as the time passed, we started feeling
comfortable with python and its ways.&lt;/p&gt;

&lt;p&gt;The project became bigger and bigger, and it was at that time that we
started missing Java and its "&lt;em&gt;bureaucratic&lt;/em&gt;" way of coding. Don't
get me wrong, bureaucracy is not a bad thing. The issue is unnecessary
bureaucracy. We started missing &lt;em&gt;static types&lt;/em&gt;, &lt;em&gt;lack of module variables&lt;/em&gt;,
&lt;em&gt;long package names&lt;/em&gt;, and &lt;em&gt;inversion of control&lt;/em&gt; to rule them all.&lt;/p&gt;

&lt;p&gt;At that time we started using "&lt;em&gt;the java way of coding&lt;/em&gt;" in python, in order
to make the project more maintainable. For example, we quit using the
sqlAlchemy session as a module variable, and started injecting it. We
erased every static reference to a module variable, and we also wanted
to get good package names (at first they seem to be the same as java,
but that's misguided).&lt;/p&gt;

&lt;p&gt;So, we needed an inversion of control (IoC) library and started to look for one.&lt;/p&gt;

&lt;h3&gt;Why a new one?&lt;/h3&gt;

&lt;p&gt;When we started looking for an IoC library, we didn't find one that filled
ours needs. The exception was &lt;a href="http://springpython.webfactional.com/"&gt;Spring-Python&lt;/a&gt;, but from our point of view,
it was a port one on one of the Java &lt;a href="http://www.springsource.org/about"&gt;Spring framework&lt;/a&gt;; and we didn't want
something that complex.&lt;/p&gt;

&lt;p&gt;What we were looking for, was something that with much of the Spring
IoC capabilities, but taking into consideration that this was python
and not Java: There are things that are simpler to do in python,
and other that are simpler to do in Java. Above all, we wanted
to say "inject this instance on that other
instance" in the simplest way possible. That was the reason we decided to do our own. I named it "ControlFreak"&lt;/p&gt;

&lt;h3&gt;How and When?&lt;/h3&gt;

&lt;p&gt;This is kind of a disclaimer, because ControlFreak was built on spare
hours, spare and sparse hours. And it's something I would like to
refactor, probably as a whole, when I found the time for it.&lt;/p&gt;

&lt;p&gt;Enough of introducction, let's me show what is controlfreak!&lt;/p&gt;

&lt;h3&gt;ControlFreak: The library&lt;/h3&gt;

&lt;p&gt;Controlfreak is a IoC library with capabilities similar to what
spring does in Java. But there are some changes on it's design
that are worth to mention. 
The source code can be found in a &lt;a href="https://code.zauber.com.ar/repos/sandbox/components/controlfreak/"&gt;SVN repository&lt;/a&gt;&lt;/p&gt;. Also, controlfreak depends on pycommons, that can be found in this &lt;a href="https://code.zauber.com.ar/repos/sandbox/components/pycommons/"&gt;svn repo&lt;/a&gt;.

&lt;h4&gt;Components&lt;/h4&gt;

&lt;p&gt;When you code, you tend to think about interfaces and the different
implementations of them. It's like you have a contract, and several
providers of that contract.&lt;/p&gt;

&lt;p&gt;Discussing with a colleague of mine, we thought that it would be
interesting to take that concept into the IoC configurations. So, that
you won't be working just with beans, but with components. A component
is a group of beans, that, one can think, provides (or exports) some
beans. For example, a database component, will provide a session
bean. And one could have different implementations of this database
component. In order to take advantage of this metaphor is that
components where created. A component, may require other component to
work properly. For example, the DAO components will need the database
component to function properly, no matter who or how is this other
component "&lt;em&gt;implemented&lt;/em&gt;"&lt;/p&gt;

&lt;p&gt;So, in controlfreak, the application is a bundle of components, wired
together and configuration files for everything that is not beans.&lt;/p&gt;

&lt;h4&gt;Python Static Beans&lt;/h4&gt;

&lt;p&gt;When considering different alternatives to inject model objects, we
arrived to a different approach to the one we would took in java.&lt;/p&gt;

&lt;p&gt;To inject model objects with services and others beans, one would need
to intercept the model object creation, so as to let the IoC library
to create the object. The ORM is the one usually creating model
objects, so one would need to intercept the model creation there.&lt;/p&gt;

&lt;p&gt;When making queries that return hundreds of objects, objects that
won't probably use any of their injected properties, one starts to
wonder if the overhead of creating those objects with IoC makes
sense. But that's a question I don't plan to answer here.&lt;/p&gt;

&lt;p&gt;Our solution, doesn't involve injecting model objects, because we end
up injecting model classes. This is what we call static beans. Classes
in python are the same as instances, just objects. So it's pretty easy
to inject them with properties, not on creation, but afterwards.&lt;/p&gt;

&lt;p&gt;There's a catch on using class injection, instead of instance
injection. The injected properties must be stateless, not dependant of
the current instance that is calling them. But that's usually the case
with services.&lt;/p&gt;

&lt;h4&gt;ControlFreak ApplicationContext&lt;/h4&gt;

&lt;p&gt;The &lt;tt&gt;ApplicationContext&lt;/tt&gt; class is the same as Spring's one. That is, it
is given an application's configuration; and we can use it as a
Bean's Locator using the &lt;tt&gt;get()&lt;/tt&gt; method.&lt;/p&gt;

&lt;p&gt;The static beans are initialized at the same time as the
&lt;tt&gt;ApplicationContext&lt;/tt&gt;, cause they inject already created objects such as
class o modules.&lt;/p&gt;

&lt;p&gt;All other beans are created on demand, and they are cached for later
use.&lt;/p&gt;

&lt;p&gt;Right now the library supports the following kind of beans:&lt;/p&gt;

&lt;ul class="lista"&gt;
  &lt;li&gt;&lt;em&gt;bean&lt;/em&gt;: Constructs and inject a class&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;factory&lt;/em&gt;: Creates a bean by calling a function (callable)&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;alias&lt;/em&gt;: An alias of another bean&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;map&lt;/em&gt;: A map of beans&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;list&lt;/em&gt;:  a list of beans &lt;/li&gt;
  &lt;li&gt;&lt;em&gt;static&lt;/em&gt;: Inject on already created objects (on &lt;tt&gt;ApplicationContext&lt;/tt&gt;
    initialization), such as class or module objects.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Configuration&lt;/h4&gt;

&lt;p&gt;At this moment the only supported configuration format is yaml files.
There are 3 kinds of yaml files to define:&lt;/p&gt;

&lt;ul class="lista"&gt;
  &lt;li&gt;components definition&lt;/li&gt;
  &lt;li&gt;configuration variables for components&lt;/li&gt;
  &lt;li&gt;application definition&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;Component's File&lt;/h5&gt;

&lt;p&gt;A component is defined by a name, required config keys, required
components and beans definitions. Several components can be defined
in the same file. That is, a component file is something like:&lt;/p&gt;

&lt;pre name="code" class="html"&gt;
component-name:
 config-keys:
   - a-config-key
   - another-config-key
 required-components:
   - other-comp-name
 definitions:
   # beans definitions

other-component-name:
  #same as before
  # ...
&lt;/pre&gt;

&lt;p&gt;Inside 'definitions' goes all components beans, next I'll show how to
configure each of the bean's types.&lt;/p&gt;

&lt;p&gt;A bean of type 'bean' can have setter or construction injection, so it
goes:&lt;/p&gt;

&lt;pre name="code" class="js"&gt;
   renderer:
     type: bean
     path: renderers.html.impl:HtmlRenderer
     constructor-args:
       debug_mode: config:debug_mode

   renderer:
     type: bean
     path: renderers.rest.impl:ReStructuredTextRenderer
     properties:
       syntax: bean:syntax_rules
&lt;/pre&gt;

&lt;p&gt;The bean's name in each case is &lt;tt&gt;'renderer'&lt;/tt&gt;, one uses constructor
injection, and the other setter injection. The first has a
constructor's keyword argument named &lt;tt&gt;'debug_mode'&lt;/tt&gt; and the value to set
is the config-key of the component &lt;tt&gt;'debug_mode'&lt;/tt&gt;. The second bean, has
a property named &lt;tt&gt;'syntax'&lt;/tt&gt; set with another bean, named
&lt;tt&gt;'syntax_rules'&lt;/tt&gt;. This bean, must be in the same component. If a bean
from another component is needed, first you need to declare the other
component in &lt;tt&gt;'required-components'&lt;/tt&gt; of the component, and then, when
referring to the bean, you should use it's absolute name, that is:
&lt;tt&gt;'comp_name::bean_name'&lt;/tt&gt;.&lt;/p&gt;

&lt;p&gt;A bean of type 'factory', has only constructor-args, so it goes:&lt;/p&gt;

&lt;pre name="code" class="js"&gt;
   syntax_rules:
     type: factory
     path: renderers.rest.rules:create_rules
     constructor-args:
       keywords: config:accepted_keywords
&lt;/pre&gt;

&lt;p&gt;If instead of a keyword argument, you want to use positional
arguments, you would place a keyword the position of the argument,
beginning with 0.&lt;/p&gt;

&lt;p&gt;A bean of type 'alias' is just a link to another bean, so it goes:&lt;/p&gt;
&lt;pre name="code" class="js"&gt;
   documents_generator:
     type: alias
     target: simple_generator
&lt;/pre&gt;
&lt;p&gt;A bean of type 'map' or 'list' needs you to define &lt;tt&gt;'properties'&lt;/tt&gt; as a
dictionary or list depending the case. Examples of this are:&lt;/p&gt;
&lt;pre name="code" class="js"&gt;
   rules_map:
     type: map
     properties:
       rule1: bean:some_rule
       rule2: bean:some_other_rule
   exceptions_list:
     type: list
     properties:
       - bean:some_exception
       - my-string-exception
&lt;/pre&gt;
&lt;p&gt;A bean fo type &lt;tt&gt;'static'&lt;/tt&gt; has only setter injection, because
controlfreak is not involved in the object creation. For example:&lt;/p&gt;
&lt;pre name="code" class="js"&gt;
   api-accounts:
     type: static
     path: popserver.controllers.api.accounts:AccountsController
     properties:
       service_dao: bean:dao::serviceDAO
       account_dao: bean:dao::accountDAO
       user_dao: bean:dao::userDAO
       account_service: bean:pop-services::accountService
&lt;/pre&gt;

&lt;h5&gt;Configuration Variables File&lt;/h5&gt;

&lt;p&gt;A configuration variables file, defines a values for component's
required configuration values. So if we have a component named
'database' that requires a config value &lt;tt&gt;'database_url'&lt;/tt&gt; the config file
would look like&lt;/p&gt;
&lt;pre name="code" class="js"&gt;
database:
 database_url: postgres://user:password@mydbserver:5432/dbname
&lt;/pre&gt;
&lt;p&gt;In the same configuration file one can place configuration values for
several components.&lt;/p&gt;

&lt;h5&gt;Application File&lt;/h5&gt;

&lt;p&gt;An application file, is where we bundle several components files, with
their configuration files. The reason to separate the config values
from the component's bean is because  the config values will probably
change more often than the bean's wiring structure. Also, I believe
that is clearer to see configuration values on a separate place
than seeing them within the beans that are, in a way,
more coupled with the programming task itself.&lt;/p&gt;

&lt;p&gt;Another thing one can do in the application file is to redefine the
components wiring. That is, to decide witch components will fulfill
the required components of other component. For example, suppose that
we have two components that &lt;em&gt;"implements"&lt;/em&gt; the same contract, one it's
called &lt;tt&gt;'dummy-cache'&lt;/tt&gt; and the other &lt;tt&gt;'standard-cache'&lt;/tt&gt;. Now, we also have
a component, let's say &lt;tt&gt;'services'&lt;/tt&gt; that requires a 'cache'
component. The application file would be the place to wire one of the
cache components to the services components: dummy for development,
and standard for production environment.&lt;/p&gt;

&lt;p&gt;Another feature of the application file is to have a same component,
configured with two different config values at the same time. Think on
the component as a class definition, that we would want to instantiate
with different values each time. For example, we have a database
component, and we are using two databases, and we need to use the same
component with two different config values. To do this, we define two
aliases for 'database' in application context: &lt;tt&gt;'database1'&lt;/tt&gt; and
&lt;tt&gt;'database2'&lt;/tt&gt;. In the config file, we will then set the values for &lt;tt&gt;'database1'&lt;/tt&gt; and
&lt;tt&gt;'database2'&lt;/tt&gt;; and not for &lt;tt&gt;'database'&lt;/tt&gt;. &lt;/p&gt;

&lt;p&gt;An example of an application file is:&lt;/p&gt;
&lt;pre name="code" class="js"&gt;
includes: #component files to include
 - "%(here)s/../../components/general/amazon-mock.yaml"
 - "%(here)s/../../components/general/cache.yaml"
 - "%(here)s/../../components/general/database.yaml"
 - "%(here)s/../../components/general/eye-services.yaml"
 - "%(here)s/../../components/general/pop-services.yaml"
 - "%(here)s/../../components/general/core-model.yaml"
 - "%(here)s/../../components/general/dao.yaml"
 - "%(here)s/../../components/general/domains.yaml"
 - "%(here)s/../../components/general/extauth-services.yaml"
customization: #aliases and rewiring as explained
 cache:
   required-components:
     cache-customization: dummy-cache-customization
 eye-services:
   required-components:
     item-age-customization: testing-item-age-customization
config: #config files to read
 - "%(here)s/../base/config.yaml"
 - "%(here)s/config.yaml"
&lt;/pre&gt;

&lt;h4&gt;Using the library&lt;/h4&gt;

&lt;p&gt;To load a control freak set up, one would to something like:&lt;/p&gt;
&lt;pre name="code" class="js"&gt;
from controlfreak.config.yaml import createApplicationContext
appctx = createApplicationContext('my-app-file.yaml')
&lt;/pre&gt;
&lt;p&gt;To use the Application Context as a bean's locator, one need to give
it the absolute path of a bean, that is, the component and the bean
name together. For example:&lt;/p&gt;
&lt;pre name="code" class="js"&gt;
session = appctx.get('database::session')
...
&lt;/pre&gt;
&lt;p&gt;This would result on the 'session' bean from the &lt;tt&gt;'database'&lt;/tt&gt; component.&lt;/p&gt;

&lt;h4&gt;Final Example&lt;/h4&gt;

&lt;p&gt;Here's an example of each file:&lt;/p&gt;
&lt;pre name="code" class="js"&gt;
component file:
reSt-renderer:
 config-keys:
   - accepted_keywords
 definitions:
   renderer:
     type: bean
     path: renderers.rest.impl:ReStructuredTextRenderer
     properties:
       syntax: bean:syntax_rules
   syntax_rules:
     type: factory
     path: renderers.rest.rules:create_rules
     constructor-args:
       keywords: config:accepted_keywords


html-renderer:
 config-keys:
   - debug_mode
 definitions:
   renderer:
     type: bean
     path: renderers.html.impl:HtmlRenderer
     constructor-args:
       debug_mode: config:debug_mode

documents-generator:
 required-components:
   - renderer
 definitions:
   documents_generator:
     type: alias
     target: simple_generator
   simple_generator:
     type: bean
     path: generators.simple:SimpleGenerator
     propreties:
       renderer: bean:renderer:renderer
   complex_generator:
     type: bean
     path: generators.complex:ComplexGenerator
     constructor-args:
       rules: bean:rules_map
       exceptions: bean:exceptions_list
   rules_map:
     type: map
     properties:
       rule1: bean:some_rule
       rule2: bean:some_other_rule
   exceptions_list:
     type: list
     properties:
       - bean:some_exception
       - my-string-exception
   some_rule:
     type: bean
     path: rules:SomeRule
   some_other_rule:
     type: bean
     path: rules:SomeOtherRule
   some_exception:
     type: bean
     path: excpetions:MyGeneratorException
&lt;/pre&gt;
&lt;p&gt;config file:&lt;/p&gt;
&lt;pre name="code" class="js"&gt;
reSt-renderer:
 accepted_keywords:
   - hey
   - jo

html-renderer:
 debug_mode: True
&lt;/pre&gt;
&lt;p&gt;application file:&lt;/p&gt;
&lt;pre name="code" class="js"&gt;
includes:
 - "%(here)s/my-components.yaml"
config:
 - "%(here)s/my-config.yaml"
&lt;/pre&gt;

&lt;p&gt;Well, that's all, I hope you will find this IoC library useful!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7870515310189033933-300651632325198540?l=engineering.zauberlabs.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://engineering.zauberlabs.com/feeds/300651632325198540/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://engineering.zauberlabs.com/2009/04/controlfreak-python-inversion-of.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/300651632325198540?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/300651632325198540?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ZauberCode/~3/YN0ui3T30Fo/controlfreak-python-inversion-of.html" title="ControlFreak: Python Inversion of Control" /><author><name>Mariano Cortesi (Cono)</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="30" height="32" src="http://bp2.blogger.com/_CadeoMsVIPY/R2vH6Z1s_kI/AAAAAAAAA0I/eVTX4Rlc5fg/S220/n724792106_7106.jpg" /></author><thr:total>3</thr:total><feedburner:origLink>http://engineering.zauberlabs.com/2009/04/controlfreak-python-inversion-of.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak4HRH89fCp7ImA9WxVbEUU.&quot;"><id>tag:blogger.com,1999:blog-7870515310189033933.post-3867176819211100060</id><published>2009-03-25T11:08:00.007-03:00</published><updated>2009-03-27T18:22:15.164-03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-27T18:22:15.164-03:00</app:edited><title>[RELEASE] Zauber Commons 3.10</title><content type="html">&lt;p&gt;If you are using Zauber Commons (our java components), you may be interested on the new version: 3.10. This release may not be  compatible with the 3.8/3.9 version.
 &lt;/p&gt;
 
 &lt;dl&gt;
   &lt;dt&gt;Global Notes:&lt;/dt&gt;
   &lt;dd&gt;
     &lt;ul class="lista"&gt;
      &lt;li&gt;new modules: &lt;em&gt;commons-web-transformation&lt;/em&gt; and &lt;em&gt;commons-wicket&lt;/em&gt;&lt;/li&gt;
      &lt;li&gt;The upgrade from older version might require supervision. Some transitive dependencies might be missing. (zauber commons changed some dependency versions)&lt;/li&gt;
      &lt;li&gt;You need to upgrade from log4j 1.2.8 to 1.2.14. We suggest to upgrade your application (this is required if you use commons-repository). Change your pom:   &lt;pre name="code" class="html"&gt;
           &lt;dependency&gt;
             &lt;groupId&gt;log4j&lt;/groupId&gt;
             &lt;artifactId&gt;log4j&lt;/artifactId&gt;
             &lt;version&gt;1.2.15&lt;/version&gt;
             &lt;exclusions&gt;
                &lt;exclusion&gt;
                  &lt;groupId&gt;javax.mail&lt;/groupId&gt;
                  &lt;artifactId&gt;mail&lt;/artifactId&gt;
                &lt;/exclusion&gt;
                &lt;exclusion&gt;
                  &lt;groupId&gt;javax.jms&lt;/groupId&gt;
                  &lt;artifactId&gt;jms&lt;/artifactId&gt;
                &lt;/exclusion&gt;
                &lt;exclusion&gt;
                  &lt;groupId&gt;com.sun.jmx&lt;/groupId&gt;
                  &lt;artifactId&gt;jmxri&lt;/artifactId&gt;
                &lt;/exclusion&gt;
                &lt;exclusion&gt;
                  &lt;groupId&gt;com.sun.jdmk&lt;/groupId&gt;
                  &lt;artifactId&gt;jmxtools&lt;/artifactId&gt;
                &lt;/exclusion&gt;
             &lt;/exclusions&gt;
            &lt;/dependency&gt;
&lt;/pre&gt;&lt;/li&gt;
     &lt;/ul&gt;
 
    &lt;/dd&gt;
 
   &lt;dt&gt;Changelog:&lt;/dt&gt;
   &lt;dd&gt;
     &lt;ul class="lista"&gt;
        &lt;li&gt;&lt;em&gt;commons-doxia:&lt;/em&gt;
            &lt;ul class="lista"&gt;
               &lt;li&gt;This module aims to provide functionality related to the transformation of &lt;em&gt;html/xml&lt;/em&gt; content.&lt;/li&gt;
               &lt;li&gt;So far we've implemented the &lt;em&gt;XmlSanitizer&lt;/em&gt; interface, the purpose of which is to parse a dom tree and "sanitize" the dangerous nodes.&lt;/li&gt;
               &lt;li&gt;The only implementation of &lt;em&gt;XmlSanitizer&lt;/em&gt; available at this time is &lt;em&gt;DeletingElementNodeSanitizer&lt;/em&gt;. It deletes element/attribute nodes considered invalid. In order to do this it requires a &lt;em&gt;TagSecutrityStrategy&lt;/em&gt;, implemented by &lt;em&gt;HashMapTagSecurityStrategy&lt;/em&gt;.&lt;/li&gt;
               &lt;li&gt;&lt;em&gt;XmlSanitizerTest&lt;/em&gt; provides an example of how to use this functionality.&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/li&gt;
          &lt;li&gt;&lt;em&gt;commons-web-wicket:&lt;/em&gt;
               &lt;ul class="lista"&gt;
                  &lt;li&gt;we start to detect reusable classes across wicket projects:&lt;em&gt;DynamicDetachableModel&lt;/em&gt;, &lt;em&gt;RepositoryDynamicDetachableModel&lt;/em&gt;, &lt;em&gt;ConfirmLink&lt;/em&gt;&lt;/li&gt;
               &lt;/ul&gt;
          &lt;/li&gt;
                 &lt;li&gt;&lt;em&gt;commons-doxia:&lt;/em&gt;
           &lt;ul class="lista"&gt;
              &lt;li&gt;upgrade to doxia 1.1 (http://jira.codehaus.org/secure/ReleaseNote.jspa?version=13617&amp;styleName=Html&amp;projectId=10780)&lt;/li&gt;
           &lt;/ul&gt;
          &lt;/li&gt;


         &lt;li&gt;&lt;em&gt;commons-spring:&lt;/em&gt;
           &lt;ul class="lista"&gt;
              &lt;li&gt;remove unused dependency: &lt;em&gt;org.springframework:spring-webmvc-struts&lt;/em&gt;&lt;/li&gt;
           &lt;/ul&gt;
          &lt;/li&gt;





         &lt;li&gt;&lt;em&gt;commons-web-utils:&lt;/em&gt;
           &lt;ul class="lista"&gt;
              &lt;li&gt;new filter (&lt;em&gt;NullFilter&lt;/em&gt;) that does nothing. usefull for conditional configuration of filters. for example in this example, depending on a property we activate/deactivate a caching filter depending on a flag:   &lt;pre name="code" class="html"&gt;
      &amp;lt;bean name="anunciosServletCache" class="ar.com.zauber.commons.spring.beans.factory.SwitchConditionalFactoryBean"&amp;gt;
            &amp;lt;property name="caseBlocks"&amp;gt;
                &amp;lt;list&amp;gt;
                    &amp;lt;bean class="ar.com.zauber.commons.spring.beans.factory.impl.BooleanPropertyCaseBlock"&amp;gt;
                        &amp;lt;constructor-arg index="0" value="${bar.cache.active}"/&amp;gt;
                        &amp;lt;constructor-arg index="1"&amp;gt;
                            &amp;lt;bean class="com.foo.bar.web.filters.AnunciosCacheFilter"&amp;gt;
                                &amp;lt;constructor-arg index="0" ref="anunciosCacheManager"/&amp;gt;
                                &amp;lt;constructor-arg index="1" value="anuncios"/&amp;gt;
                                &amp;lt;constructor-arg index="2" ref="seoStrategy"/&amp;gt;
                                &amp;lt;constructor-arg index="3" ref="pagingHelper"/&amp;gt;
                                &amp;lt;constructor-arg index="4" ref="commonsWebUtilsVersionProvider"/&amp;gt;
                                &amp;lt;constructor-arg index="5" ref="lastModificationEntities"/&amp;gt;
                            &amp;lt;/bean&amp;gt;
                        &amp;lt;/constructor-arg&amp;gt;
                    &amp;lt;/bean&amp;gt;
                    &amp;lt;bean class="ar.com.zauber.commons.spring.beans.factory.impl.DefaultCaseBlock"&amp;gt;
                        &amp;lt;constructor-arg index="0"&amp;gt;
                            &amp;lt;bean class="ar.com.zauber.commons.web.filter.NullFilter"/&amp;gt;
                        &amp;lt;/constructor-arg&amp;gt;
                    &amp;lt;/bean&amp;gt;
                &amp;lt;/list&amp;gt;
            &amp;lt;/property&amp;gt;
        &amp;lt;/bean&amp;gt;
    &lt;/pre&gt;&lt;/li&gt;
           &lt;/ul&gt;
          &lt;/li&gt;
          
          
          
          &lt;li&gt;&lt;em&gt;commons-repository:&lt;/em&gt;
           &lt;ul class="lista"&gt;
              &lt;li&gt;upgrade from hibernate 3.2.x to 3.3.1 (this is the lastest stable version. also it is the version that will be used with spring 3.x).  The changes that repository user need to take in consideration:
                  &lt;ul class="lista"&gt;
                    &lt;li&gt;Hibernate migration guide http://www.hibernate.org/250.html#A51 &lt;/li&gt;
                    &lt;li&gt;If you want to ehcache 2nd level cache you need to add   &lt;pre name="code" class="html"&gt;&amp;lt;dependency&amp;gt;
                    &amp;lt;groupId&amp;gt;org.hibernate&amp;lt;/groupId&amp;gt;
                    &amp;lt;artifactId&amp;gt;hibernate-ehcache&amp;lt;/artifactId&amp;gt;
                    &amp;lt;version&amp;gt;3.3.1.GA&amp;lt;/version&amp;gt;
                    &amp;lt;/dependency&amp;gt;&lt;/pre&gt;&lt;/li&gt;
                  &lt;/ul&gt;
              &lt;/li&gt;
              &lt;li&gt;repository now has the ability to group by and apply an agregate function at the same time. This is usefull to lazy load entities and know how many entities are in the query:    &lt;pre name="code" class="html"&gt;
        final Query/lt;DireccionDummy&amp;gt; query = 
            new SimpleQuery&amp;lt;DireccionDummy&amp;gt;(DireccionDummy.class, 
                new NullFilter(), null,  new Ordering(Collections.emptyList()));
        AggregateFunction function = new CompositeAggregateFunction(
                Arrays.asList(new AggregateFunction[]{
                        new CountPropertyAggregateFunction("numero"),
                        new GroupPropertyAggregateFilter("direccion"),
                        new GroupPropertyAggregateFilter("numero"),
                }));
        
         for(Object row: repository.aggregate(query, function, List.class)) {
             final Object [] fields = (Object[]) row;
             System.out.println("frequency: " + fields[0] + " | direccion:  " + fields[1] + "numero:  " + fields[2]);
         }
&lt;/pre&gt;
              &lt;/li&gt;
              &lt;li&gt;Another implementation of &lt;em&gt;Value&lt;/em&gt; called  &lt;em&gt;PropertyValue&lt;/em&gt;  that allows queries that have to compare it's  properies. For example &lt;em&gt;select Person where length &amp;gt; age&lt;/em&gt;. For example:  &lt;pre name="code" class="html"&gt;
        final Query&amp;lt;PersonaDummy&amp;gt; q1 =
            new SimpleQuery&amp;lt;PersonaDummy&amp;gt;(
                    PersonaDummy.class, new EqualsPropertyFilter("id", 
                            new PropertyValue("id")), null, null);


        assertEquals(Integer.valueOf(6), 
                repository.aggregate(q1, new RowCountAggregateFilter(), Integer.class));
&lt;/pre&gt;&lt;/li&gt;
              &lt;li&gt;new Hibernate interceptor used to inject dependencies from a spring context to achieve a Domain Driven Design. It is called =SpringInjectionInterceptor=. The classes wishing being injected with this interceptor, must be annotated with the annotation =@Configurable= And each field that will be injected must be transient and annotated with &lt;em&gt;@Qualifier&lt;/em&gt;.The qualifier name can be used to set the bean name (else it uses the field &lt;em&gt;name&lt;/em&gt;). For example:   &lt;pre name="code" class="html"&gt;
@Entity
@Configurable
public class DomainEntityExample implements Persistible {
    @Id
    private Long id;

    @Qualifier(value = "someService")
    private transient SomeService service;
    @Qualifier
    private transient SomeService someService;
    ...

    private DomainEntityExample() {
       // hibernate's
    }

    public DomainEntityExample(SomeService service, SomeService someService) {
        .....
        this.service = service;
        this.someService = someService;
    }
    public final SomeService getService() {
        return service;
    }
    public final SomeService getSomeService() {
        return someService;
    }
    ....
}
&lt;/pre&gt; We also provide a &lt;em&gt;SpringInjectionHibernateAuditLoggerInterceptor&lt;/em&gt; that combines the &lt;em&gt;HibernateAuditLoggerInterceptor&lt;/em&gt; with &lt;em&gt;SpringInjectionInterceptor&lt;/em&gt; (hibernate only let you specify only one interceptor) enhance &lt;em&gt;SpringInjectionInterceptor&lt;/em&gt; (the interceptor that inject dependencies to hibernates entities). If the annotated bean implements &lt;em&gt;InitializingBean&lt;/em&gt;, the &lt;em&gt;afterPropertiesSet&lt;/em&gt; is called for post configuring settings.
              &lt;/li&gt;
            
           &lt;/ul&gt;
          &lt;/li&gt;
      &lt;/ul&gt;
    &lt;/dd&gt;
    &lt;dt&gt;Known Bugs&lt;/dt&gt;
    &lt;dd&gt;None known at this time&lt;/dd&gt;
    &lt;dt&gt;How to use it&lt;/dt&gt;
    &lt;dd&gt;
 &lt;p&gt;There isn't a site with tutorials or formal documentation for Zauber Commons yet, but we are working on that. For now you can browse the source at the SVN repository &lt;a href="https://code.zauber.com.ar/repos/sandbox/components/commons/code/trunk/"&gt;https://code.zauber.com.ar/repos/sandbox/components/commons/code/trunk/&lt;/a&gt;. Also you can use Zauber Commons with a &lt;a href="http://maven.apache.org/"&gt;Maven 2&lt;/a&gt;:
 
 &lt;pre name="code" class="html"&gt;  &amp;lt;repositories&amp;gt;
     &amp;lt;repository&amp;gt;
       &amp;lt;id&amp;gt;zauber-code-releases&amp;lt;/id&amp;gt;
       &amp;lt;name&amp;gt;public zauber repository&amp;lt;/name&amp;gt;
       &amp;lt;url&amp;gt;https://repo1.zauber.com.ar/zauber/code/releases&amp;lt;/url&amp;gt;
       &amp;lt;releases&amp;gt;&amp;lt;enabled&amp;gt;true&amp;lt;/enabled&amp;gt;&amp;lt;/releases&amp;gt;
       &amp;lt;snapshots&amp;gt;&amp;lt;enabled&amp;gt;false&amp;lt;/enabled&amp;gt;&amp;lt;/snapshots&amp;gt;
     &amp;lt;/repository&amp;gt;
     &amp;lt;repository&amp;gt;
       &amp;lt;id&amp;gt;zauber-code-snapshots&amp;lt;/id&amp;gt;
       &amp;lt;name&amp;gt;public zauber repository&amp;lt;/name&amp;gt;
       &amp;lt;url&amp;gt;https://repo1.zauber.com.ar/zauber/code/snapshots&amp;lt;/url&amp;gt;
       &amp;lt;releases&amp;gt;&amp;lt;enabled&amp;gt;false&amp;lt;/enabled&amp;gt;&amp;lt;/releases&amp;gt;
       &amp;lt;snapshots&amp;gt;&amp;lt;enabled&amp;gt;true&amp;lt;/enabled&amp;gt;&amp;lt;/snapshots&amp;gt;
     &amp;lt;/repository&amp;gt;
   &amp;lt;/repositories&amp;gt;   
 &lt;/pre&gt;
 
 And for example add a dependency to your project
 
  &lt;pre name="code" class="html"&gt;  &amp;lt;dependency&amp;gt;
    &amp;lt;groupId&amp;gt;ar.com.zauber.commons.web&amp;lt;/groupId&amp;gt;
    &amp;lt;artifactId&amp;gt;commons-web-version&amp;lt;/artifactId&amp;gt;
    &amp;lt;version&amp;gt;${commons.version}&amp;lt;/version&amp;gt;
  &amp;lt;/dependency&amp;gt;&lt;/pre&gt;
 &lt;/p&gt;
 &lt;/dd&gt;
    &lt;dt&gt;Diffstat&lt;/dt&gt;
    &lt;dd&gt;&lt;pre&gt; auth/password/pom.xml                                                                                                               |    6 
 commons/pom.xml                                                                                                                     |    6 
 dao/src/test/java/ar/com/zauber/commons/dao/OrderTest.java                                                                          |   16 
 exception/pom.xml                                                                                                                   |    7 
 facebook/pom.xml                                                                                                                    |    1 
 jetty-launcher/pom.xml                                                                                                              |    6 
 message/impl/pom.xml                                                                                                                |    7 
 pom.xml                                                                                                                             |   83 +++
 repository/api/src/main/java/ar/com/zauber/commons/repository/query/aggreate/GroupPropertyAggregateFilter.java                      |   30 +
 repository/api/src/main/java/ar/com/zauber/commons/repository/query/filters/BeginsLikePropertyFilter.java                           |    8 
 repository/api/src/main/java/ar/com/zauber/commons/repository/query/filters/ContainsLikePropertyFilter.java                         |    8 
 repository/api/src/main/java/ar/com/zauber/commons/repository/query/filters/EndsLikePropertyFilter.java                             |    8 
 repository/api/src/main/java/ar/com/zauber/commons/repository/query/filters/EqualsPropertyFilter.java                               |    6 
 repository/api/src/main/java/ar/com/zauber/commons/repository/query/filters/ExactLikePropertyFilter.java                            |    8 
 repository/api/src/main/java/ar/com/zauber/commons/repository/query/filters/GreaterThanEqualsPropertyFilter.java                    |    7 
 repository/api/src/main/java/ar/com/zauber/commons/repository/query/filters/GreaterThanPropertyFilter.java                          |    7 
 repository/api/src/main/java/ar/com/zauber/commons/repository/query/filters/LessThanEqualsPropertyFilter.java                       |    7 
 repository/api/src/main/java/ar/com/zauber/commons/repository/query/filters/LessThanPropertyFilter.java                             |    7 
 repository/api/src/main/java/ar/com/zauber/commons/repository/query/filters/LikePropertyFilter.java                                 |    8 
 repository/api/src/main/java/ar/com/zauber/commons/repository/query/values/PropertyValue.java                                       |   42 +
 repository/api/src/main/java/ar/com/zauber/commons/repository/query/values/SimpleValue.java                                         |   17 
 repository/impl/entities/pom.xml                                                                                                    |    1 
 repository/impl/spring-hbm/pom.xml                                                                                                  |   39 +
 repository/impl/spring-hbm/src/main/java/ar/com/zauber/commons/repository/SpringHibernateRepository.java                            |    4 
 repository/impl/spring-hbm/src/main/java/ar/com/zauber/commons/repository/aggregate/ProjectionAggregateFunctionVisitor.java         |    3 
 repository/impl/spring-hbm/src/main/java/ar/com/zauber/commons/repository/query/visitor/CriteriaFilterVisitor.java                  |  102 ++--
 repository/impl/spring-hbm/src/main/java/ar/com/zauber/commons/repository/usertypes/URLUserType.java                                |  163 +++++++
 repository/impl/spring-hbm/src/main/java/ar/com/zauber/commons/repository/utils/SpringInjectionHibernateAuditLoggerInterceptor.java |   52 ++
 repository/impl/spring-hbm/src/main/java/ar/com/zauber/commons/repository/utils/SpringInjectionInterceptor.java                     |  217 ++++++++++
 repository/impl/spring-hbm/src/test/java/ar/com/zauber/commons/repository/test/model/DomainEntityExample.java                       |   82 +++
 repository/impl/spring-hbm/src/test/java/ar/com/zauber/commons/repository/test/model/SomeService.java                               |   27 +
 repository/impl/spring-hbm/src/test/java/ar/com/zauber/commons/repository/utils/SpringInjectionInterceptorTest.java                 |   77 +++
 repository/impl/spring-hbm/src/test/java/ar/com/zauber/commons/test/SpringHibernateRepositoryTest.java                              |   53 ++
 repository/impl/spring-hbm/src/test/resources/ar/com/zauber/commons/repository/utils/injection-hibernate-mapping-spring.xml         |   15 
 repository/impl/spring-hbm/src/test/resources/ar/com/zauber/commons/repository/utils/injection-hibernate-spring.xml                 |   52 ++
 repository/pom.xml                                                                                                                  |   49 --
 spring/pom.xml                                                                                                                      |   16 
 spring/src/main/java/ar/com/zauber/commons/spring/mail/NullMailSender.java                                                          |   16 
 web/pom.xml                                                                                                                         |    1 
 web/transformation/pom.xml                                                                                                          |   44 ++
 web/transformation/src/main/java/ar/com/zauber/commons/web/transformation/sanitizing/api/AttributeValueValidator.java               |   31 +
 web/transformation/src/main/java/ar/com/zauber/commons/web/transformation/sanitizing/api/TagSecutrityStrategy.java                  |   48 ++
 web/transformation/src/main/java/ar/com/zauber/commons/web/transformation/sanitizing/api/XmlSanitizer.java                          |   35 +
 web/transformation/src/main/java/ar/com/zauber/commons/web/transformation/sanitizing/impl/AbstractElementNodeSanitizer.java         |  125 +++++
 web/transformation/src/main/java/ar/com/zauber/commons/web/transformation/sanitizing/impl/DeletingElementNodeSanitizer.java         |   73 +++
 web/transformation/src/main/java/ar/com/zauber/commons/web/transformation/sanitizing/impl/HashMapTagSecurityStrategy.java           |   82 +++
 web/transformation/src/main/java/ar/com/zauber/commons/web/transformation/sanitizing/impl/HrefUrlOnlyValueValidator.java            |   41 +
 web/transformation/src/main/java/ar/com/zauber/commons/web/transformation/sanitizing/impl/StyleAlignmentOnlyValueValidator.java     |   42 +
 web/transformation/src/main/java/ar/com/zauber/commons/web/transformation/sanitizing/impl/StyleTextDecorationValueValidator.java    |   45 ++
 web/transformation/src/main/java/ar/com/zauber/commons/web/transformation/sanitizing/impl/TargetSelfBlankValueValidator.java        |   33 +
 web/transformation/src/test/java/ar/com/zauber/commons/web/transformation/sanitizing/impl/XmlSanitizerTest.java                     |  133 ++++++
 web/utils/src/main/java/ar/com/zauber/commons/web/filter/NullFilter.java                                                            |   51 ++
 wicket/impl/pom.xml                                                                                                                 |   58 ++
 wicket/impl/src/main/java/ar/com/zauber/commons/wicket/components/ConfirmLink.java                                                  |   69 +++
 wicket/impl/src/main/java/ar/com/zauber/commons/wicket/model/DynamicDetachableModel.java                                            |  107 ++++
 wicket/impl/src/main/java/ar/com/zauber/commons/wicket/model/RepositoryDynamicDetachableModel.java                                  |   93 ++++
 wicket/pom.xml                                                                                                                      |   20 
 &lt;/pre&gt;&lt;/dd&gt;
 &lt;/dl&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7870515310189033933-3867176819211100060?l=engineering.zauberlabs.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://engineering.zauberlabs.com/feeds/3867176819211100060/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://engineering.zauberlabs.com/2009/03/release-zauber-commons-310.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/3867176819211100060?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/3867176819211100060?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ZauberCode/~3/eTqungM34TA/release-zauber-commons-310.html" title="[RELEASE] Zauber Commons 3.10" /><author><name>Juan F. Codagnone</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://engineering.zauberlabs.com/2009/03/release-zauber-commons-310.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0ANQ3cyeyp7ImA9WxVaEE4.&quot;"><id>tag:blogger.com,1999:blog-7870515310189033933.post-655207439695231248</id><published>2009-02-11T22:35:00.005-02:00</published><updated>2009-04-06T14:43:12.993-03:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-06T14:43:12.993-03:00</app:edited><title>[RELEASE] Zauber Commons 3.8</title><content type="html">&lt;p&gt;If you are using Zauber Commons (our java components), you may be interested on the new version: 3.8. This is a small release. Compatible with the 3.7 version.
&lt;/p&gt;

&lt;dl&gt;
  &lt;dt&gt;Changelog:&lt;/dt&gt;
  &lt;dd&gt;
    &lt;ul class="lista"&gt;
     &lt;li&gt;&lt;em&gt;commons-spring&lt;/em&gt;
       &lt;ul class="lista"&gt;
          &lt;li&gt;&lt;em&gt;HttpPagingHelper&lt;/em&gt;: Now it is posible to use another GET parameter name to track the current page number (the default is "page)". The default value can be changed with the new method &lt;em&gt;setPageField(String)&lt;/em&gt;. &lt;/li&gt;
       &lt;/ul&gt;
      &lt;/li&gt;
    &lt;/ul&gt;   
   &lt;/dd&gt;
   &lt;dt&gt;Known Bugs&lt;/dt&gt;
   &lt;dd&gt;None known at this time&lt;/dd&gt;
   &lt;dt&gt;How to use it&lt;/dt&gt;
   &lt;dd&gt;
&lt;p&gt;There isn't a site with tutorials or formal documentation for Zauber Commons yet, but we are working on that. For now you can browse the source at the SVN repository &lt;a href="https://code.zauber.com.ar/repos/sandbox/components/commons/code/trunk/"&gt;https://code.zauber.com.ar/repos/sandbox/components/commons/code/trunk/&lt;/a&gt;. Also you can use Zauber Commons with a &lt;a href="http://maven.apache.org/"&gt;Maven 2&lt;/a&gt;:

&lt;pre name="code" class="html"&gt;  &amp;lt;repositories&amp;gt;
    &amp;lt;repository&amp;gt;
      &amp;lt;id&amp;gt;zauber-code-releases&amp;lt;/id&amp;gt;
      &amp;lt;name&amp;gt;public zauber repository&amp;lt;/name&amp;gt;
      &amp;lt;url&amp;gt;https://repo1.zauber.com.ar/zauber/code/releases&amp;lt;/url&amp;gt;
      &amp;lt;releases&amp;gt;&amp;lt;enabled&amp;gt;true&amp;lt;/enabled&amp;gt;&amp;lt;/releases&amp;gt;
      &amp;lt;snapshots&amp;gt;&amp;lt;enabled&amp;gt;false&amp;lt;/enabled&amp;gt;&amp;lt;/snapshots&amp;gt;
    &amp;lt;/repository&amp;gt;
    &amp;lt;repository&amp;gt;
      &amp;lt;id&amp;gt;zauber-code-snapshots&amp;lt;/id&amp;gt;
      &amp;lt;name&amp;gt;public zauber repository&amp;lt;/name&amp;gt;
      &amp;lt;url&amp;gt;https://repo1.zauber.com.ar/zauber/code/snapshots&amp;lt;/url&amp;gt;
      &amp;lt;releases&amp;gt;&amp;lt;enabled&amp;gt;false&amp;lt;/enabled&amp;gt;&amp;lt;/releases&amp;gt;
      &amp;lt;snapshots&amp;gt;&amp;lt;enabled&amp;gt;true&amp;lt;/enabled&amp;gt;&amp;lt;/snapshots&amp;gt;
    &amp;lt;/repository&amp;gt;
  &amp;lt;/repositories&amp;gt;   
&lt;/pre&gt;

And for example add a dependency to your project

 &lt;pre name="code" class="html"&gt;  &amp;lt;dependency&amp;gt;
   &amp;lt;groupId&amp;gt;ar.com.zauber.commons.web&amp;lt;/groupId&amp;gt;
   &amp;lt;artifactId&amp;gt;commons-web-version&amp;lt;/artifactId&amp;gt;
   &amp;lt;version&amp;gt;${commons.version}&amp;lt;/version&amp;gt;
 &amp;lt;/dependency&amp;gt;&lt;/pre&gt;

&lt;/dd&gt;
   &lt;dt&gt;Diffstat&lt;/dt&gt;
   &lt;dd&gt;&lt;pre&gt; HttpPagingHelper.java |   12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)
&lt;/pre&gt;&lt;/dd&gt;
&lt;/dl&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7870515310189033933-655207439695231248?l=engineering.zauberlabs.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://engineering.zauberlabs.com/feeds/655207439695231248/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://engineering.zauberlabs.com/2009/02/release-zauber-commons-38.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/655207439695231248?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/655207439695231248?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ZauberCode/~3/3cmQKe5-RaU/release-zauber-commons-38.html" title="[RELEASE] Zauber Commons 3.8" /><author><name>Juan F. Codagnone</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total><feedburner:origLink>http://engineering.zauberlabs.com/2009/02/release-zauber-commons-38.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEIDRHo6fCp7ImA9WxVXEk0.&quot;"><id>tag:blogger.com,1999:blog-7870515310189033933.post-3582564221758528236</id><published>2009-02-09T15:54:00.001-02:00</published><updated>2009-02-09T16:02:55.414-02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-09T16:02:55.414-02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="java" /><category scheme="http://www.blogger.com/atom/ns#" term="anemic domain model" /><category scheme="http://www.blogger.com/atom/ns#" term="software design" /><category scheme="http://www.blogger.com/atom/ns#" term="programming" /><category scheme="http://www.blogger.com/atom/ns#" term="OOP" /><category scheme="http://www.blogger.com/atom/ns#" term="object oriented programming" /><title>Java, the Anemic Domain Model and how to return to Object Oriented  Programming</title><content type="html">&lt;p&gt;
I've been working in Java for about 7 years and I've changed my mind 
about Java application design many times during this period. However, 
since 2 years ago I think the paradigm adopted to develop applications 
in my team has been pretty the same and this gives me the enough 
confidence to work without thinking much about these issues. The main 
problem I encountered during the past time was the different approaches 
and technologies (&lt;acronym title="Enterprise JavaBeans"&gt;EJBs&lt;/acronym&gt;, &lt;acronym title="Web Services"&gt;WS&lt;/acronym&gt;, &lt;acronym title="Service Oriented Architecture"&gt;SOA&lt;/acronym&gt;, etc). The thing is that none of them gave good guidelines of how to do a good design and addressed mainly 
performance, portability, interoperability among other issues.
&lt;/p&gt;
&lt;p&gt;
As I said, the big problem here was that good desing guidelines were not 
given and I think most of the people working in Java appeared to forget 
that they were working in a Object Oriented Paradigm. In consequence, 
almost every Java application that I encountered was designed in a 
procedural way with most of the logic spreading along the different 
services of the application. This may be a good way to address the low 
coupling and high cohesion concerns but it throws away most of the 
object oriented paradigm benefits, such as inheritance, encapsulation 
and ease of re-usability.
&lt;/p&gt;

&lt;p&gt;
The problem is not entirely of the people that work in Java, but also of 
the language itself that made difficult to use the paradigm correctly 
mainly because of the big differences between objects and classes that 
the language has (in more OO languages like Smalltalk everything is an 
object, classes are objects).
&lt;/p&gt;
&lt;p&gt;
Furthermore, with the proliferation of &lt;acronym title="Inversion of control"&gt;IoC&lt;/acronym&gt; containers (&lt;a href="http://www.springsource.org/about"&gt;Spring&lt;/a&gt;, &lt;a href="http://www.picocontainer.org/"&gt;Pico 
Container&lt;/a&gt;, &lt;a href="http://code.google.com/p/google-guice/"&gt;Guice&lt;/a&gt;, etc), injecting dependencies to services that will be 
injected to controllers or managers became a commodity in this kind of 
applications and Services were converted in the Kings of Objects, 
leaving the Domain Objects very anemic only working as C &lt;tt&gt;struct&lt;/tt&gt;s or 
simply Database representation of the Model. As I said before, this kind 
of design is much less Object Oriented than having real domain objects 
that concentrates their responsibilities and delegates what doesn't 
concerns them, in other words, a truly object oriented system.
&lt;/p&gt;

&lt;p&gt;
Studing Smalltalk and &lt;a href="http://python.org/"&gt;Python&lt;/a&gt;, but also trying to find out a better way 
to program in Java made me realize that the best thing I could do was to 
return to the object oriented way of programming and designing software 
according to this paradigm. At this point some concerns came along, due 
to the nature of the language is not so easy to convert the domain 
objects in first class citizens of a system as it should have been always.
&lt;/p&gt;

&lt;p&gt;
There are some ways to overcome this problem, but I explored 2 with 
great success. The first one is to have Factories for non database 
objects that need some injection in order to provide them with all the 
dependencies they should have complemented with &lt;acronym title="Data Access Object"&gt;DAOs&lt;/acronym&gt; or Generic DAOs 
(a.k.a. Repositories) that also injects those domain objects that comes 
from the database. The other way is to use the &lt;acronym title="Aspect-oriented programming"&gt;AOP&lt;/acronym&gt; features of the 
language and inject those domain objects hanging some VM calls. This is 
a much more advanced technique and I will address the full explanation 
of how to do this in Java using Spring, &lt;a href="http://www.hibernate.org/"&gt;Hibernate&lt;/a&gt; and the &lt;a href="http://www.eclipse.org/aspectj/"&gt;AspectJ&lt;/a&gt; in a later article.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7870515310189033933-3582564221758528236?l=engineering.zauberlabs.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://engineering.zauberlabs.com/feeds/3582564221758528236/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://engineering.zauberlabs.com/2009/02/java-anemic-domain-model-and-how-to_09.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/3582564221758528236?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/3582564221758528236?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ZauberCode/~3/x8i6hDDegUk/java-anemic-domain-model-and-how-to_09.html" title="Java, the Anemic Domain Model and how to return to Object Oriented  Programming" /><author><name>Martín Andrés Márquez</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total><feedburner:origLink>http://engineering.zauberlabs.com/2009/02/java-anemic-domain-model-and-how-to_09.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C08DQHw7fCp7ImA9WxVQGU4.&quot;"><id>tag:blogger.com,1999:blog-7870515310189033933.post-4767908719732941591</id><published>2009-01-28T15:40:00.022-02:00</published><updated>2009-02-06T12:51:11.204-02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-06T12:51:11.204-02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="about" /><category scheme="http://www.blogger.com/atom/ns#" term="blogger" /><category scheme="http://www.blogger.com/atom/ns#" term="welcome" /><title>How we created this blog</title><content type="html">We believe the best way to inaugurate it is talking about how we created it:
&lt;dl&gt;
&lt;dt&gt;Why are we using Blogger as engine?&lt;/dt&gt;
&lt;dd&gt;We are using Blogger because it was the simplest solution for us. Wordpress doesn't support PostgreSQL and Drupal seems too big for what we need&lt;/dd&gt;
&lt;dt&gt;What widgets are we using?&lt;/dt&gt;
&lt;dd&gt;&lt;ul class="lista"&gt;&lt;li&gt;We are using &lt;a href="http://fazibear.blogspot.com/2007/09/blogger-syntax-higlighter.html"&gt;Syntax Highlighter&lt;/a&gt;. Code snippets will be an important part of this blog and for that reason, they should be usable and look well.&lt;/li&gt;&lt;li&gt;We've implemented &lt;a href="http://en.wikipedia.org/wiki/SIFR"&gt;sIFR&lt;/a&gt; to replace some titles fonts, &lt;a href="http://infodotnet.blogspot.com/2007/12/tips-sifr-custom-fonts-for-blogger.html"&gt;following this tutorial&lt;/a&gt;.&lt;/li&gt;&lt;li&gt;Last but not least, we've used Twitter's official badge to add our tweets to the sidebar. More information about it &lt;a href="http://buzz.blogger.com/2007/07/twitter-badge-for-blogger.html"&gt;here&lt;/a&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;/dd&gt;
&lt;dt&gt;What about the template?&lt;/dt&gt;
&lt;dd&gt;Well... we started with the simplest template we found: Minima, created by &lt;a href="http://stopdesign.com/portfolio/web/blogger-templates.html?fs=1"&gt;Douglas Bowman&lt;/a&gt;, but we've changed it a lot.&lt;/dd&gt;
&lt;/dl&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7870515310189033933-4767908719732941591?l=engineering.zauberlabs.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://engineering.zauberlabs.com/feeds/4767908719732941591/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://engineering.zauberlabs.com/2009/01/hello-world.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/4767908719732941591?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/4767908719732941591?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ZauberCode/~3/N1kiJCjiGGE/hello-world.html" title="How we created this blog" /><author><name>Damian Calderon</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="32" height="31" src="http://4.bp.blogspot.com/_toYKT_ESrww/SX4g1RhqORI/AAAAAAAAAAc/9sz9UDtOnUY/S220/damian_mini.png" /></author><thr:total>0</thr:total><feedburner:origLink>http://engineering.zauberlabs.com/2009/01/hello-world.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0ENR38zfyp7ImA9WxVQGU4.&quot;"><id>tag:blogger.com,1999:blog-7870515310189033933.post-2678541209343520525</id><published>2009-01-21T12:03:00.001-02:00</published><updated>2009-02-06T12:48:16.187-02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-06T12:48:16.187-02:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="about" /><title>¡Hello world!</title><content type="html">&lt;p&gt;

At &lt;a href="http://www.zauber.com.ar/"&gt;Zauber&lt;/a&gt;, every day we deliver solutions and bytes that solves our customers problems. We created this blog, as a place where all Zauberins can share with the community some findings, tips, and experimental projects we develop.
&lt;/p&gt;
&lt;p&gt;Stay tunned!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7870515310189033933-2678541209343520525?l=engineering.zauberlabs.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://engineering.zauberlabs.com/feeds/2678541209343520525/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://engineering.zauberlabs.com/2009/01/hello-world_21.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/2678541209343520525?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/7870515310189033933/posts/default/2678541209343520525?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/ZauberCode/~3/DPbclc2DnA8/hello-world_21.html" title="¡Hello world!" /><author><name>Juan F. Codagnone</name><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total><feedburner:origLink>http://engineering.zauberlabs.com/2009/01/hello-world_21.html</feedburner:origLink></entry></feed>

