tag:blogger.com,1999:blog-48066407902056838242009-07-13T20:01:25.093-07:00Antagonistic PleiotropyThe waterfall only goes one way: down!Daniel Bastos Aragaohttp://www.blogger.com/profile/14224933549638075286noreply@blogger.comBlogger20125tag:blogger.com,1999:blog-4806640790205683824.post-18520070971581591682008-09-20T06:26:00.000-07:002008-09-20T06:42:43.407-07:00Yet Another Validator<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_8kJd-8eQ_1w/SNT8xVwQ0hI/AAAAAAAAAJk/Qif-AMWfOUU/s1600-h/big_tick.jpg"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://4.bp.blogspot.com/_8kJd-8eQ_1w/SNT8xVwQ0hI/AAAAAAAAAJk/Qif-AMWfOUU/s200/big_tick.jpg" alt="" id="BLOGGER_PHOTO_ID_5248097390376833554" border="0" /></a>Sick of writing validators? Sick of XML? Sick of framework specific validation? Sick of complex formats and extra stuff you never use? Well, I was too and now I've outsourced something that might help you too reducing these pains.<br />Check out <a href="http://sourceforge.net/projects/y-a-v/">YAV</a>.<br />YAV is a simple, framework independent, lightweight Java validation tool. It applies validations directly to domain models through annotations. It checks for mandatoriness, email, range and regex. If you need, create your own methods to perform more complex validations. It is JSR-303 non-compliant - thank goodness :)<br />Currently integrates nicely with Spring2.5, Struts2 is on the way.<br />It also has ValidationTestCases that minimize annoyingly repetitive testing tasks.<br />As always, there are a few edges to trim, but it works.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4806640790205683824-1852007097158159168?l=antagonisticpleiotropy.blogspot.com'/></div>Daniel Bastos Aragaohttp://www.blogger.com/profile/14224933549638075286noreply@blogger.com0tag:blogger.com,1999:blog-4806640790205683824.post-5886399086931970702008-08-11T01:45:00.000-07:002008-08-11T02:04:07.577-07:00Momentary Autism and Business Blindness on Software Development<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_8kJd-8eQ_1w/SKAAX53xxRI/AAAAAAAAAJU/ZEJS4bGz0vA/s1600-h/police.jpg"><img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_8kJd-8eQ_1w/SKAAX53xxRI/AAAAAAAAAJU/ZEJS4bGz0vA/s400/police.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5233183177676277010" /></a><br />I finished reading Blink a couple of weeks ago and the anecdotes keep on coming back to me all the time. The book has several support stories for the author’s arguments and in general they are very well constructed. There is one in especial that is closely related to software development. It is the one that talks about how police officers get into a state of momentary autism on situations of extreme pressure. Far from me saying that software developers are under the gun in the same fashion as police people, but there are similarities.<br /><br />In the book Gladwell discusses why highly trained professionals can bluntly fail to recognize true danger. The most probable reason is that once inside of complex situations the human mind tends to fail intercepting external stimuli. He suggests that a way to avoid getting caught on such mind blanking traps is to repeat safety steps. Most people can handle complex situations but few know how to avoid creating them in the first place. In software production, frequent codebase commits and updates, rigorous test writing (preferably in TDD way) and the use a continuous fast build are as important as keeping a gun away from suspects or holding the torch with the weak hand. If the process provides safety use it always.<br /><br />In his research Gladwell found that police officers working in pairs do things differently than those working alone. Actually partners tend to speed up when working together. For the police speed can be bad because failing to correctly interpret signals in life threatening situations may be disastrous. Software, on the other hand, needs to be produced quickly, so let’s pair. Developers working together are more confident and like police officers tend to be bolder and charge more. It's a pity that police doesn’t have test frameworks to find out if the suspect was holding a gun or a wallet by the time they decided to open fire.<br /><br />The autistic condition reported by officers has striking resemblance with the business blindness that plagues developers. Officers say that the fear of gunfire is such that they react without considering external factors. They are trained gunmen but the last thing they want is to fire a gun. Don’t go on writing code unless you know it has business value. It is every developer’s job to challenge requirements for purpose and need. Don’t allow yourself into a condition where everything is self-justified. Don’t use your experience to simply write more code instead make sure that every line delivers value.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4806640790205683824-588639908693197070?l=antagonisticpleiotropy.blogspot.com'/></div>Daniel Bastos Aragaohttp://www.blogger.com/profile/14224933549638075286noreply@blogger.com1tag:blogger.com,1999:blog-4806640790205683824.post-42667266390786563872008-07-26T00:58:00.002-07:002008-07-26T01:44:47.925-07:00This is a list of things to note when developing Rails/JRuby applications that will be deployed to java web containers such as Tomcat, WebSphere <span style="font-style: italic;">et alli</span>. It's obviously incomplete but it is much longer than I thought it would be when I first started.<br /><ul><li><span style="font-style: italic;">RAILS_ROOT</span> becomes the context therefore your traditional Rails folders aren't where you'd expect them to be. In a java container the public area is usually context's root. Warbler helps be copying the files from the application's Rails public folder and you can also modify how it packs the app by changing the entries in warbler.rb.</li><li>Rails caching usually depends on where public files are and things tend to go bezerk unless you set where the public folder lives. So, place this in your environment.rb: <span style="font-style: italic;">Rails.public_path="#{RAILS_ROOT}/.."</span><br /></li><li>Try to stick to one interpreter only. It's quite confusing managing dependencies and versions when having too many rubys installed, and it's very easy to end up with:<br /></li></ul><ol><li>the IDE's JRuby</li><li>the JRuby you installed</li><li>the JRuby that comes with warbler</li><li>the C-ruby install</li></ol><ul><li>Assuming the app will run in JRuby prefer NOT to use a C-ruby interpreter at all, not even in development. This doesn't necessarily means giving up Mongrel/Webrick. Java containers won't refresh changes to view files so it is very handy to use Mongrel/Webrick for the minor css/html changes, otherwise you'll loose rails quick feedback cycle.</li><li>Make sure that the version you're developing in is the same the app will be running when in production.<br /></li><li>Don't use warbler's (v. 0.9.9) JRuby version (1.1.1) it will most certainly cause you grief. Delete it from the installed GEM and get the latest <a href="http://repository.codehaus.org/org/jruby/jruby-complete">jruby-complete.jar</a>, then place it in the lib directory so warbler picks it up when packing the war.</li><li>Check <span style="font-style: italic;">config.webxml.rails.env</span> in <span style="font-style: italic;">warble.rb</span> to make sure the warbled app is configured with the environment you want it to be. This variable creates an entry in the generated web.xml that defines which <span style="font-style: italic;">RAILS_ENV</span> will be executed. </li><li>JDBC adapters seem to be a problem still. When running RSpec the <span style="font-style: italic;">test</span> environment crashes because <span style="font-style: italic;">recreate-database</span> method isn't implemented yet. It seems that Derby is the only one fully implemented.</li><li>Gems dependencies (Rails 2.1) aren't working properly. It seems that it has issues with java gems. I failed to install/unpack hpricot and activerecord-jdbc. So use other ways to freeze gems into the project. Don't forget to use <span style="font-style: italic;">config.load_paths</span> to tell where the gems are in relation to the app in the java container.<br /></li><li>Deploy as frequently as possible to the target java container to avoid surprises. I can assure you that there will bad surprises if you don't do it.</li><li>Autotest (<a href="http://www.zenspider.com/ZSS/Products/ZenTest/">ZenTest</a>) doesn't seem to like the <span style="font-style: italic;">script/spec</span> command. A cheap way to overcome this is to create a softlink called <span style="font-style: italic;">script</span> in JRuby's bin directory that points to the bin directory itself.</li><li>I'm using <a href="http://www.h2database.com/">H2</a> (file based) in development and it is a cool database but there is one annoyance in Windows. Windows locks H2 log file even if the connection is explicitly saying that it shouldn't - <span style="font-style: italic;">url: jdbc:h2:file:db/development;FILE_LOCK=NO</span>. In Linux/MacOS it behaves properly.</li><li>JNDI resources are available for databases only, if you need to grab a hold of other JNDI resources some code has to be cooked to do the lookup. I wrote this very <a href="http://antagonisticpleiotropy.blogspot.com/2008/06/reading-jndi-resources-in-jruby.html">simple JNDI adapter</a>.</li><li>Let database adapters do their jobs, it's a little more code but it guarantees you won't run into type conversion problems. For instance:</li></ul><ol><li>GOOD -><span style="font-style: italic;"> Person.find_by_name name, :conditions => ["alive = :breathing", {:breathing => true}] </span></li><li>BAD -><span style="font-style: italic;"> Person.find_by_name name, :conditions => ["alive = true"]</span></li></ol><ul><li>Use <a href="http://svn.rubyonrails.org/rails/plugins/exception_notification/">Exception Notification</a>. It provides a very nice snapshot of the state of affairs and you'll need it.</li><li>Use <a href="http://haml.hamptoncatlin.com/">HAML</a>, it really makes things simpler. This not a JRuby thing but a still a good recommendation.</li><li>Pay attention to links. Strive to use rails resolvers to create links and urls, as traditionally, in a java container you'll usually have a context. In regular rails it looks like this: <span style="font-style: italic;">http://localhost:3000/persons</span> and in java-land most likely this: <span style="font-style: italic;">http://localhost:8080/appName/persons</span></li><li>Netbeans 6.1 made me smile after frustrated weeks using <a href="http://www.aptana.org">Aptana</a> and <a href="http://www.e-texteditor.com/">E</a>. I know IDE's are religious war starters but this is my take on it. Netbeans works the others don't.<br /></li><li>If possible prefer NOT to develop in Windows, especially because it is definitely much slower. If you must use Cygwin. BTW there is this cool tool called <a href="http://software.jessies.org/terminator/">Terminator</a>, it keeps all terminals together in tabs.</li><li>I had problems making controllers see some modules. More specifically cache sweeping. In my controller I had to add these 2 lines, or it doesn't work:<br /></li></ul><ol style="font-style: italic;"><li>require File.expand_path("#{RAILS_ROOT}/vendor/rails/actionpack/lib/action_controller/caching/sweeping") unless defined? cache_sweeper</li><li>include ActionController::Caching unless defined? cache_sweeper</li></ol><ul><li>Protect from forgery has problems with WebSphere. It always complains about the generated tokens not been compatible. Is any one using it?<br /></li></ul><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4806640790205683824-4266726639078656387?l=antagonisticpleiotropy.blogspot.com'/></div>Daniel Bastos Aragaohttp://www.blogger.com/profile/14224933549638075286noreply@blogger.com0tag:blogger.com,1999:blog-4806640790205683824.post-50294204392048033552008-06-24T05:46:00.001-07:002008-06-24T06:10:24.162-07:00Slight difference on defined? resultsSome piece of ruby logic was depending on a <span style="font-style: italic;">defined?</span> check to identify <span style="font-style: italic;">local-variable</span>s. It was working fine in C-Ruby but it failed when ported to JRuby.<br />So what we found out was that the <span style="font-style: italic;">defined?</span> keywork/method/check/thingy in JRuby gives a slightly different response.<br />Try it out. In your terminal bring up <span style="font-style: italic;">irb</span> and type:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_8kJd-8eQ_1w/SGDvhGaOhDI/AAAAAAAAAI0/U5wUsO-KC30/s1600-h/irb.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_8kJd-8eQ_1w/SGDvhGaOhDI/AAAAAAAAAI0/U5wUsO-KC30/s400/irb.png" alt="" id="BLOGGER_PHOTO_ID_5215431720430371890" border="0" /></a><br />Then try it with Jruby:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_8kJd-8eQ_1w/SGDvxgcCUVI/AAAAAAAAAI8/TE4of5ve0bw/s1600-h/jruby-irb.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_8kJd-8eQ_1w/SGDvxgcCUVI/AAAAAAAAAI8/TE4of5ve0bw/s400/jruby-irb.png" alt="" id="BLOGGER_PHOTO_ID_5215432002295189842" border="0" /></a><br />JRuby spits out a<span style="font-style: italic;"> local-variable(in-block)</span> whilst C-ruby gives back <span style="font-style: italic;">local-variable</span> only. I suppose this is intentional, although I didn't go down the rabbit hole to confirm it. If you know the rationale I'd like to know it too. Anyways, just a heads up that they are different.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4806640790205683824-5029420439204803355?l=antagonisticpleiotropy.blogspot.com'/></div>Daniel Bastos Aragaohttp://www.blogger.com/profile/14224933549638075286noreply@blogger.com3tag:blogger.com,1999:blog-4806640790205683824.post-64758752981397742008-06-23T06:42:00.000-07:002008-06-23T07:16:35.043-07:00Reading JNDI resources in JRuby<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_8kJd-8eQ_1w/SF-utv0ekHI/AAAAAAAAAIs/SaByrT_Jy6o/s1600-h/dukewithrubyax7.thumbnail.png"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://2.bp.blogspot.com/_8kJd-8eQ_1w/SF-utv0ekHI/AAAAAAAAAIs/SaByrT_Jy6o/s400/dukewithrubyax7.thumbnail.png" alt="" id="BLOGGER_PHOTO_ID_5215078994472243314" border="0" /></a>The most common use of a JNDI resource in JRuby-land is for configuring datasources. But now I wanted to have ActionMailer send emails using a JNDI config. So how to do it?<br />Do not fear! JRuby is your friend and every old java trick can be used.<br /><br />So let's create the JNDI resource which is an javax.mail.Session pointing to localhost. This is what one would normally find in Tomcat's context.xml file (<a href="http://pastie.org/220348">pastie</a>):<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_8kJd-8eQ_1w/SF-qo750kMI/AAAAAAAAAIM/nCl4MCa7TL4/s1600-h/context.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_8kJd-8eQ_1w/SF-qo750kMI/AAAAAAAAAIM/nCl4MCa7TL4/s400/context.png" alt="" id="BLOGGER_PHOTO_ID_5215074513770025154" border="0" /></a><br />Then let's create an adapter to do look ups for us (<a href="http://pastie.org/220347">pastie</a>):<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_8kJd-8eQ_1w/SF-r2aRc4pI/AAAAAAAAAIc/1OH44CC_7Rg/s1600-h/adapter.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_8kJd-8eQ_1w/SF-r2aRc4pI/AAAAAAAAAIc/1OH44CC_7Rg/s400/adapter.png" alt="" id="BLOGGER_PHOTO_ID_5215075844772127378" border="0" /></a><br />And finally a simple test to see if it works (<a href="http://pastie.org/220352">pastie</a>):<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_8kJd-8eQ_1w/SF-sYtjkl2I/AAAAAAAAAIk/NtGw97ORZ-g/s1600-h/lookup.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_8kJd-8eQ_1w/SF-sYtjkl2I/AAAAAAAAAIk/NtGw97ORZ-g/s400/lookup.png" alt="" id="BLOGGER_PHOTO_ID_5215076434063955810" border="0" /></a><br />Pretty easy huh?<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4806640790205683824-6475875298139774?l=antagonisticpleiotropy.blogspot.com'/></div>Daniel Bastos Aragaohttp://www.blogger.com/profile/14224933549638075286noreply@blogger.com0tag:blogger.com,1999:blog-4806640790205683824.post-66509327976275017762008-05-27T03:23:00.000-07:002008-05-27T04:26:40.048-07:00The Omen strikes again! JRuby on Rails on, yikes, Websphere.<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_8kJd-8eQ_1w/SDvonJcf5LI/AAAAAAAAAHk/mWKNDbgdWjs/s1600-h/websphere.jpg"><img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://1.bp.blogspot.com/_8kJd-8eQ_1w/SDvonJcf5LI/AAAAAAAAAHk/mWKNDbgdWjs/s200/websphere.jpg" alt="" id="BLOGGER_PHOTO_ID_5205009553604732082" border="0" /></a>Recently I kept my self busy, and highly frustrated trying to get a <a href="http://jruby.codehaus.org/">JRuby</a> application working on WebSphere 6.1. The recipe was pretty straight forward: <a href="http://caldersphere.rubyforge.org/warbler/">warble</a> it and deploy it. Truthfully, there are a few steps that you need to be taken care of, such as configuring database.yml to point to the right place and making sure warbler.rb config file includes the proper jdbc-adapters, but that is all OK.<br /><br />So, after trying the generated .war in Tomcat and confirming that it was working fine, it was time to hit WebSphere land, and guess what!, didn't work, duh!<br /><br />The default web.xml configuration doesn't play well in WebSphere. The worst part is that there are no error messages, not even a trace in the logs to help.<br /><br />The default web.xml spat out by warbler reads:<br /><br /><span style="font-style: italic;"><filter></filter></span><span style="font-style: italic;"><filter-name></filter-name></span> <a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_8kJd-8eQ_1w/SDvtSpcf5NI/AAAAAAAAAH0/nIAoViKOe7E/s1600-h/b4.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_8kJd-8eQ_1w/SDvtSpcf5NI/AAAAAAAAAH0/nIAoViKOe7E/s400/b4.png" alt="" id="BLOGGER_PHOTO_ID_5205014698975552722" border="0" /></a><br />The filter doesn't work in WebSphere, but the servlet does the trick. So I changed the web.xml.erb within the installed gem to produce this:<br /><span style="font-style: italic;"> <listener></listener></span> <span style="font-style: italic;"><listener-class></listener-class></span><span style="font-style: italic;"><listener-class></listener-class></span><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_8kJd-8eQ_1w/SDvtoJcf5OI/AAAAAAAAAH8/_ZO0lRqS-e8/s1600-h/after.png"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_8kJd-8eQ_1w/SDvtoJcf5OI/AAAAAAAAAH8/_ZO0lRqS-e8/s400/after.png" alt="" id="BLOGGER_PHOTO_ID_5205015068342740194" border="0" /></a><br />Note that I've repeated the listener tag, it was intentional. WebSphere will complain if the listener declaration came after the servlet tag, it must be before, duh! again!<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4806640790205683824-6650932797627501776?l=antagonisticpleiotropy.blogspot.com'/></div>Daniel Bastos Aragaohttp://www.blogger.com/profile/14224933549638075286noreply@blogger.com4tag:blogger.com,1999:blog-4806640790205683824.post-11155309771254368522008-05-14T04:06:00.000-07:002008-05-14T04:40:03.071-07:00IBM - DB2 - Blobs - Hibernate - Truncating - Yikes!Every project has its caveats but those that use DB2 have the omen!<br />Yes kids, it's rant time. Why do IBM must make developers lives through out the world so miserable? To the hell with bloated enterprise software.<br />After wasting time trying to figure out why Hibernate was having problems inserting blobs into DB2, our team realized the obviousness: blobs must have their size defined, no duh!<br /><br />So imagine a domain object that reads:<br /><br /><span style="font-family: courier new;">@Entity</span><br /><span style="font-family: courier new;">public class Image {</span><br /><span style="font-family: courier new;"> @Id @GeneratedValue(strategy = GenerationType.AUTO)</span><br /><span style="font-family: courier new;"> private Long id</span><br /><span style="font-family: courier new;"> @Lob</span><br /><span style="font-family: courier new;"> private byte[] image;</span><br /><span style="font-family: courier new;">}</span><br /><br />To work in IBM/DB2 land it must read:<br /><br /><span style="font-family: courier new;">@Entity</span><br /><span style="font-family: courier new;"> public class Image {</span><br /><span style="font-family: courier new;"> @Id @GeneratedValue(strategy = GenerationType.AUTO)</span><br /><span style="font-family: courier new;"> private Long id</span><br /><span style="font-family: courier new;"> @Lob @Column(length = 1000000)</span><br /><span style="font-family: courier new;"> private byte[] image;</span><br /><span style="font-family: courier new;"> }</span><br /><br />And pray that your bytes don't get to big or you'll need to recompile your domain.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4806640790205683824-1115530977125436852?l=antagonisticpleiotropy.blogspot.com'/></div>Daniel Bastos Aragaohttp://www.blogger.com/profile/14224933549638075286noreply@blogger.com3tag:blogger.com,1999:blog-4806640790205683824.post-89277059592239938732008-02-08T05:36:00.000-08:002008-02-08T05:56:12.029-08:00True-blue Agile team<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_8kJd-8eQ_1w/R6xdkYITm_I/AAAAAAAAAGs/RJ4AHxQlWO0/s1600-h/iron.jpg"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://3.bp.blogspot.com/_8kJd-8eQ_1w/R6xdkYITm_I/AAAAAAAAAGs/RJ4AHxQlWO0/s200/iron.jpg" alt="" id="BLOGGER_PHOTO_ID_5164605752221080562" border="0" /></a>Yesterday was <a href="http://undercover.com.au/News-Story.aspx?id=4054">Iron Maiden's show</a>. <scream> Maiden </scream> And I was there *grin*. Aside stating the obvious that it was an awesomely great show, they put me to think: why some bands, or groups of people more broadly, achieve success while the majority doesn't?<br /><br />What’s the recipe? Is it talent? Is it the hard work? Is it never giving up? All of the motivational aspects are probably there, but I'd say that the common ground is that, most invariably, great teams didn’t start off great. They learned how to be great together. Team learning is key to a team’s success. Individuals have their unique capabilities and may even be the best in their fields, but unless they learn how to play together nothing really happens.<br /><br />A true-blue Agile team-player knows that the team comes before the individual. As <a href="http://www.amazon.com/Agile-Estimating-Planning-Robert-Martin/dp/0131479415">Mike Cohn</a> says: “…the team must precede the roles”. “I’m in project XZY as a developer.” is very different than “I’m a developer assigned to project XZY”.<br /><br />Another import aspect is that the sense of accomplishment has to be shared. If one person tries to take credit for the success or play the blame game when things go wrong, then that person isn’t a team-player.<br /><br />As lastly non team-players must leave. Those who don’t want to learn how to be a team should go away. Keeping around people who cannot orchestrate their actions and thoughts will take toll on the whole team. But don't feel bad about it there will always be enough space for those who like to work in solitude not sharing their sufferings or findings.<br /><br />OK, so it’s all about creating a synchronized learning team, but how do we achieve that? There are many lines of thought on learning organizations, IMO <a href="http://www.amazon.com/Fifth-Discipline-Practice-Learning-Organization/dp/0385517254">Peter Senge</a> is a great reference, but is it enough to create a first class Agile team? Are Agile teams learning teams? And finally, can we apply Agile techniques to help teams become Agile? What do you think?<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4806640790205683824-8927705959223993873?l=antagonisticpleiotropy.blogspot.com'/></div>Daniel Bastos Aragaohttp://www.blogger.com/profile/14224933549638075286noreply@blogger.com3tag:blogger.com,1999:blog-4806640790205683824.post-48979317414270596372008-01-29T05:10:00.000-08:002008-01-30T04:44:52.233-08:00Technical Debt is a cancer<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_8kJd-8eQ_1w/R58zsIITm9I/AAAAAAAAAGc/KtLfPoKwXmY/s1600-h/technicaldebt.jpg"><img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://1.bp.blogspot.com/_8kJd-8eQ_1w/R58zsIITm9I/AAAAAAAAAGc/KtLfPoKwXmY/s320/technicaldebt.jpg" alt="" id="BLOGGER_PHOTO_ID_5160900531179461586" border="0" /></a>After a discussion about Technical Debt (aka TDebt) in Thoughtworks I realized something: Technical Debt is just like cancer.<o:p></o:p> <p class="MsoNormal">There are several similarities between the disease and this "condition" that happens quite frequently in development projects.<o:p><br /></o:p></p> <p class="MsoNormal">There is a line in medicine that says that if you live long enough you will develop some sort of cancer because organisms have intrinsic failures that will manifest themselves if enough time is given. An IT project that lives long enough will present TDebt related problems.<o:p><br /></o:p></p> <p class="MsoNormal">Cancer can develop from external factors or congenital predispositions. Tobacco, sunlight or too much tuna can disturb your organism to a point of metastasis. Less than good design/coding decisions affect the general project’s health in similar way. If the team chooses to cut corners and develop bad code intentionally TDebt will build up. As for the congenital problems that may be circumvented by using some tools. From a Java angle it can be <a href="http://findbugs.sourceforge.net/">FindBug</a> or <a href="http://pmd.sourceforge.net/">PMD</a> to continuously inspect congenital problems related to the technology stack of choice.<o:p><br /></o:p></p> <p class="MsoNormal">No one wants to discover a cancer but once you find it you need to take some action or it can have terrible effects. Tackling TDebt is hard and many choose to put it off until it's too late. However if the case is a terminal one, then nothing can be done. All you can hope for is for it to live long enough to fulfill its purpose. Different types of problems require different procedures. But seems that the most popular and successful approach is: isolate and remove.<o:p><br /></o:p></p> <p class="MsoNormal">Early detection and prevention are key. The sooner the problem is identified the easier it is to heal. Regular check-ups are a Good Idea™. If a potential problem is detected it should be examined to determine whether it is benign or malign. After that one can decide the course of action. Also there's no point in being a hypochondriac, this shouldn’t consume the team’s time away, it’s preventive not obsessive.</p> <p class="MsoNormal">Some people get worse after they discover a cancer because their moral gets shot. Projects slow down because of TDebt, which gets devs very de-motivated. TDebt makes things unnecessarily complex turning simple tasks into major efforts. Anything that impairs people from living normal lives have devastating effects on their will.<o:p><br /></o:p></p> <p class="MsoNormal"><o:p></o:p>When do you communicate to your family and friends? To what extend TDebt should became visible to the business? I'd say that the approach depends on the severity of the case. Less seriously cases can be treated internally without making a big fuss, but if more people, money and support are going to be required to reestablish the healthy state then stakeholders need to fully participate in the process.<br /><br /><o:p></o:p>Bottom line, have healthy habits (TDD, simple design), prophylaxis (refactoring), use tools to monitor congenital problems (<a href="http://findbugs.sourceforge.net/">FindBug</a>/<a href="http://pmd.sourceforge.net/">PMD</a>) and frequently consult your <a href="http://www.thoughtworks.com/">doctor</a> for a code health check-up.</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4806640790205683824-4897931741427059637?l=antagonisticpleiotropy.blogspot.com'/></div>Daniel Bastos Aragaohttp://www.blogger.com/profile/14224933549638075286noreply@blogger.com0tag:blogger.com,1999:blog-4806640790205683824.post-15777266811251669602008-01-27T07:31:00.000-08:002008-01-28T00:09:48.584-08:00HashMap temptation<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_8kJd-8eQ_1w/R52MBoITm7I/AAAAAAAAAGM/FRvB83MsHX0/s1600-h/image.jpg"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://1.bp.blogspot.com/_8kJd-8eQ_1w/R52MBoITm7I/AAAAAAAAAGM/FRvB83MsHX0/s200/image.jpg" alt="" id="BLOGGER_PHOTO_ID_5160434707616471986" border="0" /></a>When integrating systems it is very easy to fall into HashMap temptation. <span style="font-style: italic;">“Just put some details in a Map and pass it to the service layer and it gives back what you need”</span>. Maybe,… but there are risks.<br /><br />I consider passing Maps around to services an anti-pattern because interfaces become less intentful and creates coupling between layers.<br /><br />Let’s consider a hypothetical example of a farm system. Every morning old McDonald wants to name roll call all animals to ensure they are safe and sound. Farmer McDonald knows he has animals in the pond and on the pasture.<br /><br />On the first pass we create a service receiving a context Map, keyed by environment type and containing animals’ names. The service returns a List with farm Animal instances.<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_8kJd-8eQ_1w/R52FwoITm1I/AAAAAAAAAFc/50vSz0XBFDA/s1600-h/1.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_8kJd-8eQ_1w/R52FwoITm1I/AAAAAAAAAFc/50vSz0XBFDA/s400/1.jpg" alt="" id="BLOGGER_PHOTO_ID_5160427818488929106" border="0" /></a><br />Old McDonald knows the animals’ names, where they live and expects them to say: “present”, in their own dialect, obviously. One client program could look like the one bellow:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_8kJd-8eQ_1w/R52HRIITm2I/AAAAAAAAAFk/gikIUx-tOKM/s1600-h/2.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_8kJd-8eQ_1w/R52HRIITm2I/AAAAAAAAAFk/gikIUx-tOKM/s400/2.jpg" alt="" id="BLOGGER_PHOTO_ID_5160429476346305378" border="0" /></a><br />With this implementation it’s impossible to have a pond roll call only. But that’s not the worst thing, knowing that the service needs to be aware of different environments and keep track of them is the creepiest part. One solution is to make the service layer more intentful and have old McDonald say explicitly the animals of which environment he is roll calling:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_8kJd-8eQ_1w/R52H4YITm3I/AAAAAAAAAFs/fPQRHj9hwMU/s1600-h/3.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_8kJd-8eQ_1w/R52H4YITm3I/AAAAAAAAAFs/fPQRHj9hwMU/s400/3.jpg" alt="" id="BLOGGER_PHOTO_ID_5160430150656170866" border="0" /></a><br />Now instead of a Map it’s a List that gets passed around, the service interface expresses *exactly* what’s to be done and code can be re-used. The downside is that an extra call needs to be made from the client. In this particular example it’s not a major hassle because it requires no extra information about the livestock:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_8kJd-8eQ_1w/R52KYYITm5I/AAAAAAAAAF8/pYSm1myW1SM/s1600-h/5.jpg"><img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://4.bp.blogspot.com/_8kJd-8eQ_1w/R52KYYITm5I/AAAAAAAAAF8/pYSm1myW1SM/s400/5.jpg" alt="" id="BLOGGER_PHOTO_ID_5160432899435240338" border="0" /></a><br />Bottom line: avoid passing Maps around and put more effort into defining highly intentful interfaces. As a rule of thumb service layers are dumb, hence they don’t have to decide which method/logic is to be invoked based on states/keys of other objects. Service layers should only know about domain objects and which methods to invoke. Utilising HashMaps in similar ways to this example violates the <a href="http://pragmaticprogrammer.com/articles/tell-dont-ask">Tell, Don’t Ask</a> principle. This design forces service layers to understand what’s inside of Maps to decide which method to invoke and the client layer in its turn, must create Maps with all things the service needs in order to process the call, which smells like coupling.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4806640790205683824-1577726681125166960?l=antagonisticpleiotropy.blogspot.com'/></div>Daniel Bastos Aragaohttp://www.blogger.com/profile/14224933549638075286noreply@blogger.com0tag:blogger.com,1999:blog-4806640790205683824.post-83060527918918044922008-01-25T14:20:00.000-08:002008-01-25T16:12:47.478-08:00Why Agile adoption fails?<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_8kJd-8eQ_1w/R5pjE4ITmyI/AAAAAAAAAFA/jCkPRWBaHCA/s1600-h/images2.jpg"><img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://3.bp.blogspot.com/_8kJd-8eQ_1w/R5pjE4ITmyI/AAAAAAAAAFA/jCkPRWBaHCA/s400/images2.jpg" alt="" id="BLOGGER_PHOTO_ID_5159545258544175906" border="0" /></a>Why some seem to succeed to produce quality software using lean methodologies and others don’t?<br /><br />For starters there’s a giant lacuna between acknowledging that Agile is useful, fast, high quality, etc and been truly Agile. For Agile to work one must believe and *act* according to her beliefs!<br /><br />I’ve noticed that teams fail to create software using lean approaches mainly because of their preconceived mindsets towards an apparently less predictable, although more precise, model.<br /><br />Unfortunately no one can build software as if it was a house. In software construction you *can* have your own voltage, no gravity and wine instead of water running in the pipes. Therefore managers need to accept that will this level of freedom there is a proportional level of uncertainty that cannot be cleared upfront, regardless of the effort put into planning and estimating.<br /><br />A forcefully preset release date on a spreadsheet means very little to software development. In the outset it only expresses a desire. Functionalities need to be sized, time must be derived for sizing and then, only then, a date estimated. Even after that, realize that that’s all it is, an estimated date.<br /><br />Trying to re-estimate stories because they’re taking longer than expected is another contributing factor for disaster. Let velocity do the work of defining progress, story size cannot change speed.<br /><br />Teams have a hard time accepting that there’s only so much that can be done to go faster in order to meet a deadline. Reducing complexity is one option, re-prioritizing and re-scoping too. Resizing your team can also have positive impact, but overtime not. By working long hours quality will inevitably be compromised and reducing quality is not an option in Agile.<br /><br />Some say Agile is too informal, and even that it makes the office space look ugly with all of those cards on the walls! Software development has always been messy and Agile only exposes it so people can act upon it. Agile is formal, as formal as the organization using it wants it to be. And yes, there is planning too. I don’t have figures but with Agile there’s more planning effort than waterfall. The difference is that the planning is diluted in everyday work such as stand ups, technical huddles, iteration planning meetings, kick-offs, planning poker, etc..<br /><br />Agile is highly dependent on talented developers. Roles such as team managers and architects have less or no impact in Agile teams. Traditional waterfall micro-management kills creativity and architects tend to do a lot of upfront design and create unacceptable resistance to design change over the course of stories. The devs need to be different too. Agile devs must be design savvy, have creativity and initiative.<br /><br />Lastly, if all of this seems too daunting and you don’t want to take the risk of figuring out Agile heuristically, go and hire an Agile consultancy. Get people with experience to help you out in a few projects and inculcate the principles. This way the organization gains confidence, establishes a faster return of investment and creates enough in-house Agile champions to sustain the changing momentum throughout the company.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4806640790205683824-8306052791891804492?l=antagonisticpleiotropy.blogspot.com'/></div>Daniel Bastos Aragaohttp://www.blogger.com/profile/14224933549638075286noreply@blogger.com0tag:blogger.com,1999:blog-4806640790205683824.post-30346480570182194612008-01-20T22:08:00.001-08:002008-01-20T22:55:48.307-08:00Swing Acceptance Testing with JFCAfter many years developing for the Web I found myself having to do some Swing code and *obviously* had to do some testing for it. I went with <a href="http://jfcunit.sourceforge.net/">JFC</a> for the functional tests and here’s a little cookbook.<br /><br />The test class extends from <span style="font-style: italic;">JFCTestCase</span><span style="color: rgb(153, 153, 153);font-family:verdana;" ><blockquote></blockquote></span> <span style="color: rgb(153, 153, 153);font-family:verdana;" >public class CurCalcTest extends JFCTestCase</span><br /><span style="color: rgb(153, 153, 153);font-family:verdana;" ><blockquote></blockquote></span>The main JFC class to take heed is <span style="font-style: italic;">JFCTestHelper</span>. Probably a Good Idea is to set it in the setup method:<br /><br /><span style="color: rgb(153, 153, 153);font-family:verdana;" > protected void setUp() throws Exception {</span><br /><span style="color: rgb(153, 153, 153);font-family:verdana;" > super.setUp();</span><br /><span style="color: rgb(153, 153, 153);font-family:verdana;" > setHelper(new JFCTestHelper());</span><br /><span style="color: rgb(153, 153, 153);font-family:verdana;" > }<br /><br /></span>After that, my approach was to get the container under test/investigation:<br /><br /> <span style="color: rgb(153, 153, 153);font-family:verdana;" >JPanel curCalcPanel = (JPanel) frame.getContentPane().getComponent(0);<br /><br /></span>And then obtain each one of the elements I want to manipulate, such as comboBoxes, textFields, and etc.:<br /><br /><span style="color: rgb(153, 153, 153);font-family:verdana;" > NamedComponentFinder amountFinder = new NamedComponentFinder(</span><br /><span style="color: rgb(153, 153, 153);font-family:verdana;" > JTextField.class, "jTextFieldAmount");</span><br /><span style="color: rgb(153, 153, 153);font-family:verdana;" > amountField = (JTextField) amountFinder.find(curCalcPanel, 0);<br /></span><br /><span style="color: rgb(153, 153, 153);font-family:verdana;" > NamedComponentFinder countryComboFinder = new</span><br /><span style="color: rgb(153, 153, 153);font-family:verdana;" > NamedComponentFinder(JComboBox.class, "jComboBoxCountry1");</span><br /><span style="color: rgb(153, 153, 153);font-family:verdana;" > countryCombo = (JComboBox) countryComboFinder.find(curCalcPanel, 0);</span><br /><span style="color: rgb(153, 153, 153);font-family:verdana;" > <br /> NamedComponentFinder messagesFinder = new</span><br /><span style="color: rgb(153, 153, 153);font-family:verdana;" > NamedComponentFinder(JLabel.class, "messages");</span><br /><span style="color: rgb(153, 153, 153);font-family:verdana;" > messagesLabel = (JLabel) messagesFinder.find(curCalcPanel, 0);<br /><br /></span>Now I can insert my keystrokes/clicks using the helper:<br /><br /><span style="color: rgb(153, 153, 153);font-family:verdana;" > getHelper().sendString(new StringEventData(this, amountField, "1"));</span><br /><span style="color: rgb(153, 153, 153);font-family:verdana;" > getHelper().enterClickAndLeave(new JComboBoxMouseEventData(this,<br /> countryCombo, 1, 1));</span><br /><span style="color: rgb(153, 153, 153);font-family:verdana;" > getHelper().enterClickAndLeave(new MouseEventData(this, convertButton));</span><br /><br />And assert my expectation(s):<br /><br /><span style="color: rgb(153, 153, 153);font-family:verdana;" > Assert.assertEquals("0.97478773", messagesLabel.getText());</span><br /><br />JFC is another fantastic tool by ThoughtWorks. It is a very useful framework but not friendly all of the time. For instance, if you forget to identify the elements properly via the <span style="font-style: italic;">setName() </span>method, and try to use <span style="font-style: italic;">NamedComponentFinder</span> no error is given, the thread just sits in there without complaining about anything.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4806640790205683824-3034648057018219461?l=antagonisticpleiotropy.blogspot.com'/></div>Daniel Bastos Aragaohttp://www.blogger.com/profile/14224933549638075286noreply@blogger.com3tag:blogger.com,1999:blog-4806640790205683824.post-5818529240083098782008-01-05T02:46:00.000-08:002008-01-05T03:05:50.988-08:00New Year's resolution<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_8kJd-8eQ_1w/R39kY8JVmgI/AAAAAAAAABU/7d5xrhrItTk/s1600-h/logo.gif"><img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://2.bp.blogspot.com/_8kJd-8eQ_1w/R39kY8JVmgI/AAAAAAAAABU/7d5xrhrItTk/s200/logo.gif" alt="" id="BLOGGER_PHOTO_ID_5151946878360066562" border="0" /></a><br />Is it too late for a New Year resolution?? Probably not. Then here it goes. I'll learn Ruby in 2008. These are the reasons:<br /><ul><li>I'm getting a bit tired of Java and Ruby seems to be the next logical move</li><li>Now that JRuby is out, chances are that the Ruby will really make to corporate environments</li><li>It has a strong community</li><li>ThoughtWorks is supporting it wholeheartedly, BTW welcome to the team Ola Bini!</li><li>Ruby is very flexible allowing some very fancy things, still lacks a bit of control thou<br /></li><li>Finally and most important, Ruby is Agile</li></ul>So Ruby, here I go!<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4806640790205683824-581852924008309878?l=antagonisticpleiotropy.blogspot.com'/></div>Daniel Bastos Aragaohttp://www.blogger.com/profile/14224933549638075286noreply@blogger.com0tag:blogger.com,1999:blog-4806640790205683824.post-3686497811101664532008-01-02T16:50:00.000-08:002008-01-02T16:56:23.508-08:00Notes on Selenium-grid<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_8kJd-8eQ_1w/R3wxysJVmfI/AAAAAAAAABM/rJxqWc2rLwc/s1600-h/up.jpg"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://2.bp.blogspot.com/_8kJd-8eQ_1w/R3wxysJVmfI/AAAAAAAAABM/rJxqWc2rLwc/s200/up.jpg" alt="" id="BLOGGER_PHOTO_ID_5151046820718549490" border="0" /></a><br /><p class="MsoNormal">The fact that web tests, let’s call them here <a href="http://www.openqa.org/selenium/">Selenium</a> tests, are time consuming seems to hurt a lot of agile projects. Long build times are hard to live with.</p> <p class="MsoNormal">In the early stages of the project there are a few Selenium tests, usually not very well structured and testing on a per story basis. As more stories are played more Selenium tests are created, usually with a certain degree of repetition, causing the build time to increase. That’s when it starts to sting. </p> <p class="MsoNormal">In my last client the build time started off in the thirty minutes range and after four iterations it was costing the team a horrendous seventy minutes. Selenium tests alone were responsible for almost fifty minutes.</p> <p class="MsoNormal">There were a few ways to reduce time. The first obvious one is ditching some tests. If you are playing by the book and doing TDD, really caring about your unit and integration tests, and have a decent test coverage, giving up a couple of redundant tests might not be so bad. Another option is to rewrite tests to eliminate redundancy and test using a scenario approach instead of the story one. Scenario based tests are a Good Idea™ but time consuming and hard to guarantee that everything that was tested before is still been tested using the conceived scenarios. A third option was to parallelize the tests and <a href="http://www.openqa.org/selenium-grid/">Selenium-grid</a> allows doing just that.</p> <p class="MsoNormal"><a href="http://www.lawrencesong.net/">Lawrence Song</a> and I had Selenium-grid up and running with no traumas. It’s quite straight forward to install it but not all is roses. Web tests that run on a farm need to be more carefully constructed that those running on a single threaded environment.</p> <p class="MsoNormal">Tests must run atomically and the rule of one behaviour per test should be strictly observed. For instance, if tests perform database operations on the same data they can have problems when running concurrently.</p> <p class="MsoNormal">Don’t leave Selenium objects hanging in there. Selenium objects that aren’t closed properly causes the hub to stop sending RC commands until you have only one Selenium server available. So the Selenium lifecycle needs to be managed more tightly.</p> <p class="MsoNormal">You need to think about the test list. In order to use the grid’s capabilities tests need to be run in a multi-thread fashion. TestNG does a better job that Parallel JUnit. Some <a href="http://gsbase.sourceforge.net/apidocs/com/gargoylesoftware/base/testing/RecursiveTestSuite.html">Gargoyle</a> like facility would help make it more manageable. As a last resource, which seems to be the sensible one especially when needing to avoid two or more tests running concurrently, is to use <a href="http://ant.apache.org/manual/CoreTasks/parallel.html">parallel ant task</a> and pick your tests using a pattern. </p> <p class="MsoNormal">Web tests are generally CPU intense and it’s a Good Idea™ to think about how many Selenium servers should be running on each box, especially if they are also running other apps like your container for example. We saw flaky results when boxes where running close to 100% CPU all the time.</p> <p class="MsoNormal">Bottom line is that Selenium-grid is a great help to solve a common problem, in our client the build time dropped significantly and now takes around twenty five minutes with a few hours of effort. Yay! And we can always add more boxes. Selenium-grid has a very positive side effect which is to reinforce better test design.</p> <p class="MsoNormal">Nevertheless I’d really enjoy if Selenium-grid could provide the community with the ability to utilise idle computers to run tests and a friendlier interface to manage the hub.</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4806640790205683824-368649781110166453?l=antagonisticpleiotropy.blogspot.com'/></div>Daniel Bastos Aragaohttp://www.blogger.com/profile/14224933549638075286noreply@blogger.com0tag:blogger.com,1999:blog-4806640790205683824.post-54516814896419389602007-11-20T02:33:00.000-08:002007-11-20T04:33:06.634-08:00Don't skimp on defining ids in your DOM<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_8kJd-8eQ_1w/R0LA2-x4lOI/AAAAAAAAABE/CaKYxuej0m0/s1600-h/476761_52269138.thumbnail.jpg"><img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://4.bp.blogspot.com/_8kJd-8eQ_1w/R0LA2-x4lOI/AAAAAAAAABE/CaKYxuej0m0/s200/476761_52269138.thumbnail.jpg" alt="" id="BLOGGER_PHOTO_ID_5134878575953482978" border="0" /></a>Recently after updating from Selenium RC from 0.8.3 to 0.9.2 I noticed some serious performance degradation, actually in an order of magnitude slower. Tests affected the most were those using XPath to match attributes. These tests were doing too broad searches by using<span style="font-style: italic;"> '//*'</span> such as in <span style="font-style: italic;">'//*[@id='errorField1']/td[2]'</span>.<o:p></o:p> <p class="MsoNormal">As a fix searches were narrowed by providing a more specific search, such as <span style="font-style: italic;">'//tr[@id='errorField1']/td[2]'</span>.<o:p></o:p></p> <p class="MsoNormal">Locators starting with '//*' search any element node from the current node that match the selection no matter where they are, been therefore very expensive.<o:p></o:p></p> <p class="MsoNormal">So the general recommendation is: be specific. Try to provide the node you want directly, ideally, a specific id should be provided, i.e. <span style="font-style: italic;">'id('errorField')//' </span>(although there are known issues in IE6). <o:p></o:p></p> <p class="MsoNormal">Despite the fact that I'd rather see a better performance when advancing versions, the moral is: don't skimp on defining ids in your DOM, the more the DOM is properly marked the easier and faster it is to be tested. Keep in mind that acceptance tests are time consuming and performance improvements are greatly appreciated, especially if you run them as part of your continuous integration build.</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4806640790205683824-5451681489641938960?l=antagonisticpleiotropy.blogspot.com'/></div>Daniel Bastos Aragaohttp://www.blogger.com/profile/14224933549638075286noreply@blogger.com0tag:blogger.com,1999:blog-4806640790205683824.post-6059354438156640882007-10-29T02:09:00.000-07:002007-10-29T02:33:41.129-07:00Few pointers on refactoring<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_8kJd-8eQ_1w/RyWoNXBT7oI/AAAAAAAAAA8/xcYR3lFc5hM/s1600-h/pointers.png"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://4.bp.blogspot.com/_8kJd-8eQ_1w/RyWoNXBT7oI/AAAAAAAAAA8/xcYR3lFc5hM/s200/pointers.png" alt="" id="BLOGGER_PHOTO_ID_5126688698302459522" border="0" /></a><br />If refactoring isn’t a part of your daily life you may find it a bit hard to know what to do. There is also that fear of messing up code that is working properly. Well, the later can be eased by having extensive test coverage. The more tests the codebase has the safer the refactoring will be. And for the former I tried to put a few pointers here. This isn’t a <a href="http://www.refactoring.com/catalog/index.html">complete list of refactorings</a> though, it is just a start.<br /><ul><li>Read the class and try to understand it.</li><li>Is the class responsibility clear? Or is the class doing more than it should?</li><li>Are there fields been accessed directly by other classes. If yes encapsulate.</li><li>Do the public methods have meaningful names? Are they aligned with the class’ responsibility? If not extract to Helper class.</li><li>Check if public methods really need to be public. Always Ctrl+Shift+G to see who’s referencing it.</li><li>Mind visibility modifiers. Ensure you have a reason when using public, protected or default.</li><li>Is the class been instantiated in more than one place and does it have subclasses? Considerer extracting an interface.</li><li>Duplicated (or very similar) code? Extract a method. Rule of thumb: DON’T Ctrl+C, Ctrl+V as it leads to Code Horror ™.</li><li>Do private methods contain class specific or do they look like a util-type of code? If yes move it to a proper class.</li><li>Util classes are singletons or static methods, we shouldn’t need to instantiate utilities.</li><li>Extract methods from the if’s conditional clause, body, and else parts. Avoid complicated ifs and elses as they usually clog the code and create unnecessary duplication. Think about using Strategy.</li><li>Check for extends. Can I compose instead of inherit?</li><li>When using methods from different interfaces in a complementary way consider writing a Façade to join the two (or more) of them<br /></li><li>Don’t wait for a NullPointer to explode the stacktrace, use Assert.</li></ul><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4806640790205683824-605935443815664088?l=antagonisticpleiotropy.blogspot.com'/></div>Daniel Bastos Aragaohttp://www.blogger.com/profile/14224933549638075286noreply@blogger.com1tag:blogger.com,1999:blog-4806640790205683824.post-62533258628538711382007-10-26T18:20:00.000-07:002007-11-05T00:36:03.220-08:00Every problem is a people-problem<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_8kJd-8eQ_1w/RyKUWnBT7lI/AAAAAAAAAAk/U4G9PXUkLec/s1600-h/Couple-Arguing_PQ_757492.jpg"><img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://2.bp.blogspot.com/_8kJd-8eQ_1w/RyKUWnBT7lI/AAAAAAAAAAk/U4G9PXUkLec/s200/Couple-Arguing_PQ_757492.jpg" alt="" id="BLOGGER_PHOTO_ID_5125822442053561938" border="0" /></a><br />A friend of mine who just starting working in an Agile project said to be worried that all problems in the project seem to people problems. I started to think about project problems. Technologies? Time and money constraints? Quality? The list can go on and on. However the bottom line is that people will have to code the solution - I know it's a simplistic view but computers will do nothing by themselves - and assuming that a minimum level of sanity was applied while establishing the deliverables, everything else must be people problems then.<br /><br />Don’t believe me? Take Kent Beck’s words for it then. In his book XP Explained he says: <span style="font-style: italic;">“… no matter what the client says the problem is, it is always a people problem.”</span> Ok now that I’m on giant’s shoulders let me try to make my point.<br /><br />What bogs velocity down?<br /><br />Interruptions – people are taken away from what they should be doing, justifiably or not. Illnesses or life administration matters.<br />Over commitment – one promises to do more than can actually be done.<br />Fear/Resistance to change – I already know this technology/methodology and changing threatens me<br />Bad sloth - In opposition to Good sloth which I’ll write later, hopefully :0) – I’ll only do the minimum and if I can I’ll do nothing.<br />Tedium – I’m so damn bored I can’t motivate myself to do nothing.<br />Over engineering – Pythagorean Switch syndrome.<br />Excess of political concern – If there is no positive press I won’t do it.<br /><br />The scales tilt to softer aspects and not to technical ones. Once we admit it and put effort into really understanding the team-members, their frustrations, aspirations and turnons we might be able to successfully remove most of the hurdles that hinder software development.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4806640790205683824-6253325862853871138?l=antagonisticpleiotropy.blogspot.com'/></div>Daniel Bastos Aragaohttp://www.blogger.com/profile/14224933549638075286noreply@blogger.com0tag:blogger.com,1999:blog-4806640790205683824.post-53189684310814288402007-10-23T06:29:00.000-07:002007-10-23T06:47:57.466-07:00We don’t stop to refactor, we refactor to not stop<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_8kJd-8eQ_1w/Rx36pMxDw5I/AAAAAAAAAAc/Kqcp_jrqExw/s1600-h/spaghetti-head.jpg"><img style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" src="http://3.bp.blogspot.com/_8kJd-8eQ_1w/Rx36pMxDw5I/AAAAAAAAAAc/Kqcp_jrqExw/s320/spaghetti-head.jpg" alt="" id="BLOGGER_PHOTO_ID_5124527536726066066" border="0" /></a><br />I don’t think I can reinforce this enough. Agile teams refactor.<br />Refactoring is a core practice that underpins Agile development. As a refresher: Refactoring is modifying code without altering system functionality. This means that if all your tests are running properly prior to a refactor exercise they should not require any extra work once refactoring is completed.<br />Refactoring contributes directly to internal quality, which is of course, non-negotiable in an Agile endeavor. Internal quality guarantees a steady velocity and maintainability throughout iterations.<br />The main reasons why some developers still vacillate to refactor mercilessly are lack of trust in the IDE capabilities and the assumption that “it can done later”.<br />You should trust your IDE or switch to one that you feel confident with. You’ll only gain confidence by understanding the IDE capabilities and practicing them. Therefore dedicate some time to study the refactoring facilities and write several examples to practice.<br />Refactoring is not an activity that can wait until a story or project is completed. No project has exclusive budget for Refactoring and because it does not deliver any extra functionality it's virtually impossible to convince sponsors to finance it.<br />Bottom line, Refactoring is an ongoing practice and the cliché still holds valid: “We don’t stop to refactor, we refactor to not stop”.<br />Happy refactorings :0)<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4806640790205683824-5318968431081428840?l=antagonisticpleiotropy.blogspot.com'/></div>Daniel Bastos Aragaohttp://www.blogger.com/profile/14224933549638075286noreply@blogger.com0tag:blogger.com,1999:blog-4806640790205683824.post-34878149272120206142007-10-19T05:15:00.000-07:002007-10-29T02:33:09.519-07:00Distorted project velocity and skewed story points<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_8kJd-8eQ_1w/RxigwMxDw4I/AAAAAAAAAAU/WVqRRNpW8xU/s1600-h/23107811.jpg"><img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://2.bp.blogspot.com/_8kJd-8eQ_1w/RxigwMxDw4I/AAAAAAAAAAU/WVqRRNpW8xU/s320/23107811.jpg" alt="" id="BLOGGER_PHOTO_ID_5123021326055097218" border="0" /></a><br />How to increase project Velocity the wrong way? Just distort Story Point estimations to be more than what they really are. Story Points are not for that. And using Project Velocity as the only fixed goal may bring disastrous results.<br /><br />Story Points represent a story’s complexity when compared to other stories. Yes, Story Points need comparison. Why? Because complexity it’s intimately related to the team’s technical capacity, gel, motivation, etc. Story points are not units of time, but people will, most invariably, relate the two. That’s not too bad as long it’s not used for the purpose of creating slack or artificially increasing velocity.<br /><br />Agile teams should be aware of their estimations and should <span>never allow intentional inflation of Story Points</span> under the risk of creating a demotivated environment, not the mention that this will discredit the the team to managers and executives. If the team insists on this practice it's better go back to time units. At least it's <span>real</span>.<div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4806640790205683824-3487814927212020614?l=antagonisticpleiotropy.blogspot.com'/></div>Daniel Bastos Aragaohttp://www.blogger.com/profile/14224933549638075286noreply@blogger.com0tag:blogger.com,1999:blog-4806640790205683824.post-62679978165491623622007-10-15T23:43:00.000-07:002007-10-19T05:35:31.673-07:00Title explained<a href="http://1.bp.blogspot.com/_8kJd-8eQ_1w/RxRf-8xDw3I/AAAAAAAAAAM/lNedgDUXuKE/s1600-h/protein.jpg"><img id="BLOGGER_PHOTO_ID_5121824211295519602" style="margin: 0px 0px 10px 10px; float: right;" alt="" src="http://1.bp.blogspot.com/_8kJd-8eQ_1w/RxRf-8xDw3I/AAAAAAAAAAM/lNedgDUXuKE/s320/protein.jpg" border="0" height="192" width="279" /></a><br /><div>The term Antagonist <span class="blsp-spelling-error" id="SPELLING_ERROR_0">Pleiotropy</span> is misused in this blog. It represents a <a href="http://en.wikipedia.org/wiki/Pleiotropy">genetic situation</a> used in G. C. Williams theory of aging. I first learned about it while reading Bryan <span class="blsp-spelling-error" id="SPELLING_ERROR_1">Appleyard's</span> book <em>"How to live forever or die trying" (</em>pretty interesting by the way). I'm using it with the single purpose of an alert. An alert that whatever you do/have today that is currently beneficial might not be in the future, in fact it can potentially ruin you completely.</div><div></div><div>Nevertheless now that the title's obscurity has been properly explained I can start :0) This blog is about software development. Yep another another one. I should have called <span class="blsp-spelling-error" id="SPELLING_ERROR_2">it YATB</span> - Yet Another Tech Blog. I promise to try and make interesting though.</div><div></div><div>I'll blog about Agile, lean processes, Java and anything that helps relieving the pain of creating decent software.</div><br /><div></div><br /><div></div><br /><div></div><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/4806640790205683824-6267997816549162362?l=antagonisticpleiotropy.blogspot.com'/></div>Daniel Bastos Aragaohttp://www.blogger.com/profile/14224933549638075286noreply@blogger.com0