<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-5963350864821674235</id><updated>2011-07-30T12:01:35.846-06:00</updated><category term='user groups'/><category term='virtualization'/><category term='continuous integration'/><category term='JIRA'/><category term='system programming'/><category term='Subversion'/><category term='RDoc'/><category term='stress testing'/><category term='IT'/><category term='mock'/><category term='Windows'/><category term='Log4r'/><category term='SSH key authentication'/><category term='Postgres'/><category term='Confluence'/><category term='rcov'/><category term='browsers'/><category term='technical debt'/><category term='TDD'/><category term='Joomla'/><category term='JRuby'/><category term='Trac'/><category term='Code Reviews'/><category term='svn+ssh'/><category term='Ruby'/><category term='FTP'/><category term='CMS'/><category term='FlexMock'/><category term='performance testing'/><category term='load testing'/><category term='Hudson'/><category term='Flex'/><category term='quality'/><category term='Watir'/><category term='Test::Unit'/><category term='Rake'/><category term='utilities'/><category term='database'/><category term='Erlang'/><title type='text'>Effective QA</title><subtitle type='html'>Making software quality assurance more effective and more fun</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>27</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5963350864821674235.post-8032770036218614497</id><published>2010-05-15T08:45:00.002-06:00</published><updated>2010-05-15T08:56:23.146-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Windows'/><category scheme='http://www.blogger.com/atom/ns#' term='database'/><title type='text'>Configuring SQL Server for external access on Windows 2003</title><content type='html'>Recently I was trying to expose SQL Server for external access on a Windows 2003 server. I ran into several issues:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;Port 1433 was blocked by the firewall. &lt;a href="http://serverfault.com/questions/60414/how-to-open-port-1433-on-windows-2003"&gt;This serverfault article&lt;/a&gt; explains how to detect and correct this&lt;/li&gt;&lt;br /&gt;&lt;li&gt;The TCP/IP filters for inbound access had to be altered. &lt;a href="http://support.microsoft.com/kb/816792"&gt;This Microsoft article&lt;/a&gt; describes doing this&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;In retrospect neither of these issues are surprising, but especially the TCP/IP filter issue took me some time to track down, so perhaps this will help someone else.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5963350864821674235-8032770036218614497?l=effectiveqa.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/8032770036218614497/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5963350864821674235&amp;postID=8032770036218614497&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/8032770036218614497'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/8032770036218614497'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/2010/05/configuring-sql-server-for-external.html' title='Configuring SQL Server for external access on Windows 2003'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5963350864821674235.post-4626145921186808937</id><published>2010-05-15T08:36:00.003-06:00</published><updated>2010-05-15T08:42:29.914-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Windows'/><category scheme='http://www.blogger.com/atom/ns#' term='utilities'/><title type='text'>Windows installer clean up utility</title><content type='html'>I recently found myself with a program that did not uninstall cleanly and it left enough of a mess that I could reinstall it. After some searching around, I found this tool from Microsoft:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://support.microsoft.com/default.aspx?scid=kb;en-us;290301"&gt;http://support.microsoft.com/default.aspx?scid=kb;en-us;290301&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;It discusses cleanup of Office installs on XP, but I found it to work fine on other programs on 64-bit Vista. Give it a try the next time you have a program that won't uninstall.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5963350864821674235-4626145921186808937?l=effectiveqa.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/4626145921186808937/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5963350864821674235&amp;postID=4626145921186808937&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/4626145921186808937'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/4626145921186808937'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/2010/05/windows-installer-clean-up-utility.html' title='Windows installer clean up utility'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5963350864821674235.post-2596328025456856389</id><published>2009-12-06T14:14:00.007-07:00</published><updated>2009-12-14T09:28:00.025-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quality'/><category scheme='http://www.blogger.com/atom/ns#' term='load testing'/><category scheme='http://www.blogger.com/atom/ns#' term='stress testing'/><category scheme='http://www.blogger.com/atom/ns#' term='performance testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Erlang'/><title type='text'>A minimal Erlang script for load testing</title><content type='html'>Recently I became interested in &lt;a href="http://www.erlang.org/"&gt;Erlang&lt;/a&gt;, a &lt;a href="http://en.wikipedia.org/wiki/Functional_programming"&gt;functional programming language&lt;/a&gt; that excels at developing &lt;a href="http://en.wikipedia.org/wiki/Concurrent_computing"&gt;concurrent applications&lt;/a&gt;. From a SQA perspective, concurrency immediately made me think of performance and load testing. I am not the first one to think this - see the open source application &lt;a href="http://tsung.erlang-projects.org/"&gt;Tsung&lt;/a&gt; to see just how far this idea has been taken.&lt;br /&gt;&lt;br /&gt;I set about to see how minimal an Erlang program I could write that would implement a bear-bones load tester for web apps. Here is what I came up with:&lt;br /&gt;&lt;pre style="font-family: courier new; font-size: 85%; font-weight: bold; color: rgb(164, 0, 0);"&gt; 1: -module(lmin).&lt;br /&gt;&amp;nbsp;2: -export([example/0, ramp/4, vclient/2]).&lt;br /&gt;&amp;nbsp;3:&lt;br /&gt;&amp;nbsp;4: vclient(Supervisor, Script) -&gt;&lt;br /&gt;&amp;nbsp;5:    inets:start(),&lt;br /&gt;&amp;nbsp;6:    Total = vclient_acc(Script, 0),&lt;br /&gt;&amp;nbsp;7:    Supervisor ! {self(), Total / 1000000}.&lt;br /&gt;&amp;nbsp;8:&lt;br /&gt;&amp;nbsp;9: vclient_acc([Cmd|Remaining_cmds], Total_time) -&gt;&lt;br /&gt;10:   Fetch_time = timed_request(Cmd),&lt;br /&gt;11: vclient_acc(Remaining_cmds, Fetch_time + Total_time);&lt;br /&gt;12: vclient_acc([], Total_time) -&gt; Total_time.&lt;br /&gt;13:&lt;br /&gt;14: timed_request({Delay, Url}) -&gt;&lt;br /&gt;15:    timer:sleep(Delay + random:uniform(Delay)),&lt;br /&gt;16:    Start_time = now(),&lt;br /&gt;17:    {ok, _Result} = http:request(Url),&lt;br /&gt;18:    timer:now_diff(now(), Start_time).&lt;br /&gt;19:&lt;br /&gt;20: ramp(Nstart, Nend, _Nstep, _Script) when Nstart &gt; Nend -&gt; done;&lt;br /&gt;21: ramp(Nstart, Nend, Nstep, Script) -&gt;&lt;br /&gt;22:    launch_vclients(Nstart, Script),&lt;br /&gt;23:    collect_results(Nstart),&lt;br /&gt;24:    timer:sleep(1000),&lt;br /&gt;25:    ramp(Nstart+Nstep, Nend, Nstep, Script).&lt;br /&gt;26:&lt;br /&gt;27: launch_vclients(0, _Script) -&gt; true;&lt;br /&gt;28: launch_vclients(N, Script) -&gt;&lt;br /&gt;29:    spawn(?MODULE, vclient, [self(), Script]),&lt;br /&gt;30:    launch_vclients(N-1, Script).&lt;br /&gt;31:&lt;br /&gt;32: collect_results(Nexpected) -&gt;&lt;br /&gt;33:    {Sum, _Results} = collect_results(Nexpected, Nexpected, [], 0),&lt;br /&gt;34:    io:format("~p: ~.2f average: ~.2f~n",&lt;br /&gt;35:    Nexpected, Sum/Nexpected]).&lt;br /&gt;36:&lt;br /&gt;37: collect_results(0, _Nexpected, Results, Sum) -&gt; {Sum, Results};&lt;br /&gt;38: collect_results(Nremaining, Nexpected, Results, Sum) -&gt;&lt;br /&gt;39:    receive&lt;br /&gt;40:       {Vclient, Time} -&gt;&lt;br /&gt;41:          collect_results(Nremaining-1, Nexpected,&lt;br /&gt;42:          [{Vclient, Time}|Results], Sum+Time)&lt;br /&gt;43:    end.&lt;br /&gt;&lt;/pre&gt;I am not going to write a Erlang tutorial here; I am a complete Erlang newbie and would not do it justice. The &lt;a href="http://erlang.org/doc.html"&gt;Erlang documentation section&lt;/a&gt; is a good place to start for those who are interested. What I will do is provide a brief overview of this application.&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Lines 4-18 are the virtual clients that will send requests to the SUT (System Under Test). timed_request (lines 14-18) makes the actual request to the server; vclient_acc accumulates the response times for each command in the script. A script is a list of commands of the format {Delay, URL}. For each command in the script, the virtual client waits for a random time in the range Delay..2*Delay and then makes a request for URL.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Lines 2o-30 launch the the virtual clients. Each client runs the same script and starts executing immediately when it is spawned. The key is ramp/4, which in turn hits the SUT with Nstart, (Nstart+Nstep), (Nstart+2*Nstep)... Nend virtual clients.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Lines 32-42 collect and report the results.&lt;/li&gt;&lt;/ul&gt;So is this proof of concept load tester useful for anything? See my previous article, "&lt;a href="http://effectiveqa.blogspot.com/2009/12/results-using-simple-erlang-load-tester.html"&gt;Results using a simple Erlang load tester&lt;/a&gt;" to find out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5963350864821674235-2596328025456856389?l=effectiveqa.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/2596328025456856389/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5963350864821674235&amp;postID=2596328025456856389&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/2596328025456856389'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/2596328025456856389'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/2009/12/minimal-erlang-script-for-load-testing.html' title='A minimal Erlang script for load testing'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5963350864821674235.post-332200371493496255</id><published>2009-12-05T17:43:00.013-07:00</published><updated>2009-12-14T09:28:42.890-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quality'/><category scheme='http://www.blogger.com/atom/ns#' term='load testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Hudson'/><category scheme='http://www.blogger.com/atom/ns#' term='stress testing'/><category scheme='http://www.blogger.com/atom/ns#' term='performance testing'/><category scheme='http://www.blogger.com/atom/ns#' term='Erlang'/><title type='text'>Results using a simple Erlang load tester</title><content type='html'>Having written a minimal load tester in &lt;a href="http://www.erlang.org/"&gt;Erlang&lt;/a&gt;, the next step was to try producing useful results with it. I downloaded the latest version of &lt;a href="http://hudson-ci.org/"&gt;Hudson&lt;/a&gt;, my favorite continuous integration tool. It comes "pre-loaded" with &lt;a href="http://winstone.sourceforge.net/"&gt;Winstone&lt;/a&gt;, a lightweight server container. What kind of load can Hudson handle? I started by devising a short script. After a random time within the specified range, the client requests a specific page:&lt;br /&gt;&lt;br /&gt;&lt;iframe src="http://spreadsheets.google.com/pub?key=tFj4G8WXEH8Y2fek13e1kvw&amp;amp;single=true&amp;amp;gid=0&amp;amp;range=A1%3AB10&amp;amp;output=html&amp;amp;widget=true" frameborder="0" height="310" width="280"&gt;&lt;/iframe&gt;&lt;br /&gt;&lt;br /&gt;Clearly this faster than most users will navigate around Hudson, so this script is something of a worst-case.&lt;br /&gt;&lt;br /&gt;I then ran the script 10 times, recording the results:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_07MQFGLRKcI/Sxvgy7VfHZI/AAAAAAAAAok/9Ja4SNJwNhw/s1600-h/load_testing_hudson_table.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 124px;" src="http://4.bp.blogspot.com/_07MQFGLRKcI/Sxvgy7VfHZI/AAAAAAAAAok/9Ja4SNJwNhw/s400/load_testing_hudson_table.png" alt="" id="BLOGGER_PHOTO_ID_5412166542741675410" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The red cells in the spreadsheet indicate where Hudson became unresponsive. The red cells containing "10.00" actually did not respond; I added those values for the purpose of making this graph:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_07MQFGLRKcI/SxvA10eZKWI/AAAAAAAAAoc/Llsy9fEyaoM/s1600-h/load_testing_hudson.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 291px;" src="http://2.bp.blogspot.com/_07MQFGLRKcI/SxvA10eZKWI/AAAAAAAAAoc/Llsy9fEyaoM/s400/load_testing_hudson.png" alt="" id="BLOGGER_PHOTO_ID_5412131408067504482" border="0" /&gt;&lt;/a&gt;Pretty clearly, Hudson is comfortable with up to 9 simultaneous clients. When moving to 12, performance starts to degrade, but is still acceptable. At 15, there were some outright failures. If this Hudson instance is intended to handle more than 12 simultaneous clients, adjustments are necessary.&lt;br /&gt;&lt;br /&gt;With a quick look through the log files, I found the problem almost immediately:&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(51, 0, 153);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;Caused by: java.lang.OutOfMemoryError: Java heap space&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;So it may be pretty easy to increase load capacity for Hudson. Good news - my tiny little script found a problem before my customers did.&lt;br /&gt;&lt;br /&gt;In a future post, I'll see what a little parameter tuning does for Hudson load handling.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5963350864821674235-332200371493496255?l=effectiveqa.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/332200371493496255/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5963350864821674235&amp;postID=332200371493496255&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/332200371493496255'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/332200371493496255'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/2009/12/results-using-simple-erlang-load-tester.html' title='Results using a simple Erlang load tester'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_07MQFGLRKcI/Sxvgy7VfHZI/AAAAAAAAAok/9Ja4SNJwNhw/s72-c/load_testing_hudson_table.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5963350864821674235.post-4760309059649813810</id><published>2009-11-24T05:50:00.003-07:00</published><updated>2009-11-27T09:01:06.391-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Windows'/><category scheme='http://www.blogger.com/atom/ns#' term='virtualization'/><title type='text'>"The Parallel port driver service failed to start" when booting in Hyper-V</title><content type='html'>At work I've been moving our 2003 Enterprise virtual machines from Microsoft's &lt;a href="http://www.microsoft.com/windows/virtual-pc/support/virtual-pc-2007.aspx"&gt;Virtual PC 2007&lt;/a&gt; to their &lt;a href="http://www.microsoft.com/windowsserver2008/en/us/hyperv-main.aspx"&gt;Hyper-V&lt;/a&gt; platform. Generally this process went smoothly, with one exception; when booting, an error dialog was displayed:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;The Parallel port driver service failed to start due to the following error:&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;The service cannot be started, either because it is disabled or because it has no enabled devices associated with it.&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;After a bit of searching, I discovered there is a registry setting that will turn off this message. Using &lt;a href="http://en.wikipedia.org/wiki/Windows_Registry"&gt;regedit&lt;/a&gt;, navigate to:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(153, 0, 0);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&amp;nbsp; &amp;nbsp;HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Parport&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;and set:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold; color: rgb(153, 0, 0);font-size:85%;" &gt;&lt;span style="font-family:courier new;"&gt;&amp;nbsp; &amp;nbsp;Start = 4&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Viola, no more error message during boot up.&lt;br /&gt;&lt;br /&gt;Reference: &lt;a href="http://support.microsoft.com/kb/935497/en-us"&gt;Microsoft Support&lt;/a&gt; (this article references Vista / 2008 Server, but it worked fine with 2003 Enterprise SP2)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5963350864821674235-4760309059649813810?l=effectiveqa.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/4760309059649813810/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5963350864821674235&amp;postID=4760309059649813810&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/4760309059649813810'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/4760309059649813810'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/2009/11/parallel-port-driver-service-failed-to.html' title='&quot;The Parallel port driver service failed to start&quot; when booting in Hyper-V'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5963350864821674235.post-2649287516374486205</id><published>2009-02-13T07:44:00.008-07:00</published><updated>2009-12-06T12:20:43.062-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quality'/><category scheme='http://www.blogger.com/atom/ns#' term='virtualization'/><title type='text'>Using virtualization to improve quality and shorten QA time</title><content type='html'>&lt;a href="mailto:michael.g.oleary@rht.com"&gt;Michael O'Leary&lt;/a&gt; at &lt;a href="http://www.roberthalftechnology.com/"&gt;Robert Half Technology&lt;/a&gt; asked me to speak to some of their clients on virtualization and how it has helped me in my QA efforts. Here are the handouts and slides:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.effectiveqa.com/virtual/virtualization-handouts.doc"&gt;handouts&lt;/a&gt; (doc format)&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.effectiveqa.com/virtual/virtualization-slides.pdf"&gt;slides&lt;/a&gt; (pdf format)&lt;/li&gt;&lt;/ul&gt;I used a variety of online resources to prepare for my presentation:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:arial;font-size:130%;"  &gt;Introduction&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Popek_and_Goldberg_virtualization_requirements"&gt;http://en.wikipedia.org/wiki/Popek_and_Goldberg_virtualization_requirements&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Hypervisor"&gt;http://en.wikipedia.org/wiki/Hypervisor&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;font-family:arial;font-size:130%;"  &gt;Resources&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.infoworld.com/topic-center/virtualization/&amp;amp;source=fssr"&gt;http://www.infoworld.com/topic-center/virtualization/&amp;amp;source=fssr&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.virtualization.info/"&gt;http://www.virtualization.info/&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;font-family:arial;font-size:130%;"  &gt;x86 Hardware Support for Virtualization&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/X86_virtualization"&gt;http://en.wikipedia.org/wiki/X86_virtualization&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.intel.com/technology/virtualization/"&gt;http://www.intel.com/technology/virtualization/&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.amd.com/us-en/0,,3715_15781,00.html"&gt;http://www.amd.com/us-en/0,,3715_15781,00.html&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:arial;font-size:130%;"  &gt;Virtualization Providers&lt;/span&gt;&lt;br /&gt;(extremely abbreviated; see &lt;a href="http://en.wikipedia.org/wiki/Comparison_of_platform_virtual_machines"&gt;http://en.wikipedia.org/wiki/Comparison_of_platform_virtual_machines&lt;/a&gt;)&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.vmware.com/"&gt;http://www.vmware.com&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.microsoft.com/virtualization"&gt;http://www.microsoft.com/virtualization&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.xen.org/"&gt;http://www.xen.org&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.virtualbox.org/"&gt;http://www.virtualbox.org&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://citrix.com/"&gt;http://citrix.com&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;font-family:arial;font-size:130%;"  &gt;Automated Testing Tools&lt;/span&gt;&lt;br /&gt;Continuous integration (Hudson): &lt;a href="https://hudson.dev.java.net/"&gt;https://hudson.dev.java.net&lt;/a&gt;&lt;br /&gt;Technical debt: &lt;a href="http://sonar.codehaus.org/"&gt;http://sonar.codehaus.org&lt;/a&gt;&lt;br /&gt;Automated testing:  &lt;a href="http://wtr.rubyforge.org/"&gt;http://wtr.rubyforge.org/&lt;/a&gt;  &lt;a href="http://seleniumhq.org/"&gt;http://seleniumhq.org/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:arial;font-size:130%;"  &gt;Cloud Computing&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Cloud_computing"&gt;http://en.wikipedia.org/wiki/Cloud_computing&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.infoq.com/articles/cloud-comparison"&gt;http://www.infoq.com/articles/cloud-comparison&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.johnmwillis.com/cloud-computing/cloud-vendors-a-to-z-revised/"&gt;http://www.johnmwillis.com/cloud-computing/cloud-vendors-a-to-z-revised/&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://aws.amazon.com/ec2/"&gt;http://aws.amazon.com/ec2/&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.mosso.com/"&gt;http://www.mosso.com/&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.gogrid.com/"&gt;http://www.gogrid.com/&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;My thanks to Michael, Robert Half Technology and the attendees.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5963350864821674235-2649287516374486205?l=effectiveqa.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/2649287516374486205/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5963350864821674235&amp;postID=2649287516374486205&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/2649287516374486205'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/2649287516374486205'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/2009/02/using-virtualization-to-improve-quality.html' title='Using virtualization to improve quality and shorten QA time'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5963350864821674235.post-4953004720816071368</id><published>2008-08-28T08:23:00.009-06:00</published><updated>2008-09-02T15:34:03.805-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quality'/><category scheme='http://www.blogger.com/atom/ns#' term='technical debt'/><title type='text'>Criteria for Selecting a Technical Debt Calculator</title><content type='html'>In "&lt;a href="http://effectiveqa.blogspot.com/2008/08/calculating-technical-debt.html"&gt;Calculating Technical Debt&lt;/a&gt;", I proposed a set of criteria for selecting a technical debt calculator. This list was:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Plugin architecture&lt;/li&gt;&lt;li&gt;Flexible roll-up rules&lt;/li&gt;&lt;li&gt;Current perspective&lt;/li&gt;&lt;li&gt;Trend perspective&lt;/li&gt;&lt;li&gt;Languages supported&lt;/li&gt;&lt;li&gt;Environments supported&lt;/li&gt;&lt;li&gt;Supports qualitative data&lt;/li&gt;&lt;li&gt;Build environments&lt;/li&gt;&lt;li&gt;Custom dashboards&lt;/li&gt;&lt;li&gt;Aggregates multiple projects&lt;/li&gt;&lt;li&gt;Continuous integration servers&lt;/li&gt;&lt;li&gt;User community&lt;/li&gt;&lt;/ul&gt;To this list I added a few more criteria relevant to using the tools:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Tool quality (is the quality calculator buggy?)&lt;/li&gt;&lt;li&gt;Latest release (is this project alive?)&lt;/li&gt;&lt;li&gt;Documentation (can I figure out how to use it?)&lt;/li&gt;&lt;/ul&gt;In "&lt;a href="http://effectiveqa.blogspot.com/2008/08/characteristcs-of-technical-debt.html"&gt;Characteristics of Technical Debt&lt;/a&gt;", I came to the conclusion that the McConnell internal quality characteristics were well suited to calculating technical debt. His criteria belong on the list then:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Calculates maintainability&lt;/li&gt;&lt;li&gt;Calculates flexibility&lt;/li&gt;&lt;li&gt;Calculates portability&lt;/li&gt;&lt;li&gt;Calculates reusability&lt;/li&gt;&lt;li&gt;Calculates readability&lt;/li&gt;&lt;li&gt;Calculates testability&lt;/li&gt;&lt;li&gt;Calculates understandability&lt;/li&gt;&lt;/ul&gt;I make no claim this list is exhaustive, but it covers enough of the issues important to me that I am comfortable moving forward with it.&lt;br /&gt;&lt;br /&gt;In making these evaluations, I need some projects to run through the tools to see how they perform. The obvious choice is some open-source projects. These projects should:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Be developed in Java&lt;/li&gt;&lt;li&gt;Have their development history captured in a version control system&lt;/li&gt;&lt;li&gt;Have high development activity&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Have JUnit tests&lt;/li&gt;&lt;li&gt;Some built with Ant, some with Maven 2&lt;/li&gt;&lt;/ul&gt;A trip around a few open-source repositories turned up a few likely candidates:&lt;br /&gt;&lt;br /&gt;&lt;div&gt;&lt;a href="http://jena.sourceforge.net/"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Jena&lt;/span&gt;&lt;/span&gt;&lt;/a&gt; - A framework for building Semantic Web applications. I'll focus on the ARQ component. (Ant)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Jena (ARQ module) has eight releases in its Subversion tags folder:&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$&gt; svn ls https://jena.svn.sourceforge.net/svn/root/jena/ARQ/tags&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;ARQ-2.0/&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;ARQ-2.0-RC/&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;ARQ-2.0-beta/&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;ARQ-2.1/&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;ARQ-2.1-beta/&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;ARQ-2.2/&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;ARQ-2.3/&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;ARQ-2.4/&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;a href="http://tiles.apache.org/"&gt;&lt;span class="Apple-style-span" style="font-weight: bold;"&gt;&lt;span class="Apple-style-span" style="font-size: large;"&gt;Tiles&lt;/span&gt;&lt;/span&gt;&lt;/a&gt; - A Web templating framework.  (Maven 2)&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Tiles has eight releases in its Subversion tags folder:&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;$&gt;svn ls http://svn.apache.org/repos/asf/tiles/framework/tags&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;tiles-2.0.0/&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;tiles-2.0.1/&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;tiles-2.0.2/&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;tiles-2.0.3/&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;tiles-2.0.4/&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;tiles-2.0.5/&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;tiles-2.0.6/&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;tiles-2.1.0/&lt;/span&gt;&lt;/div&gt;&lt;/blockquote&gt;&lt;div&gt;This would seem a trivial matter to pick out some projects to use as a basis for our tool evaluation. It turns out this is not so. I won't bore you with the reasons, but this took WAY longer than I expected.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;With criteria and test cases in hand, I'll move on to evaluating the options. &lt;a href="http://sonar.codehaus.org/"&gt;Sonar&lt;/a&gt; seems like a reasonable place to start.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5963350864821674235-4953004720816071368?l=effectiveqa.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/4953004720816071368/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5963350864821674235&amp;postID=4953004720816071368&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/4953004720816071368'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/4953004720816071368'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/2008/08/criteria-for-selecting-technical-debt.html' title='Criteria for Selecting a Technical Debt Calculator'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5963350864821674235.post-2757552744544209736</id><published>2008-08-25T16:54:00.013-06:00</published><updated>2008-08-26T10:02:14.278-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quality'/><category scheme='http://www.blogger.com/atom/ns#' term='technical debt'/><title type='text'>Characteristcs of Technical Debt</title><content type='html'>I was planning to launch into an evaluation of the tools identified in "&lt;a href="http://effectiveqa.blogspot.com/2008/08/calculating-technical-debt.html"&gt;Calculating Technical Debt&lt;/a&gt;" (please read that first if you have no idea what I am talking about), but in preparing for the evaluation, I discovered there are large bodies of work addressing the characteristics of interest for determining code quality. There is even an ISO standard (&lt;a href="http://en.wikipedia.org/wiki/ISO_9126"&gt;9126&lt;/a&gt;) defining one such set of quality characteristics.&lt;br /&gt;&lt;br /&gt;I guess it was pretty naive of me to think that quantifying software quality was a new undertaking. There are five models that appear repeatedly in the literature:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Boehm&lt;/li&gt;&lt;li&gt;McCall&lt;/li&gt;&lt;li&gt;FURPS&lt;/li&gt;&lt;li&gt;ISO 9126&lt;/li&gt;&lt;li&gt;Dromey&lt;/li&gt;&lt;/ul&gt;Each model has a different focus and thus includes different characteristics to assess quality (see &lt;a href="http://www.secc.org.eg/SEPG%202006/Ingredients/PDF_files/215.pdf"&gt;reference&lt;/a&gt; page 38). The following table summarizes these top five models:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_07MQFGLRKcI/SLNt_UFv2sI/AAAAAAAAAYg/TNHIJxTl7oc/s1600-h/matrix.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_07MQFGLRKcI/SLNt_UFv2sI/AAAAAAAAAYg/TNHIJxTl7oc/s400/matrix.png" alt="" id="BLOGGER_PHOTO_ID_5238651726054021826" border="0" /&gt;&lt;/a&gt;&lt;span style="font-size:85%;"&gt;Reference: Ortega, Maryoly; Pérez, María and Rojas, Teresita. Construction of a Systemic Quality Model for evaluating a Software Product. Software Quality Journal, 11:3, July 2003, pp. 219-242. Kluwer Academic Publishers, 2003&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;In "&lt;a href="http://effectiveqa.blogspot.com/2008/08/quantifying-cost-of-expediency.html"&gt;Quantifying the cost of expediency&lt;/a&gt;", I proposed using McConnell's "internal quality characteristics" from &lt;a href="http://www.amazon.com/Complete-Microsoft-Programming-Steve-McConnell/dp/1556154844"&gt;Code Complete&lt;/a&gt;. Does this still hold up in light of these large bodies of research? Lets see.&lt;br /&gt;&lt;br /&gt;In a perfect world, I'd take the time research all of these models along with the various hybrids that have been devised. Perhaps I'll formulate my own model one day and become rich and famous. My goal for now is not to devise the optimal model, but rather to create a proof-of-concept for  calculating the cost of expedient design and development choices.&lt;br /&gt;&lt;br /&gt;From a cursory literature search, it appears that ISO 9126 is the most widely used model. I'll use that as the basis for comparison.&lt;br /&gt;&lt;br /&gt;The ISO 9126 standard is summarized by the following graph:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_07MQFGLRKcI/SLNGVI3vSDI/AAAAAAAAAYY/o4P8DWKD-d8/s1600-h/ISODiagram.gif"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_07MQFGLRKcI/SLNGVI3vSDI/AAAAAAAAAYY/o4P8DWKD-d8/s400/ISODiagram.gif" alt="" id="BLOGGER_PHOTO_ID_5238608120534485042" border="0" /&gt;&lt;/a&gt;(from &lt;a href="http://www.cse.dcu.ie/"&gt;http://www.cse.dcu.ie&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;As you can see from the graph, the ISO model defines six major characteristics of quality:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Functionality&lt;/li&gt;&lt;li&gt;Reliability&lt;/li&gt;&lt;li&gt;Efficiency&lt;/li&gt;&lt;li&gt;Usability&lt;/li&gt;&lt;li&gt;Portability&lt;/li&gt;&lt;li&gt;Maintainability&lt;/li&gt;&lt;/ul&gt;Each is further decomposed. Comparing ISO 9126 with McConnell, you'll notice that McConnell is missing characteristics like accuracy and efficiency.  He actually presented a separate list "external quality characteristics". These refer to customer-facing issues rather than developer-facing issues. Most of the ISO 9126 characteristics missing in his internal list appear there. Intuitively external characteristics are fundamental to understanding technical debt. They are also more difficult to determine automatically. I am going to choose to postpone including them in the technical debt evaluation for now - it is the &lt;span style="font-style: italic;"&gt;expedient &lt;/span&gt;thing to do. ;-)&lt;br /&gt;&lt;br /&gt;The characteristics on McConnell's list that don't appear in ISO 9126 are flexibility and reusability. These characteristics seem relevant to the technical debt of a project. Flexibility and reusability do appear in the McCall model (see table). McConnell provides the following definitions (p. 558):&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt;&lt;blockquote&gt;&lt;span style="font-weight: bold;"&gt;Flexibility &lt;/span&gt;- The extent to which you can modify a system for uses or environments other than those for which it was specifically designed.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Reusability &lt;/span&gt;- The extent to which and the ease with which you can use parts of a system in other systems.&lt;/blockquote&gt;After all this, I am back to where I started. That is not where I expected to be. The original title of this entry was something like "An ISO model for technical debt". It was not until I started comparing ISO 9126 with McConnell that I came to the conclusion that McConnell better serves my purpose.&lt;br /&gt;&lt;br /&gt;In the next entry I'll return to looking at the available tools for calculating technical debt.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5963350864821674235-2757552744544209736?l=effectiveqa.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/2757552744544209736/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5963350864821674235&amp;postID=2757552744544209736&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/2757552744544209736'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/2757552744544209736'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/2008/08/characteristcs-of-technical-debt.html' title='Characteristcs of Technical Debt'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_07MQFGLRKcI/SLNt_UFv2sI/AAAAAAAAAYg/TNHIJxTl7oc/s72-c/matrix.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5963350864821674235.post-3597163636033564904</id><published>2008-08-20T15:25:00.008-06:00</published><updated>2008-08-26T10:02:43.980-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quality'/><category scheme='http://www.blogger.com/atom/ns#' term='technical debt'/><title type='text'>Calculating Technical Debt</title><content type='html'>In "&lt;a href="http://effectiveqa.blogspot.com/2008/08/quantifying-cost-of-expediency.html"&gt;Quantifying the cost of expediency&lt;/a&gt;", I describe the problem IT management face when they trade off shorter development time with robust code. To recap, my conjecture is that a solution to understanding such trade offs can be reached by sub-dividing the problem into two phases and addressing each individually. The phases are:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Evaluate the code base against a set of quality criteria and track trends&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Convert these metrics into an easily digestible form&lt;/li&gt;&lt;/ol&gt;At the AgileNM meeting today, I learned there is a term for the code degradation that often occurs in a software project: &lt;span style="font-weight: bold;"&gt;technical debt&lt;/span&gt;. We had an excellent discussion of qualitative ways attendees assess this cost. These included:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Decreases in team velocity over time&lt;/li&gt;&lt;li&gt;Developer time to understand unfamiliar code&lt;/li&gt;&lt;li&gt;Querying developers&lt;/li&gt;&lt;/ul&gt;How exciting to have this group interested in the very topic I've been pondering and writing about! In looking for quantitative measures of technical debt, my research turned up several candidates for calculating the current debt and tracking trends. This list is shamelessly lifted from the &lt;a href="http://sonar.codehaus.org/related-tools/"&gt;Sonar Related Tools&lt;/a&gt; page:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Open Source&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://sonar.codehaus.org/"&gt;Sonar&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://mojo.codehaus.org/dashboard-maven-plugin/"&gt;Maven Dashboard Report Plugin&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://qalab.sourceforge.net/"&gt;QALab&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://xradar.sourceforge.net/"&gt;XRadar&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;Commercial&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.castsoftware.com/"&gt;CAST Software&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.metrixware.com/"&gt;SC Metrics from MetrixWare&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.mccabe.com/"&gt;McCabe IQ&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;The commercial tools don't appear to have evaluation downloads, so I'll focus on open source tools for now. Perhaps I can get evaluation copies in the future.&lt;br /&gt;&lt;br /&gt;The open-source tools all leverage other open-source tools that determine one or more pieces of the technical-debt picture. &lt;a href="http://checkstyle.sourceforge.net/"&gt;Checkstyle&lt;/a&gt;, &lt;a href="http://pmd.sourceforge.net/"&gt;PMD&lt;/a&gt; and &lt;a href="http://pmd.sourceforge.net/cpd.html"&gt;CPD&lt;/a&gt; are static analysis tools while &lt;a href="http://www.junit.org/"&gt;JUnit&lt;/a&gt; and &lt;a href="http://cobertura.sourceforge.net/"&gt;Cobertura&lt;/a&gt; are runtime tools which all contribute to understanding the debt .&lt;br /&gt;&lt;br /&gt;The open-source tools are all Java-centric. I'll search for similar .Net tools.&lt;br /&gt;&lt;br /&gt;Originally, I had planned to jump into Sonar but, given the alternatives, it seemed prudent to consider what features best support calculating technical debt. I haven't looked at any of them closely yet, so hopefully this list isn't overly biased:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Plugin architecture for adding new analysis tools&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Flexible rules for rolling up results into characteristics&lt;/li&gt;&lt;li&gt;Current and trend perspectives&lt;/li&gt;&lt;li&gt;Support for multiple languages and environments&lt;/li&gt;&lt;li&gt;Able to consider qualitative data in calculating characteristics&lt;/li&gt;&lt;li&gt;Support for multiple build tools&lt;/li&gt;&lt;li&gt;Flexible dashboard creation to display results&lt;/li&gt;&lt;li&gt;Interfaces to continuous integration servers&lt;/li&gt;&lt;li&gt;Vigorous user community&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;In the next installment I'll present my take on how the open source tools stack up against this feature set.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5963350864821674235-3597163636033564904?l=effectiveqa.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/3597163636033564904/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5963350864821674235&amp;postID=3597163636033564904&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/3597163636033564904'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/3597163636033564904'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/2008/08/calculating-technical-debt.html' title='Calculating Technical Debt'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5963350864821674235.post-27972553201248444</id><published>2008-08-13T17:44:00.013-06:00</published><updated>2008-08-26T10:03:48.277-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quality'/><category scheme='http://www.blogger.com/atom/ns#' term='technical debt'/><title type='text'>Quantifying the Cost of Expediency</title><content type='html'>Software project managers often ask teams to proceed at the greatest possible speed without regard for the long-term consequences to code quality. Lets call such choices "expedient". If expedient choices are made infrequently, the development team can recover by refactoring the tainted code. For many shops though expediency becomes the norm rather than the exception. The downside of expedient choices is not initially apparent. There is an uneasy feeling in our stomach, but nothing tangible to explain why. The upside usually is apparent since it can (with some accounting magic) be measured in dollars. My contention is that to make informed decisions managers need the ability to measure the "expediency cost" in dollars too.&lt;br /&gt;&lt;br /&gt;We have some idea of this cost to the industry as a whole. Capers Jones estimated that &lt;a href="http://www.ispw.com/articles/Computer%20Finance.htm"&gt;almost two-thirds of developer time is spent repairing software&lt;/a&gt;. In &lt;a href="http://www.amazon.com/Complete-Microsoft-Programming-Steve-McConnell/dp/1556154844"&gt;Code Complete&lt;/a&gt;, he states:&lt;br /&gt;&lt;blockquote&gt;Projects that aim from the beginning at achieving the shortest possible schedules regardless of quality considerations, tend to have the fairly high frequencies of both schedule and cost overruns. Software projects that aim initially at achieving the highest possible levels of quality and reliability tend to have the best schedule adherence records, the highest productivity, and even the best marketplace success.&lt;/blockquote&gt;So evidence suggests we're heading down the wrong path when we attempt to be expedient, but how do we quantify this cost? What should high quality code look like?&lt;br /&gt;&lt;br /&gt;In &lt;a href="http://www.amazon.com/Complete-Microsoft-Programming-Steve-McConnell/dp/1556154844"&gt;Code Complete&lt;/a&gt; McConnell lays out the following categories for internal quality characteristics (descriptions are paraphrased):&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Maintainability &lt;/span&gt;- Can the software be modified?&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Flexibility &lt;/span&gt;- Can the software be repurposed?&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Portability &lt;/span&gt;- Can the software be ported to new environments?&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Reusability &lt;/span&gt;- Can the software be used in other systems?&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Readability &lt;/span&gt;- Can the source code be read?&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Testability &lt;/span&gt;- Can the software be verified correct?&lt;/li&gt;&lt;li&gt;&lt;span style="font-weight: bold;"&gt;Understandability &lt;/span&gt;- Can the software be understood at the system-organizational level?&lt;/li&gt;&lt;/ul&gt;I propose then the task is two-fold. First, evaluate the code base against these criteria. This includes tracking metric changes over time. Second, convert these metrics into information management can use to make informed trade-offs between quality and expediency. If this information is ultimately mapped to dollars, a real apples to apples comparison of the cost of expediency can be made.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5963350864821674235-27972553201248444?l=effectiveqa.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/27972553201248444/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5963350864821674235&amp;postID=27972553201248444&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/27972553201248444'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/27972553201248444'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/2008/08/quantifying-cost-of-expediency.html' title='Quantifying the Cost of Expediency'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5963350864821674235.post-6347028633774918732</id><published>2008-07-05T21:41:00.007-06:00</published><updated>2009-12-06T12:22:00.255-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='RDoc'/><category scheme='http://www.blogger.com/atom/ns#' term='quality'/><category scheme='http://www.blogger.com/atom/ns#' term='Code Reviews'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Practice what I Preach - Code Reviews, TDD and RDoc</title><content type='html'>The first internal release (0.1) of my ongoing attempt to "practice what I preach" is complete. The program works well, has high coverage and acted as a catalyst for many of the quality tools and practices I've been discussing. Three things stuck out in my mind as I completed the release:&lt;br /&gt;&lt;br /&gt;(1) Even on a one-man project, code reviews are beneficial. One night I spent hours in the debugger plus adding puts everywhere to complete the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;refactoring&lt;/span&gt; to &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_1"&gt;accommodate&lt;/span&gt; changes. It was one of those late nights when I should have probably just walked away. What I realized when it was finished is that about 10 minutes of inspecting the code would have produced the same results as my hours of debugging. Perhaps all of you are smarter than me and wouldn't have this outcome, but give it a try sometime and see if inspection isn't faster. Or better yet, try an informal code review with a co-worker.&lt;br /&gt;&lt;br /&gt;(2) I was shocked at how much completing the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;RDoc&lt;/span&gt; improved my code. When I started to write about something and it was complete hogwash, I could either try and explain why I had written complete hogwash or I could clean it up. It was about the same amount of work, so why not clean up the code? An example was the large increase in private methods. If they are private, I don't need to write docs on them. :-)&lt;br /&gt;&lt;br /&gt;(3) I wrote most tests and competed the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;RDoc&lt;/span&gt; after the coding was complete. They came out well, so why not keep doing this? Because for my project, these activities &lt;span style="font-weight: bold;"&gt;are the point&lt;/span&gt;. So of course I will finish them. At my day job, the code is (mostly) the point. So while I took the time to do the "right thing" at home, at work I would've been under extreme pressure to move onto the next task. Even if you don't believe TDD will deliver higher quality code, it is worth doing just so testing (and doc) get done &lt;span style="font-style: italic;"&gt;at all&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;I am researching how to quantify "code rot". My management can &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_4"&gt;quantify&lt;/span&gt; the gains of pushing code out the door half-baked if they can attract new customers as a result. But they don't have the foggiest idea what it has cost them in terms of their major asset - the code base which is essential to the viability of the business. If there were some code rot number(s) which were &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_5"&gt;convertible&lt;/span&gt; into dollars, the number of jackass decisions may well decrease. Anyone have ideas on this?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5963350864821674235-6347028633774918732?l=effectiveqa.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/6347028633774918732/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5963350864821674235&amp;postID=6347028633774918732&amp;isPopup=true' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/6347028633774918732'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/6347028633774918732'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/2008/07/practice-what-i-preach-code-reviews-tdd.html' title='Practice what I Preach - Code Reviews, TDD and RDoc'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5963350864821674235.post-7876283120260441859</id><published>2008-06-25T13:36:00.007-06:00</published><updated>2009-12-06T12:22:38.407-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quality'/><category scheme='http://www.blogger.com/atom/ns#' term='Test::Unit'/><category scheme='http://www.blogger.com/atom/ns#' term='Hudson'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Rake'/><title type='text'>Test::Unit, Rake and Hudson status</title><content type='html'>All the &lt;a href="https://hudson.dev.java.net/"&gt;Hudson&lt;/a&gt; &lt;a href="http://www.ruby-doc.org/stdlib/libdoc/test/unit/rdoc/classes/Test/Unit.html"&gt;Test::Unit&lt;/a&gt; tests were passing. A sea of success. Then I started looking at the result files. All was not good after all. The unit tests were not really passing, even though Hudson said they were:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_07MQFGLRKcI/SGRd0roFk9I/AAAAAAAAAXI/Z1PVq7Itce4/s1600-h/HudsonLog.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_07MQFGLRKcI/SGRd0roFk9I/AAAAAAAAAXI/Z1PVq7Itce4/s400/HudsonLog.png" alt="" id="BLOGGER_PHOTO_ID_5216397428047320018" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;I spent a long time trying to figure out who was dropping the ball on the status. Was it Test::Unit? &lt;a href="http://rake.rubyforge.org/"&gt;Rake&lt;/a&gt;? Windows? Hudson? I never found a definitive answer, though it was starting to look like it might be Test::Unit.&lt;br /&gt;&lt;br /&gt;I did find &lt;a href="http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/244979"&gt;this post&lt;/a&gt; and gave it a try. Unfortunately, this solution works when there is a non-zero exit status, but this is not the case when running Unit::Test from rake.&lt;br /&gt;&lt;br /&gt;The solution turned out to be much simpler than trying to figure out how to correct Rake or Test::Unit. Hudson to the rescue. Hudson supports a &lt;a href="http://hudson.gotdns.com/wiki/display/HUDSON/Plugins"&gt;plugin architecture&lt;/a&gt;. The &lt;a href="https://hudson.dev.java.net/servlets/ProjectDocumentList?expandFolder=5818&amp;amp;folderID=0"&gt;repository&lt;/a&gt; has a plugin named &lt;a href="http://hudson.gotdns.com/wiki/display/HUDSON/Text-finder+Plugin"&gt;Text-finder Plugin&lt;/a&gt; (&lt;a href="https://hudson.dev.java.net/servlets/ProjectDocumentList?folderID=6769&amp;amp;expandFolder=6769&amp;amp;folderID=5818"&gt;download it here&lt;/a&gt;). It determines the success or failure of a build by looking for a regular expression in the build artifacts or system output.  I added a rule which looks for the expression &lt;span style="font-weight: bold; color: rgb(51, 0, 153);"&gt;/\d+ tests, \d+ assertions, 0 failures, 0 errors/ &lt;/span&gt;in the console output. If the expression is found, the build passes; otherwise it fails. Once installed the configuration panel has this section:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_07MQFGLRKcI/SGRbSUC3d0I/AAAAAAAAAXA/ZaUYvfTv5cY/s1600-h/HudsonFinder.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_07MQFGLRKcI/SGRbSUC3d0I/AAAAAAAAAXA/ZaUYvfTv5cY/s400/HudsonFinder.png" alt="" id="BLOGGER_PHOTO_ID_5216394638578382658" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;Yet again Hudson solves the problem where other players are dropping the ball. The Hudson status now accurately conveys the result of running the unit tests.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5963350864821674235-7876283120260441859?l=effectiveqa.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/7876283120260441859/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5963350864821674235&amp;postID=7876283120260441859&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/7876283120260441859'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/7876283120260441859'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/2008/06/testunit-rake-and.html' title='Test::Unit, Rake and Hudson status'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_07MQFGLRKcI/SGRd0roFk9I/AAAAAAAAAXI/Z1PVq7Itce4/s72-c/HudsonLog.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5963350864821674235.post-2634315661861570211</id><published>2008-06-14T13:21:00.012-06:00</published><updated>2009-12-06T12:23:28.333-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quality'/><category scheme='http://www.blogger.com/atom/ns#' term='mock'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='FlexMock'/><title type='text'>Ruby - Making a Mockery of Testing</title><content type='html'>Having gotten rcov working well, I now had to eat the bitter fruit of my low coverage. The main code talks to a news server, so testing would not be so simple as calling a few methods and checking the results. Perhaps I still need to refactor into smaller, more easily testable methods. I'll visit that at another time.&lt;br /&gt;&lt;br /&gt;The solution is to "mock" the news server. A mock is code that provides the same interface (or at least enough of it for the tests) as a "real" object or class, yet return expected data each time the test is run. Mocks also can be configured to know how many times a method should be called, in what order they are called, the values that should be passed in and so on. If these conditions are not met, an error is thrown and the test fails.&lt;br /&gt;&lt;p&gt;Ruby has several tools for creating mock objects. I settled on &lt;a href="http://flexmock.rubyforge.org/"&gt;Flex Mock&lt;/a&gt; after reading a few blogs. Others were passionate about &lt;a href="http://mocha.rubyforge.org/"&gt;Mocha&lt;/a&gt; - I'll take a look at that another time.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;For the purposes of my test, a &lt;a href="http://rubyforge.org/projects/ruby-net-nntp/"&gt;Ruby newsreaderAPI&lt;/a&gt; needs to provide the following methods:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Net::NNTP.new(host, port, timeout) - Specify the &lt;em&gt;host,&lt;/em&gt; &lt;em&gt;port&lt;/em&gt; and &lt;em&gt;timeout&lt;/em&gt; values to use when connecting (&lt;strong&gt;class method&lt;/strong&gt;)&lt;/li&gt;&lt;li&gt;Net::NNTP.connect() - Connect to the host with parameters set in new.&lt;/li&gt;&lt;li&gt;Net::NNTP.xover(groupname, :from=&gt;low, :to=&gt;high) - Retrieve the headers from group &lt;em&gt;groupname&lt;/em&gt; in the range &lt;em&gt;low..high&lt;/em&gt;&lt;/li&gt;&lt;li&gt;Net::NNTP.group(group) - Set the &lt;em&gt;group&lt;/em&gt; to fetch articles from&lt;/li&gt;&lt;li&gt;Net::NNTP.article(id) - Retrieve the article with the given &lt;em&gt;id&lt;/em&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Notice there is one class method to mock. After a little looking, I found the answer in the &lt;a href="http://onestepback.org/software/flexmock/"&gt;README file&lt;/a&gt; (see section "Mocking Class Objects) for FlexMock. The answer is to have the class method return another flexmock object which is the instance.&lt;/p&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;nntp_mock = flexmock&lt;br /&gt;... more stuff here to define nntp_mock...&lt;br /&gt;flexmock(Net::NNTP).should_receive(:new).and_return(nntp_mock)&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;p&gt;Now when the Net::NNTP.new method is called, it will return our flexmock instance which handles the rest of the test.&lt;/p&gt;&lt;p&gt;Lets look at the flexmock instance object now:&lt;/p&gt;&lt;blockquote&gt;&lt;span style="font-size:85%;"&gt;&lt;span style="font-family:courier new;"&gt;nntp_mock = flexmock&lt;br /&gt;nntp_mock.should_receive(:connect).once.&lt;br /&gt;   with_no_args&lt;br /&gt;nntp_mock.should_receive(:group).once.&lt;br /&gt;   with(String).and_return(group_mock)&lt;br /&gt;nntp_mock.should_receive(:xover).once.&lt;br /&gt;   with(String, Hash).and_return([summary1, summary2])&lt;br /&gt;nntp_mock.should_receive(:article).twice.&lt;br /&gt;   with(String).and_return(article1, article2)&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;&lt;p&gt;One interesting feature is that parameters may be chained together. So for example the last line specified that:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;It responds to the method call 'article'&lt;/li&gt;&lt;li&gt;It should be called exactly twice during the test (fail otherwise)&lt;/li&gt;&lt;li&gt;It must receive exactly one parameter which is a string&lt;/li&gt;&lt;li&gt;It returns the specified articles&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;So with just a few lines of code we've written a newsgroup reader application which is sufficient for our test. Its behavior is deterministic and further our test will fail if any of the expectations set for it fail. That is a lot of value for a small effort.&lt;/p&gt;&lt;p&gt;The &lt;a href="http://onestepback.org/software/flexmock/"&gt;README file&lt;/a&gt; is extensive and gave me enough information to write my mock.&lt;/p&gt;&lt;p&gt;The next time you need to write a test for code which references an external resource, mock it instead. You'll be happy you did.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5963350864821674235-2634315661861570211?l=effectiveqa.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/2634315661861570211/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5963350864821674235&amp;postID=2634315661861570211&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/2634315661861570211'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/2634315661861570211'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/2008/06/ruby-making-mockery-of-testing.html' title='Ruby - Making a Mockery of Testing'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5963350864821674235.post-4942864156932922072</id><published>2008-06-12T11:56:00.018-06:00</published><updated>2008-06-14T18:07:19.198-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='RDoc'/><category scheme='http://www.blogger.com/atom/ns#' term='Log4r'/><category scheme='http://www.blogger.com/atom/ns#' term='Confluence'/><category scheme='http://www.blogger.com/atom/ns#' term='Hudson'/><category scheme='http://www.blogger.com/atom/ns#' term='rcov'/><category scheme='http://www.blogger.com/atom/ns#' term='Trac'/><category scheme='http://www.blogger.com/atom/ns#' term='JIRA'/><category scheme='http://www.blogger.com/atom/ns#' term='TDD'/><title type='text'>Walking the Talk, a few days later</title><content type='html'>The "Walking the Talk" project is well underway. My progress has been brisk and I'm learning quite a bit along the way. The simplicity of Ruby is a gift, allowing me to understand the concepts involved without getting bogged down by endless details.&lt;br /&gt;&lt;br /&gt;Several tools were left out of the quality sandbox sandbox last time. &lt;a href="http://rdoc.sourceforge.net/"&gt;RDoc&lt;/a&gt; (source-embedded documentation ala JavaDoc) and &lt;a href="http://log4r.sourceforge.net/"&gt;Log4r&lt;/a&gt; (logfile support ala Log4J) are both useful tools for the agile developer. I'm still learning some of the finer points of each, but both were up and functioning at a basic level in no time. Expect to hear more about these in a future post.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Hudson&lt;/span&gt;&lt;br /&gt;&lt;a href="https://hudson.dev.java.net/"&gt;Hudson&lt;/a&gt; continues to be awesome. I just read on &lt;a href="http://weblogs.java.net/blog/kohsuke/archive/2008/05/ill_be_spending.html"&gt;Kohsuke Kawaguchi's Blog&lt;/a&gt; that Hudson and his other projects he's been doing in the background are going to become his day job. This is exciting news for Hudson fans! The brisk development pace will likely accelerate further.&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;TDD&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;I had an epiphany several months ago in our AgileNM meeting about TDD. A member said that TDD significantly reduced the &lt;a href="http://en.wikipedia.org/wiki/Cyclomatic_complexity"&gt;cyclomatic complexity&lt;/a&gt; of the code. Ah, TDD is not about having better tests, it is about writing better code! I'll relate my personal experience with this a little later, but let's just say for now that my personal experience has only increased my enthusiasm! Take a look at &lt;a href="http://www.acm.org/src/subpages/gf_entries_06/DavidJanzen_src_gf06.pdf"&gt;this paper&lt;/a&gt; from David Jansen of the University of Kansas for more background.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;rcov&lt;/span&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_07MQFGLRKcI/SFHLpvgyD1I/AAAAAAAAAR8/5CEOrRyTSmU/s1600-h/rcovExample.png"&gt;&lt;img id="BLOGGER_PHOTO_ID_5211170161833414482" style="margin: 0pt 0pt 10px 10px; float: right; cursor: pointer;" alt="" src="http://4.bp.blogspot.com/_07MQFGLRKcI/SFHLpvgyD1I/AAAAAAAAAR8/5CEOrRyTSmU/s200/rcovExample.png" border="0" /&gt;&lt;/a&gt;&lt;a href="http://eigenclass.org/hiki.rb?rcov"&gt;rcov&lt;/a&gt; pretty much worked as expected. There were only two ways that it fell short of the standard set by Cobertura for me. The first was the lack of hit counts for each line. I found this interesting to understand where the hot spots in the code might be even before firing up a profiler.&lt;br /&gt;&lt;br /&gt;The other shortcoming of rcov compared to Cobertura is that it does not include cyclomatic complexity analysis. After a little Googling, it appears that &lt;a href="http://saikuro.rubyforge.org/"&gt;Saikuro&lt;/a&gt; fills that gap. I will report on it as soon as I get a chance to play with it.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Trac&lt;/span&gt;&lt;br /&gt;Trac was the biggest disappointment of the bunch. One area where Ruby leaves Python in the dust is in package management. I had to install so many different packages and take so many manual steps just to get something that sort of worked. Compared to &lt;a href="http://www.rubygems.org/"&gt;RubyGems&lt;/a&gt; projects, this is an absolute joke. I couldn't get either of the plugins I installed to work.&lt;br /&gt;&lt;br /&gt;The good news is there will soon be an excellent issue tracker/wiki available. &lt;a href="http://www.atlassian.com/software/confluence/"&gt;Confluence&lt;/a&gt;, the wiki we use at work, already has a personal edition available. With the 4.0 release of JIRA (date not announced yet) there will be a &lt;a href="http://jira.atlassian.com/browse/JRA-10393?focusedCommentId=117768#action_117768"&gt;personal edition of JIRA&lt;/a&gt; as well. Both are from &lt;a href="http://www.atlassian.com/"&gt;Atlassian&lt;/a&gt;, who are fantastic to work with. Goodbye Trac, it was fun knowing you, but I want to spend more time developing my app and less time screwing around with plugins.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5963350864821674235-4942864156932922072?l=effectiveqa.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/4942864156932922072/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5963350864821674235&amp;postID=4942864156932922072&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/4942864156932922072'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/4942864156932922072'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/2008/06/walking-talk-few-days-later.html' title='Walking the Talk, a few days later'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_07MQFGLRKcI/SFHLpvgyD1I/AAAAAAAAAR8/5CEOrRyTSmU/s72-c/rcovExample.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5963350864821674235.post-2810087815504415100</id><published>2008-06-07T08:33:00.004-06:00</published><updated>2008-06-08T06:06:00.359-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Subversion'/><category scheme='http://www.blogger.com/atom/ns#' term='Hudson'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Trac'/><category scheme='http://www.blogger.com/atom/ns#' term='continuous integration'/><category scheme='http://www.blogger.com/atom/ns#' term='Postgres'/><title type='text'>Walking the Talk</title><content type='html'>At work, I am the champion of many technologies which further software quality, including:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Continuous integration (&lt;a href="https://hudson.dev.java.net/"&gt;Hudson&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;Version control (&lt;a href="http://subversion.tigris.org/"&gt;Subversion&lt;/a&gt;)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.agiledata.org/essays/tdd.html"&gt;Test Driven Development&lt;/a&gt;&lt;/li&gt;&lt;li&gt;Unit testing (&lt;a href="http://www.junit.org/"&gt;JUnit&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;Defect tracking (&lt;a href="http://www.atlassian.com/software/jira/"&gt;JIRA&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;Light documentation via a wiki (&lt;a href="http://www.atlassian.com/software/confluence/"&gt;Confluence&lt;/a&gt;)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Coverage analysis (&lt;a href="http://cobertura.sourceforge.net/"&gt;Cobertura&lt;/a&gt;)&lt;/li&gt;&lt;li&gt;Profiling (&lt;a href="http://www.yourkit.com/"&gt;YourKit&lt;/a&gt;)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Automated builds/testing (&lt;a href="http://ant.apache.org/"&gt;Ant&lt;/a&gt;)&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;Recently I started playing around writing a newsgroup reader in &lt;a href="http://www.ruby-lang.org/en/"&gt;Ruby&lt;/a&gt;. So I immediately started using all these tools, right? Wrong. I just started hacking away. I was able to establish a proof of concept pretty quickly and learn about some of the gotchas. But after being at this a while, I started feeling lost. I'd forget how something worked and have to rediscover something I'd figured out previously. I'd have ideas for things that I wanted to do, but no place to write them down and think about priorities. Perhaps it was time for me to start walking my talk.&lt;br /&gt;&lt;br /&gt;At home I have several constraints I don't have at work. I am writing in Ruby, not Java. I am not willing to pay the money for commercial tools (JIRA, Confluence, YourKit). I think Ant is a silly way to do builds and automated tests. So I started thinking about what my own tool set might look like.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Continuous integration&lt;/span&gt;: &lt;span style="font-weight: bold;"&gt;Hudson&lt;/span&gt;. I have written about this before, but it is a fantastic continuous integration tool. Kohsuke Kawaguchi is constantly improving it, so it is just getting better and better.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Version control&lt;/span&gt;: &lt;span style="font-weight: bold;"&gt;Subversion&lt;/span&gt;. I see no reason to switch here either. Version control with only one developer is dead-simple anyway, but why bother learning something new when Subversion works so well?&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Unit testing&lt;/span&gt;:  &lt;a style="font-weight: bold;" href="http://www.ruby-doc.org/stdlib/libdoc/test/unit/rdoc/classes/Test/Unit.html"&gt;Test::Unit&lt;/a&gt;. It ships with Ruby and is the spiritual equivalent to JUnit.  &lt;a href="http://rubyforge.org/projects/zentest/"&gt;ZenTest&lt;/a&gt; also looks very interesting - promising to go far beyond the simple XUnit frameworks. I'll take a look at this as well.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Defect tracking&lt;/span&gt;: &lt;a style="font-weight: bold;" href="http://trac.edgewall.org/"&gt;Trac&lt;/a&gt;. There are endless open source defect trackers out there. Maybe some are better than Trac. But I like that it is light weight, has an integrated wiki and has &lt;a href="http://trac-hacks.org/"&gt;bazillions of plugins&lt;/a&gt;, including Hudson integration. It is also written in Python, my previous favorite language before Ruby.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Wiki&lt;/span&gt;: &lt;span style="font-weight: bold;"&gt;Trac&lt;/span&gt;. See Defect Tracking above.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Coverage Analysis&lt;/span&gt;: &lt;a style="font-weight: bold;" href="http://eigenclass.org/hiki.rb?rcov"&gt;rcov&lt;/a&gt;. To the best of my knowledge, this is the only game in town. The outputs look very similar to Cobertura. I haven't played with this yet, but it is on my short list.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Profiling&lt;/span&gt;: &lt;a style="font-weight: bold;" href="http://ruby-prof.rubyforge.org/"&gt;ruby-prof&lt;/a&gt;. This seems to be the clear winner over Profile. I could not find a single reference comparing the two that didn't favor ruby-prof.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-style: italic;"&gt;Automated builds/testing&lt;/span&gt;: &lt;a style="font-weight: bold;" href="http://en.wikipedia.org/wiki/Rake_%28software%29"&gt;Rake&lt;/a&gt;. There are quite a few &lt;a href="http://www.infoq.com/news/2007/05/fast-ruby-builds-with-buildr"&gt;Ruby-based build tools&lt;/a&gt; available. Since I am planning to use &lt;a href="http://www.rubyonrails.org/"&gt;Rails&lt;/a&gt; in my implentation, Rake seems like the obvious choice.&lt;br /&gt;&lt;br /&gt;That is the plan. I'll see how it all works out and report back on my progress. Even if it is a big failure, I will have taken a sip (gulp?) of my own medicine.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5963350864821674235-2810087815504415100?l=effectiveqa.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/2810087815504415100/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5963350864821674235&amp;postID=2810087815504415100&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/2810087815504415100'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/2810087815504415100'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/2008/06/walking-talk.html' title='Walking the Talk'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5963350864821674235.post-4122069977247713526</id><published>2008-03-08T07:05:00.003-07:00</published><updated>2009-12-06T12:24:01.249-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quality'/><category scheme='http://www.blogger.com/atom/ns#' term='Hudson'/><category scheme='http://www.blogger.com/atom/ns#' term='continuous integration'/><title type='text'>Google calendar plugin for Hudson</title><content type='html'>For some time now I have been a major fan of &lt;a href="https://hudson.dev.java.net/"&gt;Hudson&lt;/a&gt;, an open source continuous integration server. I recently gave a presentation to my group on using Hudson not only to run our continuous integration effort, but also to routinely check for anomalies in our database and environment.&lt;br /&gt;&lt;br /&gt;One question that my boss posed was how we could monitor results from home, since the server Hudson runs on is not exposed to the outside world. At first I did not have a good answer, but  a quick trip to the &lt;a href="http://hudson.gotdns.com/wiki/display/HUDSON/Plugins"&gt;Hudson plugin wiki&lt;/a&gt;. First of all, I was shocked to find there were nearly 50 plugins available. Hudson is clearly catching on. The one that seemed like the best solution for our team is the &lt;a href="http://hudson.gotdns.com/wiki/display/HUDSON/Google+Calendar+Plugin"&gt;plugin&lt;/a&gt; to publish results to &lt;a href="http://calendar.google.com/"&gt;Google Calendar&lt;/a&gt;. With some simple setup in Hudson, build results are published to a shared Google Calendar. None of the build artifacts are published, so there is no risk of loosing important resources. At the same time, we can stay current with the health of our system from home.&lt;br /&gt;&lt;br /&gt;We could also use email for this, but this seems like a more elegant solution. If you are looking for a way to access your Hudson results from outside your firewall, this just might be your ticket!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5963350864821674235-4122069977247713526?l=effectiveqa.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/4122069977247713526/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5963350864821674235&amp;postID=4122069977247713526&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/4122069977247713526'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/4122069977247713526'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/2008/03/google-calendar-plugin-for-hudson.html' title='Google calendar plugin for Hudson'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5963350864821674235.post-5700743395155303304</id><published>2008-01-19T07:33:00.000-07:00</published><updated>2008-01-24T13:19:09.847-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JRuby'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>Using JRuby when package names include capitals</title><content type='html'>I discovered solutions to a few problems I was having using JRuby with our Ruby libraries at work. The first relates to our domain name and "magic" names in JRuby. For example, you can write something like:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;org.junit.Assert.assertEquals("Silly example", 4, 4)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;This code will run just fine. But now consider my company - &lt;a href="http://samba.biz/"&gt;samba.biz&lt;/a&gt;. From the example above, I expected to be able to write:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;biz.samba.Assert.assert_equals("Silly example", 4, 4)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;But this gives me "NameError: undefined local variable or method 'biz' for main:Object". It turns out that 'com' and 'org' (and perhaps others?) are "magic" names that support this syntax, but 'biz' is not. After some fooling around, I was able to get the above example to work like this:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;include_class 'biz.samba.Assert'&lt;br /&gt;Assert.assert_equals("Silly example", 4, 4)&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;This also solved another problem I was having at work. For some reason, we have some package names that include capital letters (why?). For example&lt;br /&gt;&lt;code&gt;&lt;br /&gt;biz.samba.backend.states.CA.utils.ProcessEpnsByList&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;JRuby wanted to think that CA was a class name, since it starts with a capital letter. Again, the syntax above solves this issue.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://blogs.sun.com/coolstuff/entry/using_java_classes_in_jruby"&gt;http://blogs.sun.com/coolstuff/entry/using_java_classes_in_jruby&lt;/a&gt; &lt;br /&gt;was a big help in helping figure this out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5963350864821674235-5700743395155303304?l=effectiveqa.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/5700743395155303304/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5963350864821674235&amp;postID=5700743395155303304&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/5700743395155303304'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/5700743395155303304'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/2008/01/using-jruby-when-package-names-include.html' title='Using JRuby when package names include capitals'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5963350864821674235.post-8151288016233158826</id><published>2007-12-15T12:53:00.000-07:00</published><updated>2007-12-23T18:09:36.164-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Joomla'/><category scheme='http://www.blogger.com/atom/ns#' term='CMS'/><title type='text'>Correcting blank image and link dialogs in Joomla</title><content type='html'>I was going nuts! When I worked on my friend's &lt;a href="http://www.joomla.org/"&gt;Joomla&lt;/a&gt; site from home, the Image and Link dialogs appear just fine:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_07MQFGLRKcI/R2QyplX1RjI/AAAAAAAAABk/Qa1yiugPzls/s1600-h/works.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_07MQFGLRKcI/R2QyplX1RjI/AAAAAAAAABk/Qa1yiugPzls/s400/works.png" alt="" id="BLOGGER_PHOTO_ID_5144292364352046642" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;But when I tried it from work or when my friend did it from her house, the dialogs came up blank:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_07MQFGLRKcI/R2Q0B1X1RkI/AAAAAAAAABs/5951CksilIQ/s1600-h/broken.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://3.bp.blogspot.com/_07MQFGLRKcI/R2Q0B1X1RkI/AAAAAAAAABs/5951CksilIQ/s400/broken.png" alt="" id="BLOGGER_PHOTO_ID_5144293880475502146" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;I tried every combination of browser setting and browser (Firefox, Opera, IE). Nothing. What was so magical about my machine at home?&lt;br /&gt;&lt;br /&gt;I found the answer on &lt;a href="http://alexle.net/archives/193"&gt;Alex Le's blog&lt;/a&gt;. It turns out that my site home (as defined by $mosConfig_live_site) was set to &lt;span style="font-weight: bold;"&gt;www&lt;/span&gt;.site_name.com while I was firing up the administration console with http://site_name.com/administrator (notice the lack of www). Once I launched from http://&lt;span style="font-weight: bold;"&gt;www&lt;/span&gt;.site_name.com/administrator, the edit dialogs are dandy again, just like they are from home. Thanks, Alex!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5963350864821674235-8151288016233158826?l=effectiveqa.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/8151288016233158826/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5963350864821674235&amp;postID=8151288016233158826&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/8151288016233158826'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/8151288016233158826'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/2007/12/correcting-blank-image-and-link-dialogs.html' title='Correcting blank image and link dialogs in Joomla'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_07MQFGLRKcI/R2QyplX1RjI/AAAAAAAAABk/Qa1yiugPzls/s72-c/works.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5963350864821674235.post-3904153789809832684</id><published>2007-12-15T12:27:00.000-07:00</published><updated>2008-03-08T07:30:40.714-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JRuby'/><title type='text'>Getting JRuby gem utility to work</title><content type='html'>I've been cursing my brains out trying to get the &lt;a href="http://jruby.codehaus.org/"&gt;JRuby&lt;/a&gt; version of &lt;a href="http://rubygems.org/"&gt;gem&lt;/a&gt; to work. After much hunting around, I found that a Java memory size issue was causing the problem. Things have been working fine since I started installing gems with:&lt;br /&gt;&lt;br /&gt;jruby &lt;span style="font-weight: bold;"&gt;-J-Xmx512M&lt;/span&gt; -S gem install &lt;gemname&gt;&lt;br /&gt;&lt;br /&gt;My apologies for having lost the original reference to this information. This &lt;a href="http://jira.codehaus.org/browse/JRUBY-1085"&gt;bug entry&lt;/a&gt; might have been where I first found the solution.&lt;/gemname&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5963350864821674235-3904153789809832684?l=effectiveqa.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/3904153789809832684/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5963350864821674235&amp;postID=3904153789809832684&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/3904153789809832684'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/3904153789809832684'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/2007/12/getting-jruby-gem-utility-to-work.html' title='Getting JRuby gem utility to work'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5963350864821674235.post-8306351105365608709</id><published>2007-12-15T11:17:00.000-07:00</published><updated>2007-12-23T18:11:25.333-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='JRuby'/><category scheme='http://www.blogger.com/atom/ns#' term='FTP'/><category scheme='http://www.blogger.com/atom/ns#' term='system programming'/><category scheme='http://www.blogger.com/atom/ns#' term='IT'/><category scheme='http://www.blogger.com/atom/ns#' term='Postgres'/><title type='text'>JRuby as a system programming language</title><content type='html'>At work, we are starting to refactor some of our system utilities. The scripts interact with these basic components:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Postgres databases&lt;/li&gt;&lt;li&gt;FTP servers&lt;/li&gt;&lt;li&gt;Files on various servers&lt;/li&gt;&lt;li&gt;Java applications&lt;/li&gt;&lt;li&gt;Specific system calls&lt;/li&gt;&lt;/ul&gt;My boss, being from an "older generation" ;-), favors Unix scripting (sed, bash, etc.) . Being a Ruby/JRuby enthusiast myself, I wanted to show my team how easy these tasks are in JRuby. While sed might take fewer characters in some cases, I think JRuby strikes an ideal match between terseness and readability.&lt;br /&gt;&lt;br /&gt;Note that the following code will not run on your computer, at least not without setting up a Postgres database and changing the FTP server info, etc. But it will give you a good flavor for system programming in JRuby.&lt;br /&gt;&lt;span style="line-height: 0.5;font-size:75;" &gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#&lt;br /&gt;&lt;br /&gt;# Copyright 2007 Effectiveqa.com. All rights reserved&lt;br /&gt;&lt;br /&gt;#&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def postgres&lt;br /&gt;&lt;br /&gt;# Accessing Postgres from JRuby&lt;br /&gt;&lt;br /&gt;# http://ruby.scripting.ca/postgres/rdoc/&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  $LOAD_PATH &lt;&lt; 'C:/jruby-1.0.1/lib/ruby/gems/1.8/gems/postgres-pr-0.4.0/lib'&lt;br /&gt;   &lt;br /&gt;  require 'postgres'&lt;br /&gt;&lt;br /&gt;  con = PGconn.connect('localhost', 5432, nil, nil, 'foo', 'postgres', 'password'&lt;br /&gt;&lt;br /&gt;  res = con.query("select * from bar")&lt;br /&gt;&lt;br /&gt;  puts res[0][0]&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def ftp&lt;br /&gt;&lt;br /&gt;  # FTP Access&lt;br /&gt;&lt;br /&gt;  # http://ruby-doc.org/stdlib/libdoc/net/ftp/rdoc/index.html&lt;br /&gt;&lt;br /&gt;  require 'net/ftp'&lt;br /&gt;&lt;br /&gt;  Net::FTP.open('effectiveqa.com') do |ftp|&lt;br /&gt;&lt;br /&gt;     ftp.login('username', 'password')&lt;br /&gt;&lt;br /&gt;     ftp.chdir('public_html')&lt;br /&gt;&lt;br /&gt;     ftp.list('*.css').each {|file| puts file}&lt;br /&gt;&lt;br /&gt;     ftp.gettextfile('main.css', 'local_main.css')&lt;br /&gt;&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def ftp_password&lt;br /&gt;&lt;br /&gt;  # Show how easily JRuby can handle password problem&lt;br /&gt;&lt;br /&gt;  require 'net/ftp'&lt;br /&gt;&lt;br /&gt;  begin&lt;br /&gt;&lt;br /&gt;     ftp = Net::FTP.open('effectiveqa.com')&lt;br /&gt;&lt;br /&gt;     ftp.login('effectiv', 'BADPASSWORD')&lt;br /&gt;&lt;br /&gt;  rescue&lt;br /&gt;&lt;br /&gt;     puts "Here is where I fix the password"&lt;br /&gt;&lt;br /&gt;     ftp.login('username', 'password')&lt;br /&gt;&lt;br /&gt;     ftp.chdir('public_html')&lt;br /&gt;&lt;br /&gt;     ftp.list('*.css').each {|file| puts file}&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def file_tricks&lt;br /&gt;&lt;br /&gt;  # Different file/directory manipulations&lt;br /&gt;&lt;br /&gt;  # http://www.ruby-doc.org/stdlib/libdoc/fileutils/rdoc/index.html&lt;br /&gt;&lt;br /&gt;  require 'fileutils'&lt;br /&gt;&lt;br /&gt;  include FileUtils&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  begin cd('dfsdf') rescue puts 'Oops, had a problem...' end&lt;br /&gt;&lt;br /&gt;  chmod(0777, 'local_main.css')&lt;br /&gt;&lt;br /&gt;  puts "Don't match!" if ! cmp('local_main.css', 'local_main_1.css')&lt;br /&gt;&lt;br /&gt;  cp('local_main.css', 'local_main_copy.css')&lt;br /&gt;&lt;br /&gt;  puts "Do match!" if cmp('local_main.css', 'local_main_copy.css')&lt;br /&gt;&lt;br /&gt;  puts pwd&lt;br /&gt;&lt;br /&gt;  rm('local_main_copy.css')&lt;br /&gt;&lt;br /&gt;  begin rm('DOESNT_EXIST') rescue puts 'Caught one' end&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def file_tests&lt;br /&gt;&lt;br /&gt;  # Very nice tests&lt;br /&gt;&lt;br /&gt;  # http://ruby-doc.org/docs/ProgrammingRuby/html/ref_m_filetest.html&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  puts FileTest.directory?('example.zip') # false&lt;br /&gt;&lt;br /&gt;  puts FileTest.size('example.zip') # 1723&lt;br /&gt;&lt;br /&gt;  puts FileTest.file?('.') # false&lt;br /&gt;&lt;br /&gt;  puts FileTest.file?('example.zip') # true&lt;br /&gt;&lt;br /&gt;  puts FileTest.readable?('example.zip') # true&lt;br /&gt;&lt;br /&gt;  puts FileTest.writable?('example.zip') # true&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  include FileTest&lt;br /&gt;&lt;br /&gt;  puts directory?('.') # true; needs include&lt;br /&gt;&lt;br /&gt;  puts file?('.') # false&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;def use_java&lt;br /&gt;&lt;br /&gt;  # Show off how easy it is to use Java from JRuby&lt;br /&gt;&lt;br /&gt;  include Java&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  zf = java.util.zip.ZipFile.new('example.zip')&lt;br /&gt;&lt;br /&gt;  puts "There are #{zf.size} files in the zip."&lt;br /&gt;&lt;br /&gt;  zf.entries.each {|entry| puts "  file: #{entry}"}&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def split_files&lt;br /&gt;&lt;br /&gt;  # Easy processing of DB dump files&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;  lines = IO.readlines('pipeFile.txt')&lt;br /&gt;&lt;br /&gt;  lines.each {|line| puts line.split('|')[1]}&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;def system_calls&lt;br /&gt;&lt;br /&gt;  # JRuby has full access to OS calls&lt;br /&gt;&lt;br /&gt;  lines = `df`.split("\n")&lt;br /&gt;&lt;br /&gt;  lines.shift   # Read off header line&lt;br /&gt;&lt;br /&gt;  lines.each do |line|&lt;br /&gt;&lt;br /&gt;    fields = line.split&lt;br /&gt;&lt;br /&gt;    next unless fields[0] =~ /C:$/   # Only care about the C: drive&lt;br /&gt;&lt;br /&gt;    percent = fields[4].to_i&lt;br /&gt;&lt;br /&gt;    puts "Holy cow, disk almost full" if percent &gt; 95&lt;br /&gt;&lt;br /&gt;    puts "Disk &gt; 50% full" if percent &gt; 50&lt;br /&gt;&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;# Some interesting Ruby libraries&lt;br /&gt;&lt;br /&gt;# http://beaver.net/slides/ruby/10-easy-pieces.html&lt;br /&gt;&lt;br /&gt;# Library doc: http://www.ruby-doc.org/stdlib/&lt;br /&gt;&lt;br /&gt;# Pathnames: http://www.ruby-doc.org/stdlib/libdoc/pathname/rdoc/index.html&lt;br /&gt;&lt;br /&gt;# MD5, sha1: http://www.ruby-doc.org/stdlib/libdoc/digest/rdoc/index.html&lt;br /&gt;&lt;br /&gt;# Waking trees: http://ruby-doc.org/stdlib/libdoc/find/rdoc/index.html&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;puts "\n**** I can access postgres\n"&lt;br /&gt;&lt;br /&gt;postgres&lt;br /&gt;&lt;br /&gt;puts "\n**** I can access FTP\n"&lt;br /&gt;&lt;br /&gt;ftp&lt;br /&gt;&lt;br /&gt;puts "\n**** I can tell if an FTP password failed\n"&lt;br /&gt;&lt;br /&gt;ftp_password&lt;br /&gt;&lt;br /&gt;puts "\n**** I have all kinds of *nix file commands\n"&lt;br /&gt;&lt;br /&gt;file_tricks&lt;br /&gt;&lt;br /&gt;puts "\n**** I also have all kinds of cool file tests\n"&lt;br /&gt;&lt;br /&gt;file_tests&lt;br /&gt;&lt;br /&gt;puts "\n**** I can easily use Java code\n"&lt;br /&gt;&lt;br /&gt;use_java&lt;br /&gt;&lt;br /&gt;puts "\n**** I can split up Dave's db dump files\n"&lt;br /&gt;&lt;br /&gt;split_files&lt;br /&gt;&lt;br /&gt;puts "\n**** I can make OS calls with ease\n"&lt;br /&gt;&lt;br /&gt;system_calls&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;The only shortcoming I could find with JRuby is that it doesn't support all the command line options that Ruby does. So you can see that JRuby falls behind in the terseness of its one-liner to rip a particular field out of a pipe-delimited dump file, though I would argue it is more readable.&lt;br /&gt;&lt;span style="line-height: 0.5;font-size:75;" &gt;&lt;br /&gt;&lt;pre&gt;#&gt; ruby -n -a -F"\|" -e "puts $F[1]" pipeFile.txt&lt;br /&gt;&lt;br /&gt;#&gt; perl -n -a -F"\|" -e 'print "$F[1]\n"' pipeFile.txt&lt;br /&gt;&lt;br /&gt;#&gt; jruby -e "IO.readlines('pipeFile.txt').each {|ln| puts ln.split('|')[1]}"&lt;br /&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5963350864821674235-8306351105365608709?l=effectiveqa.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/8306351105365608709/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5963350864821674235&amp;postID=8306351105365608709&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/8306351105365608709'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/8306351105365608709'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/2007/12/jruby-as-system-programming-language.html' title='JRuby as a system programming language'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5963350864821674235.post-3205575919869323001</id><published>2007-12-05T09:28:00.001-07:00</published><updated>2009-12-11T18:58:35.901-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Subversion'/><category scheme='http://www.blogger.com/atom/ns#' term='svn+ssh'/><category scheme='http://www.blogger.com/atom/ns#' term='SSH key authentication'/><title type='text'>Using Subversion svn+ssh protocol without typing passwords</title><content type='html'>I have been having more and more problems using the svn: protocol for &lt;a href="http://subversion.tigris.org/"&gt;Subversion&lt;/a&gt;. So I've moved to using the svn+ssh: protocol. The only frustration was having to constantly enter my password (sometimes many times) for each svn command. It turns out that svn+ssh: is using standard SSH protocols, so SSH key authentication solves the problem.&lt;br /&gt;&lt;br /&gt;I found a nice write-up on &lt;a href="http://www.pthree.org/2007/02/10/ssh-key-authentication/"&gt;Aaron Toponce's blog&lt;/a&gt; on how to set it up.&lt;br /&gt;&lt;br /&gt;It is a little more complicated for Windows. I will address that in a future installment.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5963350864821674235-3205575919869323001?l=effectiveqa.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/3205575919869323001/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5963350864821674235&amp;postID=3205575919869323001&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/3205575919869323001'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/3205575919869323001'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/2007/12/using-subversion-svnssh-protocol.html' title='Using Subversion svn+ssh protocol without typing passwords'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5963350864821674235.post-3884665777826003359</id><published>2007-11-28T20:26:00.001-07:00</published><updated>2009-12-11T19:00:49.652-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='user groups'/><category scheme='http://www.blogger.com/atom/ns#' term='IT'/><title type='text'>New Mexico Information Technology Infrastructure &amp; Architecture group forming</title><content type='html'>Today, I attended the first meeting of "New Mexico Information Technology Infrastructure &amp;amp; Architecture," the brainchild of  Thierry Thelliez, oft contributor and board member of the &lt;a href="http://www.abqspin.org/AgileNM"&gt;AgileNM group&lt;/a&gt; that I run. Thierry envisions the group positioned somewhere between the AgileNM/SPIN groups and the technology-focused groups (like the New Mexico &lt;a href="http://www.rubyabq.org/"&gt;Ruby&lt;/a&gt; and &lt;a href="http://www.abqjug.org/"&gt;Java&lt;/a&gt; users groups) in terms of where it fits on the technology vs. business continuum. Some of the topics discussed that caught my eye:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Server virtualization&lt;/li&gt;&lt;li&gt;Web frameworks&lt;/li&gt;&lt;li&gt;Open source&lt;/li&gt;&lt;li&gt;Scripting languages (e.g. Ruby, Python)&lt;/li&gt;&lt;li&gt;Wikis&lt;/li&gt;&lt;li&gt;Distributed architectures&lt;/li&gt;&lt;/ul&gt;The next meeting is scheduled for January, 2008. Visit the &lt;a href="http://tech.groups.yahoo.com/group/nmitia/"&gt;NMITIA&lt;/a&gt; site for more details and to add your input for topics you'd like to see. Like the AgileNM group, Thierry's vision is that group members will largely drive the agenda. So help drive the group in a direction that will meet your professional needs.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5963350864821674235-3884665777826003359?l=effectiveqa.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/3884665777826003359/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5963350864821674235&amp;postID=3884665777826003359&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/3884665777826003359'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/3884665777826003359'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/2007/11/new-mexico-information-technology.html' title='New Mexico Information Technology Infrastructure &amp; Architecture group forming'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5963350864821674235.post-617599247438568363</id><published>2007-11-24T07:33:00.000-07:00</published><updated>2008-03-08T07:29:12.282-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Flex'/><title type='text'>Flex Functional Testing with Ruby</title><content type='html'>I have been playing with Flex the last few days, creating an application to &lt;a href="http://en.wikipedia.org/wiki/Screen_scraping"&gt;screen scrape&lt;/a&gt; audio equipment sales sites on a periodic basis and send me email when a component I am looking for is posted. Currently, I am a little hung up trying to use &lt;a href="http://www.themidnightcoders.com/weborb/rubyonrails/index.htm"&gt;WebORB interface&lt;/a&gt; between Flex 3 Beta 2 and &lt;a href="http://www.rubyonrails.org/"&gt;Ruby on Rails&lt;/a&gt;. The examples appear to all be written for Flex 2. So far, I have found some references that make it sound doable, but I am not quite there yet.&lt;br /&gt;&lt;br /&gt;In the meantime, I ran across &lt;a href="http://funfx.rubyforge.org/"&gt;FunFX&lt;/a&gt;, a Ruby library for functional testing of Flex applications. This is very exciting to me since, until now, I was only aware of Mercury (oops, HP) &lt;a href="https://h10078.www1.hp.com/cda/hpms/display/main/hpms_content.jsp?zn=bto&amp;amp;cp=1-11-127-24%5E1352_4000_100__"&gt;QuickTest Pro&lt;/a&gt; as a testing option for Flex. To be able to test Flex apps with code very similar to the &lt;a href="http://wtr.rubyforge.org/"&gt;Watir &lt;/a&gt;tests I write now is very exciting. I have not fired it up yet, but as soon as I have some experience with it, I'll report back.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5963350864821674235-617599247438568363?l=effectiveqa.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/617599247438568363/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5963350864821674235&amp;postID=617599247438568363&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/617599247438568363'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/617599247438568363'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/2007/11/flex-functional-testing-with-ruby.html' title='Flex Functional Testing with Ruby'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5963350864821674235.post-1182919609250818425</id><published>2007-11-20T20:09:00.003-07:00</published><updated>2009-11-24T06:20:06.148-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='browsers'/><title type='text'>Firefox 3 Beta Available!</title><content type='html'>I just read in the &lt;a href="http://www.nytimes.com/idg/IDG_002570DE00740E18002573990073C1C2.html?ref=technology"&gt;New York Times&lt;/a&gt; technology section that the &lt;a href="http://ftp.mozilla.org/pub/mozilla.org/firefox/nightly/latest-trunk/firefox-3.0b2pre.en-US.win32.installer.exe"&gt;Beta for Firefox 3&lt;/a&gt; (Minefield) is now available. Being too curious, I had to give it a try.&lt;br /&gt;&lt;br /&gt;It doesn't work with most of my plugins yet (although I did manage to load &lt;a href="http://adblockplus.org/en/"&gt;Adblock Plus&lt;/a&gt;!). The first big problem I found was editing this post. The Javascript editor for Blogger did not respond particularly well, so I am finishing this up with Firefox 2. And, so far, I have not noticed any killer features I can't live without.&lt;br /&gt;&lt;br /&gt;Even so, I still plan to use Firefox 3 for most of my casual browsing. The reason I plan to stay with it is speed. Except for &lt;a href="http://www.opera.com/"&gt;Opera&lt;/a&gt;, this is the fastest browser I have seen. Mozilla also claims that it has fixed 300 memory leaks.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5963350864821674235-1182919609250818425?l=effectiveqa.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/1182919609250818425/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5963350864821674235&amp;postID=1182919609250818425&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/1182919609250818425'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/1182919609250818425'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/2007/11/firefox-3-beta-available.html' title='Firefox 3 Beta Available!'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5963350864821674235.post-5414598690318174898</id><published>2007-11-10T11:18:00.000-07:00</published><updated>2008-03-08T07:30:20.469-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Joomla'/><title type='text'>Killer CMS - Joomla</title><content type='html'>I hadn't had much need for a Content Management System (CMS) until, recently, I offered to help a friend get her site up and running. She has written professionally for the Web for years, but the actual web design is handled by the organizations she works for. I was going to whip something up for her myself but with &lt;a href="http://www.cmsmatrix.org/"&gt;zillions of CMS systems available&lt;/a&gt;, I didn't see any reason to start from scratch.&lt;br /&gt;&lt;br /&gt;She doesn't have a hosting service yet, so I started looking around at some of them. Many hosting services include CMS support. It seemed like it would be easier to start with one that was pre-installed, so I first looked for services with pre-installed CMS. Several providers supported &lt;a href="http://www.joomla.org/"&gt;Joomla!&lt;/a&gt;, so I decided to give that a try.&lt;br /&gt;&lt;br /&gt;Joomla!'s demo site was down, so I went ahead and installed it on my local machine. It was literally installed in five minutes. My home box is a Windows machine and I already had the Apache/MySql/PHP stack installed using &lt;a href="http://www.apachefriends.org/en/xampp.html"&gt;XAMPP&lt;/a&gt;. If you haven't tried XAMPP, it is just about the easiest way to get the stack up and running on Windows. All I did was drop the .zip files contents into my xampp\htdocs directory, point my browser at http://localhost/joomla/install, answer a few questions and I was done. So many things like this I get frustrated just getting things set up that I give up before I ever start. Not so with Joomla!.&lt;br /&gt;&lt;br /&gt;After the install process completes, you have to remove the install folder in order to continue. This is a security feature. Once it is removed, pointing my browser to http://localhost/joomla produced a page that looked like:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_07MQFGLRKcI/RzX8gNabcGI/AAAAAAAAAA8/QxDJ1Gru5XM/s1600-h/joomla.png"&gt;&lt;img style="cursor: pointer;" src="http://3.bp.blogspot.com/_07MQFGLRKcI/RzX8gNabcGI/AAAAAAAAAA8/QxDJ1Gru5XM/s400/joomla.png" alt="" id="BLOGGER_PHOTO_ID_5131284980745072738" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;So far, I have found Joomla! to be intuitive and easy to learn. But what really makes it exciting to me is the depth of the community behind it. For example, Googling on "Joomla templates" returns 7.9 MILLION hits. The first &lt;a href="http://www.joomla24.com/"&gt;template site&lt;/a&gt; I went to has 1,500 free templates available! Hundreds of plugins are also available. I guess I am the only one in the world who didn't know about Joomla! until now.&lt;br /&gt;&lt;br /&gt;My comments are based on the 1.5 RC3 (codename &lt;a href="http://www.joomla.org/content/view/3994/1/"&gt;Takriban&lt;/a&gt;) release. The current production version is 1.0.13, which I have not tried.&lt;br /&gt;&lt;br /&gt;One thing that frosts me is that it is written in PHP. I consider this a hack language, not worthy of real software efforts. Yet people are getting cool things done with it. Too bad it isn't written in &lt;a href="http://www.rubyonrails.org/"&gt;Rails&lt;/a&gt; or &lt;a href="http://www.djangoproject.com/"&gt;Django&lt;/a&gt;. ;-)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5963350864821674235-5414598690318174898?l=effectiveqa.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/5414598690318174898/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5963350864821674235&amp;postID=5414598690318174898&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/5414598690318174898'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/5414598690318174898'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/2007/11/killer-cms-joomla.html' title='Killer CMS - Joomla'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_07MQFGLRKcI/RzX8gNabcGI/AAAAAAAAAA8/QxDJ1Gru5XM/s72-c/joomla.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5963350864821674235.post-8637828149677312016</id><published>2007-10-30T12:03:00.003-06:00</published><updated>2009-12-06T13:59:51.964-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='quality'/><category scheme='http://www.blogger.com/atom/ns#' term='Hudson'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><category scheme='http://www.blogger.com/atom/ns#' term='Watir'/><category scheme='http://www.blogger.com/atom/ns#' term='performance testing'/><category scheme='http://www.blogger.com/atom/ns#' term='continuous integration'/><title type='text'>Using Watir and Hudson to Monitor Performance</title><content type='html'>Currently, I have a full suite of &lt;a href="http://wtr.rubyforge.org/"&gt;Watir&lt;/a&gt; regression tests that I use routinely during the development of our web app. For those who may not be familiar with it, Watir is a &lt;a href="http://www.ruby-lang.org/en/"&gt;Ruby&lt;/a&gt; library which allows programmatic control of Internet Explorer to navigate through an application under test (AUT) and determine if the application is performing properly. I'll have more to say about Watir another time.&lt;br /&gt;&lt;br /&gt;One of the challenges with our application is performance. I wanted to have a way of determining which changes to the app, network, hardware, etc. were having a positive or negative impact on performance. By wrapping some timing functions around the most timing-sensitive issues in the regression library, I created a performance benchmark.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;font-family:arial;" &gt;The Timing Wrapper&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The simplest timing wrapper could be as simple as this:&lt;br /&gt;&lt;pre style="font-family: courier new; font-size: 100%; font-weight: bold; color: rgb(164, 0, 0);"&gt;&lt;br /&gt;start = Time.now&lt;br /&gt;# Do your operations here&lt;br /&gt;elapsed = Time.now - start&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I started this way then decided I wanted a little more capability, so I came up with a hierarchical timer, to easily time activities within larger activities. A likeness of the library I use is &lt;a href="http://www.effectiveqa.com/blog/timer.rb"&gt;available here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;font-family:arial;" &gt;Watir&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Watir is a very nice, open-source Ruby library that allows driving an IE session from a Ruby program and then scraping the pages to determine if a proper result was generated. I started with &lt;a href="http://www.openqa.org/selenium/"&gt;Selenium&lt;/a&gt;, but ran into problems with https and a few other things that Watir was able to handle. The one area where Selenium really beat Watir was in the quality of the recorder. But pretty quickly you learn to write the scripts by hand, with a little help from the &lt;a href="http://www.microsoft.com/downloads/details.aspx?familyid=e59c3964-672d-4511-bb3e-2d5e1db91038&amp;amp;displaylang=en"&gt;IE Developer Toolbar&lt;/a&gt;. Watir does have a &lt;a href="http://www.openqa.org/watir-recorder/"&gt;recorder&lt;/a&gt;, but I did not find it very useful.&lt;br /&gt;&lt;br /&gt;A simple test might look something like this:&lt;br /&gt;&lt;pre style="font-family: courier new; font-size: 100%; font-weight: bold; color: rgb(164, 0, 0);"&gt;&lt;br /&gt;def list_page_to_page&lt;br /&gt; # Try some list features&lt;br /&gt; [['User 1', 'List 1', 'Company 1 page 1 -&gt; page 2'],&lt;br /&gt;  ['User 2', 'List 2', 'Company 2 page 1 -&gt; page 2'],&lt;br /&gt;  ['User 3', 'List 3', 'Company 3 page 1 -&gt; page 2'],&lt;br /&gt; ].each do |user_name, list, label|&lt;br /&gt;    login(user_name, $password, @test_site)&lt;br /&gt;    @ie.link(:text, list).click&lt;br /&gt;&lt;br /&gt;    # Now try paging...&lt;br /&gt;    time(label) { @ie.link(:url, /page=2/).click }&lt;br /&gt;    logout&lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This example logs in as three different users, clicks on a link with particular text in it and then times how long it takes for the page to return when clicking a link that goes to page two of a multi-page list.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;font-family:arial;" &gt;Hudson&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For a test like this to be valuable, it needs to be run on a regular basis. While cron or &lt;a href="http://support.microsoft.com/kb/308569"&gt;Scheduled Tasks&lt;/a&gt; can do this, I much prefer &lt;a href="https://hudson.dev.java.net/"&gt;Hudson&lt;/a&gt;, the continuous integration engine we use for verifying our commits do not break our JUnit tests. Hudson normally fires on actions like Subversion commits, but it can also schedule builds on a regular basis. So I set the performance task to run every hour and it just cranks away, sending me an email if there are any problems. While there are a lot of continuous integration engines available, both open-source and commercial, I am extremely pleased with both the quality of Hudson and the rate of development. I'll be writing a lot more about Hudson as soon as I get a chance. Check it out!&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_07MQFGLRKcI/Ryimlnz1TeI/AAAAAAAAAA0/RNgqL6ouch8/s1600-h/hudson.png"&gt;&lt;img style="cursor: pointer;" src="http://2.bp.blogspot.com/_07MQFGLRKcI/Ryimlnz1TeI/AAAAAAAAAA0/RNgqL6ouch8/s400/hudson.png" alt="" id="BLOGGER_PHOTO_ID_5127531341033065954" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style=";font-family:arial;font-size:130%;"  &gt;&lt;span style="font-weight: bold;"&gt;Give Me My Screen Back!&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Since Watir actually fires up an instance of IE to do its work, it can be very disconcerting when a test fires off on your desktop machine while you are working on something else. I did have Watir minimize IE as soon as it started, but it would still be stealing focus from me and sometimes things I was trying to type in an editor would end up in some form field in IE and break the test.&lt;br /&gt;&lt;br /&gt;I tried using another box, but it turns out it was slow enough that the tests didn't run very well. What finally worked out was using a virtual machine via &lt;a href="http://www.vmware.com/"&gt;VMware&lt;/a&gt;. Their &lt;a href="http://www.vmware.com/download/server/"&gt;VMWare Server&lt;/a&gt; is free, though you do have to sign up to get activation codes. So far, the amount of spam has been quite reasonable. I have a fairly beefy machine at work (Intel dual core, 2GB RAM), but I don't notice any degradation in performance.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:arial;font-size:130%;"  &gt;Graphing the Results&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;While I could export the results to Excel (or better yet, &lt;a href="http://symphony.lotus.com/software/lotus/symphony/home.jspa"&gt;IBM Lotus Symphony&lt;/a&gt;), I ended up using the powerful &lt;a href="http://www.jfree.org/jfreechart/"&gt;JFreeChart&lt;/a&gt; package. It offers an amazing amount of control in creating just the graph you want. I looked for a Ruby graphing package, but everything I found was pathetic compared to JFreeChart. Since I am not much of a Java fan, I wrote the code in &lt;a href="http://jruby.codehaus.org/"&gt;JRuby&lt;/a&gt;. This also allowed me to pull in information from other sources, including our Apache logs and &lt;a href="http://www.zabbix.com/"&gt;Zabbix&lt;/a&gt;. Here is a sample chart:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_07MQFGLRKcI/RyiZf3z1TdI/AAAAAAAAAAs/UM53taRiwBc/s1600-h/sp2007-08-18.png"&gt;&lt;img style="cursor: pointer;" src="http://3.bp.blogspot.com/_07MQFGLRKcI/RyiZf3z1TdI/AAAAAAAAAAs/UM53taRiwBc/s320/sp2007-08-18.png" alt="" id="BLOGGER_PHOTO_ID_5127516948597657042" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This particular graph shows that on a weekend with almost no traffic to the site (pink line), there were still performance hits on both staging (blue line) and production (red line) around 4 AM and 4 PM. These periods also corresponded to increased CPU load on the server (black line).&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;font-family:arial;" &gt;Summary&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;By using several open-source tools and a few snippets of code, I am able to record and graph the performance of our system over time and understand the impact changes to our system and operating environment have on our user experience. I recommend adding performance testing to your standard regression test suite. The immediate feedback is very helpful in heading off design decisions with negative performance implications.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5963350864821674235-8637828149677312016?l=effectiveqa.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/8637828149677312016/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5963350864821674235&amp;postID=8637828149677312016&amp;isPopup=true' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/8637828149677312016'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/8637828149677312016'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/2007/10/using-watir-and-hudson-to-monitor.html' title='Using Watir and Hudson to Monitor Performance'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://2.bp.blogspot.com/_07MQFGLRKcI/Ryimlnz1TeI/AAAAAAAAAA0/RNgqL6ouch8/s72-c/hudson.png' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5963350864821674235.post-8200583190244432941</id><published>2007-10-19T15:17:00.000-06:00</published><updated>2007-12-16T10:35:09.822-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='load testing'/><category scheme='http://www.blogger.com/atom/ns#' term='stress testing'/><category scheme='http://www.blogger.com/atom/ns#' term='performance testing'/><title type='text'>Open Source Load Testing with WebLOAD</title><content type='html'>&lt;span style="font-weight: bold;font-family:verdana;font-size:130%;"  &gt;Introduction&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For some time now I've been playing with &lt;a href="http://grinder.sourceforge.net/"&gt;Grinder&lt;/a&gt; as a load-testing tool. There was much to like about Grinder - it seemed like one of the more advanced open-source load/capacity testers. The scripting language is &lt;a href="http://www.jython.org/"&gt;Jython&lt;/a&gt;, which I love as a result of long being a fan of &lt;a href="http://www.python.org/"&gt;Python&lt;/a&gt;. Still, it is clearly underpowered compared to commercial tools. Then, one day when I was visiting Open Source Testing, I ran across &lt;a href="http://www.webload.org/"&gt;WebLOAD&lt;/a&gt; and I knew that I was on to something special.&lt;br /&gt;&lt;br /&gt;WebLOAD claims to contain over 250 man-years of development. It was converted to open source in April 2007.  It was created by Ilan Kinreich, &lt;span style=";font-family:georgia;font-size:100%;"  &gt;a co-founder of Mercury Interactive. In my opinion, this is a commercial quality application. One area that really shows is the documentation. After trying to piece together how some open-source tools work by reading forum entries, having &lt;span style="font-weight: bold;"&gt;real &lt;/span&gt;documentation is a godsend.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:verdana;font-size:130%;"  &gt;Getting Started&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;WebLOAD has an excellent &lt;a href="http://www.webload.org/WebLOAD%20QuickStart_OpenSource.pdf"&gt;Quick Start&lt;/a&gt; guide. I highly recommend starting there. The basic steps for running a load test are:&lt;br /&gt;&lt;/span&gt;&lt;ol&gt;&lt;li&gt;Create an Agenda&lt;/li&gt;&lt;li&gt;Configure a load template&lt;/li&gt;&lt;li&gt;Configure session options&lt;/li&gt;&lt;li&gt;Run the test&lt;/li&gt;&lt;li&gt;Analyze the results&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;span style=";font-family:georgia;font-size:100%;"  &gt;&lt;span style="font-weight: bold;"&gt;Create an Agenda&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Creating agendas are easy. WebLOAD comes with a proxy recorder. You simply start the recorder and execute a user scenario in your browser. The proxy is set up automatically - no manual steps in your browser options. The commands are stored as Javascript. I really appreciate not having to learn yet another proprietary language.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_07MQFGLRKcI/RySFeXz1TaI/AAAAAAAAAAM/Pbi52KBqjPo/s1600-h/ide.png"&gt;&lt;img style="cursor: pointer;" src="http://1.bp.blogspot.com/_07MQFGLRKcI/RySFeXz1TaI/AAAAAAAAAAM/Pbi52KBqjPo/s400/ide.png" alt="" id="BLOGGER_PHOTO_ID_5126369032688455074" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The recorder also has playback and debug capabilities. It is really nice to get your agenda working cleanly before running 1,000 concurrent versions of it!&lt;br /&gt;&lt;span style=";font-family:georgia;font-size:100%;"  &gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Configure a Load Template&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A load template is when you actually configure the test to be run. What agenda(s) will be used? What statistics will be collected? How many simultaneous users will you simulate? Will they hit the site all at once or ramp up linearly? What host or hosts will provide the virtual clients?&lt;br /&gt;&lt;br /&gt;All of this is done from the main WebLOAD console, not the IDE that you used to record the Agenda.&lt;br /&gt;&lt;br /&gt;I highly recommend using the wizard that runs through the configuration options to set up the template.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Setting Session Options&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Under &lt;span style="font-weight: bold;"&gt;Tools &gt; Current Session Options&lt;/span&gt;, there are a large number of controls you can set, like the maximum time it can take for a page to return before it is considered a failure. In the Quick Start guide, they set a 20-second maximum time and verify 5% of the sessions.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Run the Test&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;From the Console, you just click the the Start Session icon and you are under way.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_07MQFGLRKcI/RySN-3z1TcI/AAAAAAAAAAc/jJUY7Sj34Mw/s1600-h/console2.png"&gt;&lt;img style="cursor: pointer;" src="http://3.bp.blogspot.com/_07MQFGLRKcI/RySN-3z1TcI/AAAAAAAAAAc/jJUY7Sj34Mw/s320/console2.png" alt="" id="BLOGGER_PHOTO_ID_5126378387127225794" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;I love watching the various stats displaying in real time. Very cool! When running a stress test, monitoring the log view gives a good indication of when things start to break down.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Analyze the Results&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;WebLOAD has the ability to graph any number of parameters and statistics, including things like CPU and disk utilization on the server(s). It also supports export of data to popular formats such as Excel.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:verdana;font-size:130%;"  &gt;Hurdles&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I did have to overcome several problems before WebLOAD would work with the main application I test. The first is that my application uses &lt;a href="http://en.wikipedia.org/wiki/Rewrite_engine"&gt;URL rewriting&lt;/a&gt; to track user sessions. So any URL recorded with the IDE will be incorrect at testing time, since each session is assigned a new sessionid which is part of the URL. This is where WebLOAD's professional documentation comes in again. On &lt;a href="http://www.webload.org/community-resources/index.php"&gt;their forum&lt;/a&gt;, a white paper called "&lt;a href="http://www.webload.org/phpbb/viewtopic.php?t=69"&gt;Session Management in Performance Testing [How-to]&lt;/a&gt;" describes handling URL re-writing along with cookies and hidden-form fields. You've got to love professional documentation!&lt;br /&gt;&lt;br /&gt;The second issue I haven't figured out yet is why I was not able to record from our test site. I had to build sessions from our production site, then went in and modified the URLs to reference our test server. I'll let you know what I figure out with this one.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:verdana;font-size:130%;"  &gt;Gotchas&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I learned a lesson the hard way. Do not run a stress test on your production system during business hours! (Notice issue number two in "Hurdles.") I managed to run an Agenda that hadn't been converted to the testing server's URLs. Ouch. It brought down the server at one point. Not a good thing to be doing at 10 AM! There is one good thing that came from this - it convinced me that WebLOAD was actually doing something. It's not just a program that draws pretty graphs. ;-)&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-family:verdana;font-size:130%;"  &gt;Summary&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Indeed, I am impressed with WebLOAD. It comes closest to an "ideal" load-testing solution than anything I've seen in the open source world. I especially like the professional quality documentation. With most open-source load testers, I give up in frustration before I ever get anything working. With WebLOAD, I had things working in a morning.&lt;br /&gt;&lt;br /&gt;Perhaps others who have experience with commercial tools such as HP's &lt;a href="https://h10078.www1.hp.com/cda/hpms/display/main/hpms_content.jsp?zn=bto&amp;amp;cp=1-11-126-17%5E8_4000_100__"&gt;LoadRunner&lt;/a&gt; will chime in on how it compares to the "big boys".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5963350864821674235-8200583190244432941?l=effectiveqa.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://effectiveqa.blogspot.com/feeds/8200583190244432941/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5963350864821674235&amp;postID=8200583190244432941&amp;isPopup=true' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/8200583190244432941'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5963350864821674235/posts/default/8200583190244432941'/><link rel='alternate' type='text/html' href='http://effectiveqa.blogspot.com/2007/10/open-source-load-testing-with-webload.html' title='Open Source Load Testing with WebLOAD'/><author><name>Frank</name><uri>http://www.blogger.com/profile/17737727794944256372</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='24' height='32' src='http://www.effectiveqa.com/images/frank.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_07MQFGLRKcI/RySFeXz1TaI/AAAAAAAAAAM/Pbi52KBqjPo/s72-c/ide.png' height='72' width='72'/><thr:total>0</thr:total></entry></feed>
