<?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-20525325</id><updated>2011-07-08T00:27:29.218-04:00</updated><category term='Computing'/><category term='Lean'/><category term='Agile'/><category term='Java'/><category term='Ruby'/><category term='Economics'/><category term='Object-Oriented'/><title type='text'>appleCart.upset()</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://cgardner.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20525325/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://cgardner.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Christopher R. Gardner</name><uri>http://www.blogger.com/profile/02189732519896125051</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>12</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-20525325.post-7775280514246956011</id><published>2010-06-20T23:03:00.023-04:00</published><updated>2010-06-21T20:09:41.925-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Test Driving a ThreadLocal Implementation: Part 1</title><content type='html'>A typical system needs access to variables or resources of varying scopes. Those resources are accessible from many providers, including singletons, configuration objects that read external properties files, and factories that rely on configuration files for dependency injection frameworks.  Some resources should be globally reachable by any object in the system.  Other resources, however, should be  restricted to one object, a trusted subsystem, or even a single thread.&lt;br /&gt;&lt;br /&gt;In the case of a thread, an oft-used solution in the Java world is the venerable &lt;code&gt;ThreadLocal&lt;/code&gt;.  Some transaction processing approaches in multi-threaded systems, for example, employ a &lt;code&gt;static final ThreadLocal&lt;/code&gt; to make a unique transactional resource available to any object in a thread.  In particular, developers using pre-3.0.1 versions of Hibernate often used &lt;a href="http://simoes.org/docs/hibernate-2.1/42.html" target="_blank"&gt;this approach&lt;/a&gt; to propagate a &lt;code&gt;Session&lt;/code&gt; to data access objects.&lt;br /&gt;&lt;br /&gt;We could use &lt;code&gt;ThreadLocal&lt;/code&gt; in creating a framework based on the &lt;a href="http://martinfowler.com/eaaCatalog/unitOfWork.html" target="_blank"&gt;UnitOfWork&lt;/a&gt; pattern.  In a layered system that uses the framework, we could propagate a &lt;code&gt;UnitOfWork&lt;/code&gt; object to a &lt;a href="http://martinfowler.com/eaaCatalog/repository.html" target="_blank"&gt;Repository&lt;/a&gt; without muddying the Repository interface.  It's fairly easy to visualize how all this might work.  An application object could tell a &lt;code&gt;UnitOfWorkManager&lt;/code&gt; to create a &lt;code&gt;UnitOfWork&lt;/code&gt; for managing a transaction boundary.  Repositories could call upon the &lt;code&gt;UnitOfWorkManager&lt;/code&gt; for the current &lt;code&gt;UnitOfWork&lt;/code&gt; to support implementation details (e.g., using a JDBC &lt;code&gt;Connection&lt;/code&gt;).&lt;br /&gt;&lt;br /&gt;Assume in a earlier unit test, we discovered the applicability of the &lt;code&gt;UnitOfWorkManager&lt;/code&gt; and &lt;code&gt;UnitOfWork&lt;/code&gt; concepts.  We ultimately decided to create a &lt;code&gt;UnitOfWorkManager&lt;/code&gt; interface with implementations that could be injected into other objects.&lt;br /&gt;&lt;br /&gt;Here is our interface.  We'll skip the details of the &lt;code&gt;UnitOfWork&lt;/code&gt; itself.&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;package example;&lt;br /&gt;&lt;br /&gt;public interface UnitOfWorkManager {&lt;br /&gt;    UnitOfWork create();&lt;br /&gt;    UnitOfWork current();&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Let's test drive a &lt;code&gt;UnitOfWorkManager&lt;/code&gt; implementation, proving that each thread can create and access a unique &lt;code&gt;UnitOfWork&lt;/code&gt; object from one &lt;code&gt;UnitOfWorkManager&lt;/code&gt;.&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;package example;&lt;br /&gt;&lt;br /&gt;import static org.junit.Assert.*;&lt;br /&gt;&lt;br /&gt;import org.junit.*;&lt;br /&gt;&lt;br /&gt;public class UnitOfWorkManagerTest {&lt;br /&gt;    private UnitOfWorkManager manager;&lt;br /&gt;    private UnitOfWorkConsumer firstConsumer;&lt;br /&gt;    private UnitOfWorkConsumer secondConsumer;&lt;br /&gt;&lt;br /&gt;    @Before&lt;br /&gt;    public void setUp() {&lt;br /&gt;        manager = new MyUnitOfWorkManager();&lt;br /&gt;        firstConsumer = new UnitOfWorkConsumer(manager);&lt;br /&gt;        secondConsumer = new UnitOfWorkConsumer(manager);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Test&lt;br /&gt;    public void createsUniqueUnitsOfWorkPerThread()&lt;br /&gt;            throws InterruptedException {&lt;br /&gt;        firstConsumer.consume();&lt;br /&gt;        secondConsumer.consume();&lt;br /&gt;        assertNotSame(firstConsumer.newWork,&lt;br /&gt;                      secondConsumer.newWork);&lt;br /&gt;        assertNotSame(firstConsumer.currentWork,&lt;br /&gt;                      secondConsumer.currentWork);&lt;br /&gt;        assertSame(firstConsumer.newWork,&lt;br /&gt;                   firstConsumer.currentWork);&lt;br /&gt;        assertSame(secondConsumer.newWork,&lt;br /&gt;                   secondConsumer.currentWork);&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    private class UnitOfWorkConsumer extends Thread {&lt;br /&gt;        final UnitOfWorkManager manager;&lt;br /&gt;        UnitOfWork newWork;&lt;br /&gt;        UnitOfWork currentWork;&lt;br /&gt;&lt;br /&gt;        UnitOfWorkConsumer(UnitOfWorkManager manager) {&lt;br /&gt;            this.manager = manager;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        @Override&lt;br /&gt;        public void run() {&lt;br /&gt;            newWork = manager.create();&lt;br /&gt;            currentWork = manager.current();&lt;br /&gt;        }&lt;br /&gt;        &lt;br /&gt;        void consume() throws InterruptedException {&lt;br /&gt;            start();&lt;br /&gt;            join();&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Finally, we have our implementation.&lt;br /&gt;&lt;code&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;package example;&lt;br /&gt;&lt;br /&gt;public class MyUnitOfWorkManager implements UnitOfWorkManager {&lt;br /&gt;    private static final ThreadLocal&amp;lt;UnitOfWork&amp;gt; localUnitOfWork =&lt;br /&gt;        new ThreadLocal&amp;lt;UnitOfWork&amp;gt;() {&lt;br /&gt;            @Override&lt;br /&gt;            protected UnitOfWork initialValue() {&lt;br /&gt;                return new UnitOfWork();&lt;br /&gt;            }&lt;br /&gt;        };&lt;br /&gt;&lt;br /&gt;    public UnitOfWork create() {&lt;br /&gt;        UnitOfWork unitOfWork = current();&lt;br /&gt;        prepare(unitOfWork);&lt;br /&gt;        return unitOfWork;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public UnitOfWork current() {&lt;br /&gt;        return localUnitOfWork.get();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private void prepare(UnitOfWork unitOfWork) {&lt;br /&gt;       //Not shown&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Typically, objects in a static context are accessed via static methods.  We don't do that here because we are implementing an interface, and our static access is an implementation detail.  Incidentally, we'll need to prevent returning an unprepared &lt;code&gt;UnitOfWork&lt;/code&gt; if a consumer fails to first call &lt;code&gt;create()&lt;/code&gt;.  We may be able to eliminate &lt;code&gt;create()&lt;/code&gt; altogether and override &lt;code&gt;ThreadLocal.get()&lt;/code&gt; to handle proper initialization when &lt;code&gt;current()&lt;/code&gt; is called.  This scenario is beyond the scope of our example.&lt;br /&gt;&lt;br /&gt;In any event, we've succesfully test-driven a simple implementation of our original goal.  The test, however, could stand some minor refactoring, which we'll take up in a later post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20525325-7775280514246956011?l=cgardner.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cgardner.blogspot.com/feeds/7775280514246956011/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20525325&amp;postID=7775280514246956011' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20525325/posts/default/7775280514246956011'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20525325/posts/default/7775280514246956011'/><link rel='alternate' type='text/html' href='http://cgardner.blogspot.com/2010/06/test-driving-threadlocal-implementation.html' title='Test Driving a ThreadLocal Implementation: Part 1'/><author><name>Christopher R. Gardner</name><uri>http://www.blogger.com/profile/02189732519896125051</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20525325.post-5775369277759109350</id><published>2010-06-20T10:39:00.003-04:00</published><updated>2010-06-20T11:51:17.273-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>The Laws of WebSphere RAD</title><content type='html'>&lt;a href="http://en.wikipedia.org/wiki/Parkinson's_Law"&gt;Parkison's&lt;/a&gt; WebSphere RAD Law: RAD's demand for resources expands to consume all available RAM and CPU.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://en.wikipedia.org/wiki/Hofstadter's_law"&gt;Hofstadter's&lt;/a&gt; WebSphere RAD Law: It takes longer than expected for RAD to do anything, even when accounting for Hofstadter's WebSphere RAD law.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20525325-5775369277759109350?l=cgardner.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cgardner.blogspot.com/feeds/5775369277759109350/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20525325&amp;postID=5775369277759109350' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20525325/posts/default/5775369277759109350'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20525325/posts/default/5775369277759109350'/><link rel='alternate' type='text/html' href='http://cgardner.blogspot.com/2010/06/laws-of-websphere-rad.html' title='The Laws of WebSphere RAD'/><author><name>Christopher R. Gardner</name><uri>http://www.blogger.com/profile/02189732519896125051</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20525325.post-666118510242183016</id><published>2009-12-06T10:00:00.003-05:00</published><updated>2010-06-20T10:47:34.657-04:00</updated><title type='text'>Ralph and Ray Separated at Birth?</title><content type='html'>&lt;div&gt;Ray Manzarek of the Doors&lt;/div&gt;&lt;br /&gt;&lt;img src="http://temp15.proto-sites.com/files/images/28.jpg" /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;Ralph Johnson of GoF&lt;/div&gt;&lt;br /&gt;&lt;img src="http://www.gbg.expo-c.se/res/Gbg/ralph_johnson178_250.jpg" /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20525325-666118510242183016?l=cgardner.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cgardner.blogspot.com/feeds/666118510242183016/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20525325&amp;postID=666118510242183016' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20525325/posts/default/666118510242183016'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20525325/posts/default/666118510242183016'/><link rel='alternate' type='text/html' href='http://cgardner.blogspot.com/2009/12/ralph-and-ray-separated-at-birth.html' title='Ralph and Ray Separated at Birth?'/><author><name>Christopher R. Gardner</name><uri>http://www.blogger.com/profile/02189732519896125051</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20525325.post-6437889039207736454</id><published>2009-07-16T19:32:00.004-04:00</published><updated>2010-06-20T11:40:58.960-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Economics'/><title type='text'>A Free Market for Health Care</title><content type='html'>A former co-worker of mine suggested on his Facebook page that a solution for health care is a 2% income tax. Being a free market capitalist, I retorted that a completely free market for health care would solve our problems. Another person chimed in saying that the free market failed for the financial, airline, and automotive sectors. I felt obligated to offer this reply:&lt;br /&gt;&lt;br /&gt;There is no free market in any of the sectors you mention. The financial sector, for example, is among the most heavily regulated industries and it crumbled. A free market in a truly capitalistic system would allow any organization within those sectors to succeed or fail on its own. That did not happen. The government bailed out their friends in the financial and automotive sectors in a fascist, mercantilistic system, using the money of future generations.&lt;br /&gt;&lt;br /&gt;While the FAA still heavily regulates it, the airline industry was partially deregulated in 1978 (government removed price controls of fares). Look what has happened since then: There are low cost carriers such as AirTran and Southwest Airlines, making flights cheaper for everyone.&lt;br /&gt;&lt;br /&gt;A purely free market for health care would open up all kinds of options for insurance and medical services. Consumers would choose the best plans that would work for them with regard to cost and services. Some people would buy  catastrophic-only plans and pay directly for routine care. Others might purchase more comprehensive plans. Finally, in a free market, there might be more alternatives to insurance outright. Even now, for example, many doctors are providing concierge models that allow patients to see a doctor at almost any time for a range of services. Unfortunately, however, insurance and medical care are highly regulated by the federal government and individual states, increasing the cost to all.&lt;br /&gt;&lt;br /&gt;With a government run or dominated health care system, there would be fewer alternatives that would otherwise be created by capitalism. There would be &lt;br /&gt;either a severely hampered or no price system at all that demands providers and payors offer care and payment more efficiently (current regulations have brought this about today). Taxes will be raised, health care will be rationed, and you won't be able to do anything about it. Here is a taste of things to come:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.nytimes.com/2009/07/16/us/16hospital.html?_r=1&lt;br /&gt;     target="_blank"&gt;Massachusetts in Suit Over Cost of Universal Care&lt;/a&gt;&lt;br /&gt;&lt;a href="http://www.cqpolitics.com/wmspage.cfm?parm1=5&amp;amp;docID=news-000003168293"&gt;CBO Chief: Health Bills To Increase Federal Costs&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;As an example with the universal coverage in MA, health care is already being rationed. There are plans to remove legal immigrants from the system. Today on National People's Radio (NPR), I heard a story of a legal immigrant who has cancer. He's about to be removed from coverage. People complain if private insurance drops coverage, but it looks like universal health care has effectively rationed service to some people. We don't need this disaster on a grand scale.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20525325-6437889039207736454?l=cgardner.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cgardner.blogspot.com/feeds/6437889039207736454/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20525325&amp;postID=6437889039207736454' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20525325/posts/default/6437889039207736454'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20525325/posts/default/6437889039207736454'/><link rel='alternate' type='text/html' href='http://cgardner.blogspot.com/2009/07/free-market-for-health-care.html' title='A Free Market for Health Care'/><author><name>Christopher R. Gardner</name><uri>http://www.blogger.com/profile/02189732519896125051</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20525325.post-5876484850711722747</id><published>2009-03-20T20:36:00.004-04:00</published><updated>2010-06-20T11:42:11.100-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Computing'/><title type='text'>Excellent Posts on Load Balancing</title><content type='html'>&lt;a href="http://devcentral.f5.com/weblogs/dmacvittie/archive/2009/03/11/intro-load-balancing-for-developers-ndash-the-architectrsquos-view.aspx"&gt;This&lt;/a&gt; and &lt;a href="http://devcentral.f5.com/weblogs/dmacvittie/archive/2009/03/17/intro-to-load-balancing-for-developers-ndash-how-they-work.aspx"&gt;this&lt;/a&gt; are must reads on the elements of load balancing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20525325-5876484850711722747?l=cgardner.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cgardner.blogspot.com/feeds/5876484850711722747/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20525325&amp;postID=5876484850711722747' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20525325/posts/default/5876484850711722747'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20525325/posts/default/5876484850711722747'/><link rel='alternate' type='text/html' href='http://cgardner.blogspot.com/2009/03/excellent-posts-on-load-balancing.html' title='Excellent Posts on Load Balancing'/><author><name>Christopher R. Gardner</name><uri>http://www.blogger.com/profile/02189732519896125051</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20525325.post-920369778755617780</id><published>2009-03-04T18:17:00.007-05:00</published><updated>2009-03-04T20:38:29.768-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><title type='text'>Continuous Integration (CI) Needs No Standards</title><content type='html'>In his CM Crossroads &lt;a href="http://www.cmcrossroads.com/content/view/12735/120/"&gt;article&lt;/a&gt;, Bob Aiello postulates that CI has problems, "... many of which could be solved (or at least made better) by adopting well-established industry standards (e.g., IEEE, ISO etc.)."   Mr. Aiello never proves his supposition.  Of the "many" purported CI problems, he writes of only one: The creation of unit tests.  The IEEE 1008 Unit Testing Standard, he says, will help developers in this pursuit.&lt;br /&gt;&lt;br /&gt;Are such standards really necessary for any aspect of CI?  With regard to writing unit tests, there are many excellent books on overall approaches, tools, and patterns.  Moreover, as for CI servers, the open source and commercial worlds have been providing successful products for almost a decade.  The popular servers can work with many different source code repositories, such as Subversion and Git, and run common build tools, such as ant and rake.&lt;br /&gt;&lt;br /&gt;CI is doing just fine, thank you very much.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20525325-920369778755617780?l=cgardner.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cgardner.blogspot.com/feeds/920369778755617780/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20525325&amp;postID=920369778755617780' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20525325/posts/default/920369778755617780'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20525325/posts/default/920369778755617780'/><link rel='alternate' type='text/html' href='http://cgardner.blogspot.com/2009/03/continuous-integration-ci-needs-no.html' title='Continuous Integration (CI) Needs No Standards'/><author><name>Christopher R. Gardner</name><uri>http://www.blogger.com/profile/02189732519896125051</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20525325.post-1989101167436806689</id><published>2009-02-17T20:03:00.005-05:00</published><updated>2009-02-17T20:24:25.824-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>Rcor is Now Ruby-Concordion</title><content type='html'>&lt;a href="http://code.google.com/p/rcor/"&gt;Rcor&lt;/a&gt;, a wonderful acceptance testing tool based on &lt;a href="http://www.concordion.org/"&gt;Concordion&lt;/a&gt;, has just been renamed Ruby-Concordion.  Please check it out.  You can get the latest gem from the &lt;a href="http://code.google.com/p/rcor/downloads/list"&gt;Google download page&lt;/a&gt; or from &lt;a href="http://rubyforge.org/projects/ruby-concordion/"&gt;RubyForge&lt;/a&gt;.  Better yet just install it directly:&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&lt;code&gt;gem install concordion&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20525325-1989101167436806689?l=cgardner.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cgardner.blogspot.com/feeds/1989101167436806689/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20525325&amp;postID=1989101167436806689' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20525325/posts/default/1989101167436806689'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20525325/posts/default/1989101167436806689'/><link rel='alternate' type='text/html' href='http://cgardner.blogspot.com/2009/02/rcor-is-now-ruby-concordion.html' title='Rcor is Now Ruby-Concordion'/><author><name>Christopher R. Gardner</name><uri>http://www.blogger.com/profile/02189732519896125051</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20525325.post-7345038281990737817</id><published>2009-02-12T20:47:00.013-05:00</published><updated>2010-06-20T11:43:39.163-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>Double Ruby</title><content type='html'>Now that I'm beginning to use Ruby for more than Hello World programs, I started searching for a great mocking framework. My search brought me to &lt;a href="http://www.ibm.com/developerworks/web/library/wa-mockrails/index.html"&gt;Bruce Tate's overview of Ruby mocking frameworks&lt;/a&gt;, which illustrates &lt;a href="http://mocha.rubyforge.org/"&gt;mocha&lt;/a&gt; and &lt;a href="http://flexmock.rubyforge.org/"&gt;Flex Mock&lt;/a&gt;. I noticed that both frameworks require the use of symbols to stub method calls. I much prefer the approach that &lt;a href="http://code.google.com/p/mockito/"&gt;mockito&lt;/a&gt;, my favorite Java mocking framework, takes: Stubbing method calls via calls to the methods themselves rather than string representations thereof. This technique makes tests easier to write and maintain.&lt;br /&gt;&lt;br /&gt;I stumbled across &lt;a href="https://rubyforge.org/projects/double-ruby/"&gt;RR (Double Ruby)&lt;/a&gt;, a framework that may be Ruby's answer to mockito. It supports many, if not most, of the approaches to Test Double. I happen to be interested in the stub approach and created a variation of the tests in Bruce's article.&lt;br /&gt;&lt;br /&gt;Here is what I came up with:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;require 'test/unit'&lt;br /&gt;require 'rr'&lt;br /&gt;&lt;br /&gt;class DoubleRubyTest &amp;#60; Test::Unit::TestCase&lt;br /&gt; include RR::Adapters::TestUnit&lt;br /&gt;&lt;br /&gt; def setup&lt;br /&gt;   @document = stub_document&lt;br /&gt;   @view = View.new(@document)&lt;br /&gt; end&lt;br /&gt;&lt;br /&gt; def test_view_prints_and_remains_open&lt;br /&gt;   stub(@document).close.returns(false)&lt;br /&gt;   assert(@view.print)&lt;br /&gt;   assert(!@view.close)&lt;br /&gt; end&lt;br /&gt;&lt;br /&gt; def test_view_prints_and_closes&lt;br /&gt;   stub(@document).close.returns(true)&lt;br /&gt;   assert(@view.print)&lt;br /&gt;   assert(@view.close)&lt;br /&gt; end&lt;br /&gt;&lt;br /&gt; private&lt;br /&gt;&lt;br /&gt; def stub_document&lt;br /&gt;   stub!.print.returns(true).subject&lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;class View&lt;br /&gt; def initialize(document)&lt;br /&gt;   @document = document&lt;br /&gt; end&lt;br /&gt;&lt;br /&gt; def print&lt;br /&gt;   @document.print&lt;br /&gt; end&lt;br /&gt;&lt;br /&gt; def close&lt;br /&gt;   @document.close&lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Notice the stub_document method. The single line of code creates the stub and mocks the print method in one swoop. The subject method returns a reference to the mock itself.&lt;br /&gt;&lt;br /&gt;Per the &lt;a href="https://rubyforge.org/frs/shownotes.php?group_id=6484&amp;amp;release_id=30504"&gt;release notes&lt;/a&gt;, the framework seeks to make mocked code "more scannable."  In my case, this scannability helped me to do a reasonable rename refactoring in NetBeans.&lt;br /&gt;&lt;br /&gt;While my example created a stub based on no particular class definition (an empty object), the framework does allow you to stub objects of specific classes.&lt;br /&gt;&lt;br /&gt;With its wonderfully terse syntax and variety of Test Doubles, this is one framework you should soon evaulate.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20525325-7345038281990737817?l=cgardner.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cgardner.blogspot.com/feeds/7345038281990737817/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20525325&amp;postID=7345038281990737817' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20525325/posts/default/7345038281990737817'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20525325/posts/default/7345038281990737817'/><link rel='alternate' type='text/html' href='http://cgardner.blogspot.com/2009/02/double-ruby.html' title='Double Ruby'/><author><name>Christopher R. Gardner</name><uri>http://www.blogger.com/profile/02189732519896125051</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20525325.post-6856470625151350875</id><published>2009-01-28T18:54:00.000-05:00</published><updated>2009-01-28T19:07:17.529-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><category scheme='http://www.blogger.com/atom/ns#' term='Ruby'/><title type='text'>rcor 0.8.7 Released</title><content type='html'>&lt;a href="http://code.google.com/p/rcor/"&gt;rcor&lt;/a&gt; 0.8.7, a Ruby acceptance testing tool based on &lt;a href="http://www.concordion.org/"&gt;Concordion&lt;/a&gt;, has just been released.  I've had the pleasure of making a few minor contributions to rcor and am starting to use it in anger at work.  Give it a &lt;a href="http://code.google.com/p/rcor/downloads/list"&gt;try&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20525325-6856470625151350875?l=cgardner.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cgardner.blogspot.com/feeds/6856470625151350875/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20525325&amp;postID=6856470625151350875' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20525325/posts/default/6856470625151350875'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20525325/posts/default/6856470625151350875'/><link rel='alternate' type='text/html' href='http://cgardner.blogspot.com/2009/01/rcor-087-released.html' title='rcor 0.8.7 Released'/><author><name>Christopher R. Gardner</name><uri>http://www.blogger.com/profile/02189732519896125051</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20525325.post-3507540195809161599</id><published>2006-10-11T14:12:00.000-04:00</published><updated>2006-10-12T10:02:16.338-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Object-Oriented'/><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Sad Commentary on the Purpose of Domain Objects</title><content type='html'>I'm reading the book &lt;i&gt;&lt;a href="http://www.bookpool.com/sm/1590596455"&gt;Pro EJB 3 Java Persistence API&lt;/a&gt;&lt;/i&gt;.  I highly recommend this book to learn the JPA.  When I came across the following passage about unit testing JPA entities, however, I was dismayed but not suprised:&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;Entities themselves are unlikely to be extensively tested in isolation. Most methods on entities are simple getters or setters that relate to the persistent state of the entity or to its relationships. &lt;b&gt;Business methods may also appear on entities but are less common.  In many applications, entities are little more than basic JavaBeans.&lt;/b&gt; (p. 357)&lt;/blockquote&gt;&lt;br /&gt;In my own application development, entities are the domain, or business, objects.  Hence, in my warped world a domain object &lt;i&gt;must&lt;/i&gt; have sophisticated business methods that affect its state.  I thought state and behavior are supposed to be coupled. From the sheer number of procedural systems masquerading as object-oriented, I must be in the minority.  I guess I need to forget about objects.  I should change my blog name to the following:&lt;br /&gt;&lt;pre&gt;&lt;span style="font-size:100%;"&gt;&lt;code&gt;&lt;br /&gt;if (appleCart.getState() == AppleCartState.NOT_UPSET) {&lt;br /&gt;    appleCart.setState(AppleCartState.UPSET);&lt;br /&gt;}&lt;/code&gt;&lt;/span&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20525325-3507540195809161599?l=cgardner.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cgardner.blogspot.com/feeds/3507540195809161599/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20525325&amp;postID=3507540195809161599' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20525325/posts/default/3507540195809161599'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20525325/posts/default/3507540195809161599'/><link rel='alternate' type='text/html' href='http://cgardner.blogspot.com/2006/10/sad-commentary-on-purpose-of-domain.html' title='Sad Commentary on the Purpose of Domain Objects'/><author><name>Christopher R. Gardner</name><uri>http://www.blogger.com/profile/02189732519896125051</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20525325.post-6974023616601812539</id><published>2006-10-10T16:36:00.000-04:00</published><updated>2006-10-12T09:16:34.293-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Lean'/><category scheme='http://www.blogger.com/atom/ns#' term='Agile'/><title type='text'>Should Agile Be Imposed?</title><content type='html'>There has been some recent buzz regarding Martin Fowler's blog about the &lt;a href="http://martinfowler.com/bliki/AgileImposition.html"&gt;imposition of agile development&lt;/a&gt;.  In general, I agree with his view.  However, there are situations that could dictate otherwise.&lt;br /&gt;&lt;br /&gt;What if management is trying to transform the way the organization does business?  In fact, management is obliged to make decisions that change the organization for the better.  Those decisions may indeed impact members of the organization on a daily basis.&lt;br /&gt;&lt;br /&gt;For example, a company's revenues have been falling for 5 consecutive quarters.  With increasing costs, profits are becoming losses.  The company is losing customers.  Management determines the business model is flawed and studies alternatives.  They conclude that lean production may increase the likelihood of survival and prosperity.  They want to apply lean thinking to all aspects of the business from logistics, to inventory, and to software development.&lt;br /&gt;&lt;br /&gt;A commissioned group of developers and managers conclude an agile software process may be an appropriate component of the lean business model.  Currently, the organization uses a waterfall software process with which many participants are quite happy.  The process, however, is chock-full of prescriptive procedures and deliverables that a value stream analysis suggests are wasteful.  Moreover, the process has led to over-budget software that fails to solve current business problems.&lt;br /&gt;&lt;br /&gt;In this case, someone must make changes.  While there are many participants willing to use agile, there is much resistance.  Some key participants are even threatening to quit if they are forced to use agile.  Nonetheless, it cannot stand that the discordant will be doing waterfall and the accordant will be doing agile.&lt;br /&gt;&lt;br /&gt;What if someone does not begin to impose change?  What happens to the organization if the current poor practices are allowed to stand?  Will there be consequences in the market?  Are the competitors producing more quickly and making more money?  If agile development cannot at least mitigate the current software problems, what can?&lt;br /&gt;&lt;br /&gt;In any troubled organization, there are some who are perfectly content to roll around in the filth of the status quo; there are others at all organizational levels who are truly visionary and can be agents of change.  Sometimes outright acceptance does not happen; sometimes finesse fails; sometimes imposition is required.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20525325-6974023616601812539?l=cgardner.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cgardner.blogspot.com/feeds/6974023616601812539/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20525325&amp;postID=6974023616601812539' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20525325/posts/default/6974023616601812539'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20525325/posts/default/6974023616601812539'/><link rel='alternate' type='text/html' href='http://cgardner.blogspot.com/2006/10/should-agile-be-imposed-there-has-been.html' title='Should Agile Be Imposed?'/><author><name>Christopher R. Gardner</name><uri>http://www.blogger.com/profile/02189732519896125051</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-20525325.post-114144140409921048</id><published>2006-03-03T21:46:00.000-05:00</published><updated>2006-10-11T20:57:14.832-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Java'/><title type='text'>Towards Typesafe Closures in Java 5.0</title><content type='html'>In my study of &lt;a href="http://www.ruby-lang.org/en/"&gt;Ruby&lt;/a&gt;, I've become enamored with the concept of &lt;a href="http://martinfowler.com/bliki/Closure.html"&gt;closures&lt;/a&gt;.  Many a Java developer has pined for such a brilliant feature.  Perhaps one day the language itself or its standard packages will provide support. What, however, could one do in the meantime?&lt;br /&gt;&lt;br /&gt;The &lt;a href="http://jakarta.apache.org/commons/collections/"&gt;Collections&lt;/a&gt; component of &lt;a href="http://jakarta.apache.org/commons/components.html"&gt;Jakarta Commons&lt;/a&gt; offers the static utility solution, namely this class and method:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;CollectionUtils.forAllDo(Collection, Closure).&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;code&gt;Closure&lt;/code&gt; is an interface with an execute operation that takes an &lt;code&gt;Object&lt;/code&gt;.  &lt;code&gt;Closure.execute(Object)&lt;/code&gt; has the nagging requirement that you must downcast the &lt;code&gt;Object&lt;/code&gt; parameter to do something very meaningful with it, and downcasting may result in a &lt;code&gt;ClassCastException.&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;While &lt;code&gt;CollectionUtils&lt;/code&gt; has the advantage of using the standard Java collections, it would be proper if a &lt;code&gt;Collection&lt;/code&gt; object could run a &lt;code&gt;Closure&lt;/code&gt; over itself in true object-oriented fashion.  If you are willing to live with your own collection class, you can do this.  Moreover, you can do this is in a typesafe manner with Java 5.0 &lt;a href="http://java.sun.com/j2se/1.5/pdf/generics-tutorial.pdf"&gt;generics&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Here we have the typesafe &lt;code&gt;Closure&lt;/code&gt; interface:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;public interface Closure&amp;lt;E&amp;gt; {&lt;br /&gt;    void execute(E item);&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;and the custom collection class (of course, a better name for it might be in order):&lt;br /&gt;&lt;pre&gt;&lt;span style="font-size:100%;"&gt;&lt;code&gt;&lt;br /&gt;import java.util.ArrayList;&lt;br /&gt;import java.util.Collection;&lt;br /&gt;import java.util.Iterator;&lt;br /&gt;&lt;br /&gt;public class ClosureableCollection&amp;lt;E&amp;gt; implements Collection&amp;lt;E&amp;gt; {&lt;br /&gt;    private Collection&amp;lt;E&amp;gt; collection;&lt;br /&gt;&lt;br /&gt;    public ClosureableCollection() {&lt;br /&gt;        this(new ArrayList&amp;lt;E&amp;gt;());&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public ClosureableCollection(Collection&amp;lt;E&amp;gt; collection) {&lt;br /&gt;        this.collection = collection;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void execute(Closure&amp;lt;E&amp;gt; closure) {&lt;br /&gt;        for (E collected : collection) {&lt;br /&gt;            closure.execute(collected);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;    ...&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;Notice that we implemented the &lt;code&gt;Collection&lt;/code&gt; interface.  One reason you may want to do this is if you have existing methods to which you must pass a &lt;code&gt;Collection&lt;/code&gt;.  Another reason is that maybe one day &lt;code&gt;Collection&lt;/code&gt; will actually accept closures, and, consequently, refactoring might be minimal.&lt;br /&gt;&lt;br /&gt;Now let's see how we can actually use this.&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;import static org.junit.Assert.assertTrue;&lt;br /&gt;&lt;br /&gt;import org.junit.Before;&lt;br /&gt;import org.junit.Test;&lt;br /&gt;&lt;br /&gt;public class ClosureableCollectionTest {&lt;br /&gt;    private Shape square;&lt;br /&gt;    private Shape circle;&lt;br /&gt;    private ClosureableCollection&amp;lt;Shape&amp;gt; shapes;&lt;br /&gt;&lt;br /&gt;    @Before&lt;br /&gt;    public void setUp() {&lt;br /&gt;        square = new Square();&lt;br /&gt;        circle = new Circle();&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    @Test&lt;br /&gt;    public void closureDrawsShapes() {&lt;br /&gt;        shapes = new ClosureableCollection&amp;lt;Shape&amp;gt;();&lt;br /&gt;        shapes.add(square);&lt;br /&gt;        shapes.add(circle);&lt;br /&gt;        shapes.execute(new Closure&amp;lt;Shape&amp;gt;() {&lt;br /&gt;            public void execute(Shape item) {&lt;br /&gt;                item.draw();&lt;br /&gt;                assertTrue(item.equals(square)&lt;br /&gt;                        || item.equals(circle));&lt;br /&gt;            }&lt;br /&gt;        });&lt;br /&gt;    }&lt;br /&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;The cost is having to carry your own collection class.  The benefit is a typesafe, object-oriented approach to a feature that Java should have now.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/20525325-114144140409921048?l=cgardner.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://cgardner.blogspot.com/feeds/114144140409921048/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=20525325&amp;postID=114144140409921048' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/20525325/posts/default/114144140409921048'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/20525325/posts/default/114144140409921048'/><link rel='alternate' type='text/html' href='http://cgardner.blogspot.com/2006/03/implementing-typesafe-closures-in-java.html' title='Towards Typesafe Closures in Java 5.0'/><author><name>Christopher R. Gardner</name><uri>http://www.blogger.com/profile/02189732519896125051</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry></feed>
