<?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-7546437942865144565</id><updated>2011-12-02T15:11:09.909-06:00</updated><category term='Business of IT'/><category term='logging'/><category term='grails'/><category term='JAMon'/><category term='Drupal'/><category term='grails podcast'/><category term='java'/><category term='groovy'/><category term='Architecure'/><category term='future state'/><category term='tweet'/><category term='best practices'/><category term='Flex'/><category term='performance'/><category term='social'/><category term='testing'/><category term='IT Management'/><title type='text'>3.times { theFun }</title><subtitle type='html'>Enterprise IT</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://ericbweimer.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://ericbweimer.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Eric Weimer</name><uri>http://www.blogger.com/profile/12419103951437664659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://3.bp.blogspot.com/-w1EAD8kSauk/Ttk-ifkupvI/AAAAAAAAARE/9Dbf5dwiXr4/s220/webpic.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>19</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7546437942865144565.post-4070149109443042757</id><published>2011-05-08T20:47:00.000-05:00</published><updated>2011-05-08T20:47:36.805-05:00</updated><title type='text'>How to Interview Developers</title><content type='html'>Over the years I have performed many interviews. I’ve also been on the other side of the table and am frequently amazed by the range of quality of interviews. I believe I do an excellent job at interviewing candidates, but then again so do most of the interviewers I’ve met.&lt;br /&gt;&lt;br /&gt;The problem of determining how well a candidate will perform in a role is difficult. We look at the past as an indicator of the future, but it is hard to determine past performance when each candidate has learned to show their background in the most positive manner. &lt;br /&gt;&lt;br /&gt;There are many techniques to assess a candidate, but I prefer to look at how useful they are. There are no good or bad questions, just degrees of &lt;i&gt;usefulness&lt;/i&gt;. Here are some of what I consider "best interview practices".&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Repeatability&lt;/b&gt;. We frequently interview multiple candidates for a role, and it is critical to be able to compare them. Use a form with interview questions and score them. Include both technical and soft skills, and leave room for comments. Scores are always approximate, but are useful when making comparisons. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Focus on time in your assessment.&lt;/b&gt; API's are displayed in an instant with any modern IDE. Any mediocre developer can memorize API's, but do they know how to solve problems? It is far more useful to understand concepts than being able to memorize classes and methods.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Theory versus practice.&lt;/b&gt; Yes, there are some folks who excel at theory but have trouble coding. If you need them to code, a take-home coding problem works very well to filter those out. Spend the little time you have in the interview to assess the level of understanding the candidate has.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Gear questions to the role.&lt;/b&gt; Ask questions that the candidate needs for the role, then add a few at a level higher. This provides a good indication of of how well suited the candidate is for the role and how close they are for the next step up. If the role is a lead developer, skip the simple questions life "what is the difference between a class and an object" and ask questions that show deeper understanding like" what is the difference between composition and aggregation"? &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Avoid hangups. &lt;/b&gt;Keep personal bias out of the process. One common anti-pattern is when the candidate reminds one of someone else who did or did not turn out well. It happens with technical questions as well as appearance, previous employers, schooling, etc. And it goes both ways, like the pony-tailed guy who won the job over a short-haired competitor. I've had both short and long hair, but am the same person. And in these days of casual dress, I really do not care if anyone wears a tie or not. As long as they show up on time in clothes that do not offend, I am fine. In fact if I can contact them before the interview I ask them to dress like they would while on the job. Then when they show up in a Cubs jersey, well lets not go there..&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Keep it real. &lt;/b&gt;An interview is an artificial situation to begin with, so keep the questions clear and realistic. Much has been written about the type of questions with no answer, but how does that translate to work? Questions that are too vague or too hypothetical are simply not predictive about success. Keep the interview realistic; time is short.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Ask about trends. &lt;/b&gt;Good developers are often aware of industry trends. When all they know is what they've encountered at work, they could be good at grinding out code but will not succeed as leaders. Do they have at least a high level understanding of trends (e.g. clouds, tdd, ddd, bdd, lean, scrum, esb, soa, etc.)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Ask about objectivity. &lt;/b&gt;Can the candidate separate personal from professional opinion? Do they make blanket statements? Do they contradict industry best practices by repeating arguments that were settled years ago? Are they open to other opinions?&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Determine rationality. &lt;/b&gt;Look for those who are willing to work with your standards but eager to debate. It is OK to engage in a friendly debate to see if they can do so without getting heated and angry.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Sell. &lt;/b&gt;Obviously you want to attract good people and the interview is a great place to get candidates excited. Be yourself to allow a natural bonding to occur. Be honest about the job and discuss what others in the role like and dislike. Realistically you both need to determine if you'll work well together.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7546437942865144565-4070149109443042757?l=ericbweimer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ericbweimer.blogspot.com/feeds/4070149109443042757/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ericbweimer.blogspot.com/2011/05/how-to-interview-developers.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/4070149109443042757'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/4070149109443042757'/><link rel='alternate' type='text/html' href='http://ericbweimer.blogspot.com/2011/05/how-to-interview-developers.html' title='How to Interview Developers'/><author><name>Eric Weimer</name><uri>http://www.blogger.com/profile/12419103951437664659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://3.bp.blogspot.com/-w1EAD8kSauk/Ttk-ifkupvI/AAAAAAAAARE/9Dbf5dwiXr4/s220/webpic.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7546437942865144565.post-4996374190969384591</id><published>2011-05-08T20:42:00.000-05:00</published><updated>2011-05-08T20:42:04.225-05:00</updated><title type='text'>Economies of Open Source</title><content type='html'>Perhaps the most unexpected success story of the last decade is the proliferation of open source software.&lt;br /&gt;&lt;br /&gt;When Richard Stallman began touting his ideas regarding free software (free as in free beer) many viewed this as idealistic. Of course Stallman had no issues about getting paid to write software. His assertion was that software represented information that should be shared. It was expected at this time that open source software would play at most a minor role in mainstream development.&lt;br /&gt;&lt;br /&gt;Historically software vendors vigorously guarded their source code to maintain competitive advantage. What we know today is availability of source code is an asset to developers, while competitors are only slightly hindered due to modern code dis-assemblers.. &lt;br /&gt;&lt;br /&gt;Linksys made history by opening their source code, which spawned a mini-industry of firmware upgrades that fueled sales of their hardware. Linksys effectively changed their revenue model from a hardware/firmware offering to a hardware solution with a basic operating system that users can easily upgrade, often for free.&lt;br /&gt;&lt;br /&gt;Vendors are exploring other revenue models that, for instance, combine open source software with enhancements (e.g. IBM Websphere) or offer support and consulting (e.g. SpringSource). &lt;br /&gt;&lt;br /&gt;Whether you like the idea of Open Source or not, odds are that just about any modern application makes use of some Open Source software. .NET developers are adopting open source tools like nHibernate and Spring.net. Look under the wraps at IBM's Websphere and you will find it is largely based on Open Source solutions.&lt;br /&gt;&lt;br /&gt;The reason is that in many domains, Open Source solutions now offer industry best solutions. This seems to be a contradiction to all things we learned about free market economics. How can free software compete with commercial solutions?&lt;br /&gt;&lt;br /&gt;The answer is quite simple: marketing. We take for granted that a vendor needs to peddle their wares. Competition results in better products for the consumer, however sales teams skew the picture to gain competitive advantage. &lt;br /&gt;&lt;br /&gt;In general Open Source solutions have no marketing, no sales teams, no slick presentations. The community vets these solutions, allowing &lt;b&gt;the best&lt;/b&gt; to bubble to the top. It is the &lt;i&gt;lack of marketeers&lt;/i&gt; that allow Open Source solutions to compete on merit alone, and that has resulted in today's plethora of high quality Open Source options.&lt;br /&gt;&lt;br /&gt;Perhaps the most common misunderstanding is about how Open Source solutions as funded. Certainly some are created out of passion, career enhancement or ego fulfillment. However Microsoft has performed so well that competitors now fund the Open Source community. In fact most large vendors have paid positions that contribute either part or full time to the community.&lt;br /&gt;&lt;br /&gt;It will be interesting to see what the future holds for the Open Source community. In the meantime, enjoy the riches available now, and contribute back to the community if you have the chance.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7546437942865144565-4996374190969384591?l=ericbweimer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ericbweimer.blogspot.com/feeds/4996374190969384591/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ericbweimer.blogspot.com/2011/05/economies-of-open-source.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/4996374190969384591'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/4996374190969384591'/><link rel='alternate' type='text/html' href='http://ericbweimer.blogspot.com/2011/05/economies-of-open-source.html' title='Economies of Open Source'/><author><name>Eric Weimer</name><uri>http://www.blogger.com/profile/12419103951437664659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://3.bp.blogspot.com/-w1EAD8kSauk/Ttk-ifkupvI/AAAAAAAAARE/9Dbf5dwiXr4/s220/webpic.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7546437942865144565.post-4606605198333702925</id><published>2010-07-03T15:14:00.002-05:00</published><updated>2010-07-03T15:18:52.231-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='Architecure'/><category scheme='http://www.blogger.com/atom/ns#' term='future state'/><category scheme='http://www.blogger.com/atom/ns#' term='IT Management'/><category scheme='http://www.blogger.com/atom/ns#' term='Business of IT'/><title type='text'>Architecture in the Enterprise</title><content type='html'>Recently I heard about a consulting company that sent a prospect to interview for an Enterprise Architect role. The interviewer, resume in hand, zeroed in on the lack of EA experience. Unfortunately the folks who set this up never identified this as an Enterprise Architect role. The prospect was a software architect, not an Enterprise Architect.&lt;br /&gt;&lt;br /&gt;Unfortunately some managers in recent years have appropriated the term 'architect' after running out of titles for the senior developers. Senior-senior developer? Master developer? Guru developer? I must admit, 'architect' sounds better.&lt;br /&gt;&lt;br /&gt;In reality architecture is a set of disciplines, each unique and specific. Beware of the unmodified term "architect", it has no meaning without context.&lt;br /&gt;&lt;br /&gt;In my experience, I have seen the following architecture roles:&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Enterprise Architect&lt;/b&gt;&lt;br /&gt;Enterprise architecture is performed at the strategic level. Typically EA's plan future-state architectures for the enterprise. They do no development at all and actual development experience is helpful but not necessary. EA's can provide competitive advantage over the long run. They can also bring an enterprise to it's knees. &lt;br /&gt;&lt;b&gt; &lt;/b&gt;&lt;br /&gt;&lt;b&gt;Technical (or Solution) Architect&lt;/b&gt;&lt;br /&gt;This is a project-level position that recommends the hardware best suited for an application or system of applications. Actual development experience is helpful but not necessary.&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Chief Architect&lt;/b&gt;&lt;br /&gt;In the mid-late 1990's architects were seen as overhead, but motivation existed for CIO's to have an architect. This would be a very senior person, essentially the only named architect in the enterprise. Nowadays Chief Architect is sometimes used to designate the top architect, or can be just a ceremonial title.&lt;br /&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;br /&gt;&lt;b&gt;Application Architect&lt;/b&gt;&lt;br /&gt;Works at the project level, typically overseeing all technical aspects of the project. This is the original "architect", responsible for frameworks and design, aka "software architecture". Typically promoted from Technical Lead, the best AA's have been know to improve developer productivity by 2 times or more.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Network, Security, Data, Infrastructure, etc. Architects&lt;/b&gt;&lt;br /&gt;These are technology-specific professionals who create enterprise standards, assist development teams and provide governance. They are responsible for their specific technical space, ensuring it meets project and enterprise requirements.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Summary&lt;/b&gt;&lt;br /&gt;Each architecture role aligns with Enterprise Architecture and strategic business initiatives. For example, years before the current services trend, good application architects would design to support services, since future state architectures were likely to move to a Services Orientated Architecture.&lt;br /&gt;&lt;br /&gt;Each architecture role is fairly specific with little overlap. They are specialists who help tame the complexity required of enterprise solutions through standards, governance and best practices. Some can play multiple roles with training and experience, but they are generally not interchangeable.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7546437942865144565-4606605198333702925?l=ericbweimer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ericbweimer.blogspot.com/feeds/4606605198333702925/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ericbweimer.blogspot.com/2010/07/architecture-in-enterprise.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/4606605198333702925'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/4606605198333702925'/><link rel='alternate' type='text/html' href='http://ericbweimer.blogspot.com/2010/07/architecture-in-enterprise.html' title='Architecture in the Enterprise'/><author><name>Eric Weimer</name><uri>http://www.blogger.com/profile/12419103951437664659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://3.bp.blogspot.com/-w1EAD8kSauk/Ttk-ifkupvI/AAAAAAAAARE/9Dbf5dwiXr4/s220/webpic.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7546437942865144565.post-4527858334958499625</id><published>2010-03-09T14:42:00.002-06:00</published><updated>2011-05-08T20:48:35.384-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Chicago Groovy User Group - March 2010</title><content type='html'>I am giving a talk on "recipes" at the March 9, 2010 Chicago Groovy User Group (www.cgug.org).&lt;br /&gt;&lt;br /&gt;The Powerpoint may be found &lt;a href="http://www.weimerweb.com/The%20Recipe%20Talk.pptx"&gt;here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7546437942865144565-4527858334958499625?l=ericbweimer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ericbweimer.blogspot.com/feeds/4527858334958499625/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ericbweimer.blogspot.com/2010/03/chicago-groovy-user-group-march-2010.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/4527858334958499625'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/4527858334958499625'/><link rel='alternate' type='text/html' href='http://ericbweimer.blogspot.com/2010/03/chicago-groovy-user-group-march-2010.html' title='Chicago Groovy User Group - March 2010'/><author><name>Eric Weimer</name><uri>http://www.blogger.com/profile/12419103951437664659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://3.bp.blogspot.com/-w1EAD8kSauk/Ttk-ifkupvI/AAAAAAAAARE/9Dbf5dwiXr4/s220/webpic.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7546437942865144565.post-7187430853301965772</id><published>2009-12-14T11:22:00.001-06:00</published><updated>2010-07-03T15:16:21.569-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='best practices'/><category scheme='http://www.blogger.com/atom/ns#' term='testing'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='JAMon'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Testing the Grails JAMon Plugin</title><content type='html'>Previously I wrote about creating a JAMon plugin for Grails. Today I'll add some tests.&lt;br /&gt;&lt;br /&gt;Since a plugin is a Grails application, you should add tests to your plugin project. Let's begin with opening a command window in the plugin project (jamon) and creating a test class:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;grails create-integration-test JamonGrailsPlugin&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Now we edit the class Grails created. We find this class in jamon\test\integration\JamonGrailsPluginTests.groovy.&lt;br /&gt;&lt;br /&gt;First we see Grails creates a class that extends GrailsUnitTestCase. Since this is an integration test, we'll change it to extend GroovyTestCase instead. Let's add a few handy imports as well:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;import grails.test.*&lt;br /&gt;&lt;br /&gt;import org.codehaus.groovy.grails.commons.ApplicationHolder&lt;br /&gt;import org.codehaus.groovy.grails.commons.GrailsApplication&lt;br /&gt;import javax.sql.DataSource&lt;br /&gt;&lt;br /&gt;class JamonGrailsPluginTests extends GroovyTestCase {&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;I'll add a couple variables for brevity sake:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;def app = ApplicationHolder.application&lt;br /&gt;def ctx = app.mainContext&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Next we'll add the boiler plate setUp and tearDown methods. I like &lt;a href="http://joe.truemesh.com/blog/archives/agile/000047.html"&gt;AgileDox &lt;/a&gt;naming so I'll override getName() as well:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;protected void setUp() {&lt;br /&gt;        super.setUp()&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    protected void tearDown() {&lt;br /&gt;        super.tearDown()&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public String getName() {&lt;br /&gt;        return super.getName().substring(4).replaceAll("([A-Z])", " \$1").toLowerCase();&lt;br /&gt;    }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;This first test will be to verify the dataSources have been updated with the jamon proxy:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;void testDataSourcesAreJamonEnabled() {&lt;br /&gt;        ctx.getBeanNamesForType(DataSource).each{ beanName -&amp;gt;&lt;br /&gt;            def bean = ctx.getBean( beanName )&lt;br /&gt;            assertEquals "com.jamonapi.proxy.JAMonDriver", bean.driverClassName&lt;br /&gt;            assert bean.url.startsWith("jdbc:jamon:")&lt;br /&gt;            assert bean.url.contains('jamonrealdriver=')&lt;br /&gt;        }&lt;br /&gt;    }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;We make use of the Spring method getBeanNamesForType() to get all beans subclassed from DataSource, then simply test the attributes we attempted to set.&lt;br /&gt;&lt;br /&gt;To verify that jamon is configured in the Spring context, we need a class in the plugin, such as a service class, to verify it is included in autoProxyCreatorBean. We can add a service by the grails command 'grails create-service jamonTest'. Of course we do not want the class added to our target applications, so we add the classname to the pluginExcludes variable in JamonGrailsPlugin:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;def pluginExcludes = [&lt;br /&gt;     "grails-app/views/error.gsp",&lt;br /&gt;     "grails-app/services/JamonTestService.groovy"&lt;br /&gt;   ]&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Now we can code out test:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;void testJamonHasSpringAop() {&lt;br /&gt;        assertNotNull ctx.getBean("jamonInterceptor")&lt;br /&gt;        def autoProxyCreatorBean = ctx.getBean("autoProxyCreator")&lt;br /&gt;        assertNotNull autoProxyCreatorBean&lt;br /&gt;        assertArrayEquals (["jamonTestService"].toArray(), autoProxyCreatorBean.beanNames.toArray()) &lt;br /&gt;    }&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;The remaining tests can be coded in a similar fashion. It is a good idea to include tests for all the plugin behaviours as well as any bugs that creep up over time.&lt;br /&gt;&lt;br /&gt;That is it for the JAMon series. Hope these articles saved you some time. Your comments are encouraged!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7546437942865144565-7187430853301965772?l=ericbweimer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ericbweimer.blogspot.com/feeds/7187430853301965772/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ericbweimer.blogspot.com/2009/12/testing-grails-jamon-plugin.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/7187430853301965772'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/7187430853301965772'/><link rel='alternate' type='text/html' href='http://ericbweimer.blogspot.com/2009/12/testing-grails-jamon-plugin.html' title='Testing the Grails JAMon Plugin'/><author><name>Eric Weimer</name><uri>http://www.blogger.com/profile/12419103951437664659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://3.bp.blogspot.com/-w1EAD8kSauk/Ttk-ifkupvI/AAAAAAAAARE/9Dbf5dwiXr4/s220/webpic.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7546437942865144565.post-1241520127148497236</id><published>2009-11-22T14:33:00.082-06:00</published><updated>2010-07-03T15:16:40.808-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='best practices'/><category scheme='http://www.blogger.com/atom/ns#' term='logging'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='Flex'/><category scheme='http://www.blogger.com/atom/ns#' term='JAMon'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>JAMon plugin for Grails: Part 4 of 4</title><content type='html'>In this series we completed steps 1-4 of our task list:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Add jamon.jar to the application classpath&lt;/li&gt;&lt;li&gt;Use JAMon's datasource proxy to monitor SQL&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Implement the JAMonServletFilter to monitor page hits&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Leverage Spring AOP via Spring's JamonPerformanceMonitorInterceptor class to monitor services&lt;/li&gt;&lt;li&gt;Add a Spring filter to monitor Grails controllers&lt;/li&gt;&lt;/ol&gt;Now lets complete step #5: Add a Spring filter to monitor Grails controllers. Spring filters are different than Servlet filters, although the details are beyond the scope of this article. Grails makes it easy to add Spring filters. Read the Grails documention for the details.&lt;br /&gt;&lt;br /&gt;Create a package structure under grails-app/conf. I used org/grails/plugins/filters. Create a file named JamonFilters and add the following code:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;package org.grails.plugins.filters&lt;br /&gt;&lt;br /&gt;import com.jamonapi.MonitorFactory&lt;br /&gt;import com.jamonapi.Monitor&lt;br /&gt;import org.codehaus.groovy.grails.commons.ConfigurationHolder&lt;br /&gt;/**&lt;br /&gt; * @author eric weimer&lt;br /&gt; */&lt;br /&gt; class JamonFilters {&lt;br /&gt;    &lt;br /&gt;    Monitor monitor, viewMonitor, previewMonitor&lt;br /&gt;    def skipControllers = (ConfigurationHolder.config.jamon.controllersToExclude)? ConfigurationHolder.config.jamon.controllersToExclude: []&lt;br /&gt;    def filters = {&lt;br /&gt;&lt;br /&gt;         monitorController(controller: "*", action: "*") {&lt;br /&gt;             before = {&lt;br /&gt;                 if (!(controllerName in skipControllers)) {&lt;br /&gt;                     def monName = "Controller.${controllerName}.${actionName}"&lt;br /&gt;                     monitor = MonitorFactory.start("${monName}")&lt;br /&gt;                     previewMonitor = MonitorFactory.start("${monName}.noview")&lt;br /&gt;                 }&lt;br /&gt;                 true&lt;br /&gt;             }&lt;br /&gt;             after = {&lt;br /&gt;                 if (previewMonitor) {&lt;br /&gt;                     previewMonitor.stop()&lt;br /&gt;                     def monName = "Controller.${controllerName}.${actionName}.view"&lt;br /&gt;                     viewMonitor = MonitorFactory.start("${monName}")&lt;br /&gt;                 }&lt;br /&gt;                 true&lt;br /&gt;              }&lt;br /&gt;             afterView = {&lt;br /&gt;                 if (monitor) monitor.stop()&lt;br /&gt;                 if (viewMonitor) viewMonitor.stop()&lt;br /&gt;                 true&lt;br /&gt;              }&lt;br /&gt;         }&lt;br /&gt;     }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;This code calls JAMon methods to start and stop timings. Note the variable &lt;i&gt;skipControllers&lt;/i&gt;. This allows users of the plugin to easily define a list of controllers NOT to monitor by adding the variable &lt;br /&gt;&lt;i&gt;jamon.controllersToExclude&lt;/i&gt; to groovy.config.&lt;br /&gt;&lt;br /&gt;This is all you need to do! Grails will add this filter to the application when you install the plugin. &lt;br /&gt;&lt;br /&gt;To allow users to provide additional customizations to the plugin, we document some configuration settings they can set, and then access those settings in our plugin. For example, in the application's Config.groovy class, let's allow users to specify the following:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;jamon.monitorControllers = true&lt;br /&gt;jamon.monitorServices = true&lt;br /&gt;jamon.servicesToExclude = ['consoleService']&lt;br /&gt;jamon.controllersToExclude = []&lt;br /&gt;jamon.additionalBeans = ['com.eweimer.terrapin.util.MediaAccess','com.eweimer.terrapin.util.Key']&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;These settings will allow users to turn off monitoring for Controllers or Services, and specify services NOT to monitor as well as additional Spring beans classes to include.&lt;br /&gt;&lt;br /&gt;To access these values in our JamonGrailsPlugin, we'll import:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;import org.codehaus.groovy.grails.commons.ConfigurationHolder&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;To perform a safe test on a boolean value we can use the following code to default to true when the user does not specify a value:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;def skipServices = application.config.jamon.servicesToExclude ?: []&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Put together, the code now looks like this:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;def monBeanNames = []&lt;br /&gt;def skipServices = application.config.jamon.servicesToExclude ?: []&lt;br /&gt;  &lt;br /&gt;if (application.config.jamon.monitorServices ?: true) {&lt;br /&gt;   monBeanNames = application.serviceClasses.collect{ it.shortName[0].toLowerCase() + it.shortName[1..-1] }&lt;br /&gt;   monBeanNames -= skipServices&lt;br /&gt;}&lt;br /&gt;if (application.config.jamon.additionalBeans) {&lt;br /&gt;   monBeanNames += application.config.jamon.additionalBeans&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;By using this logic we can allow users to easily customize the behavior of our jamon plugin.&lt;br /&gt;&lt;br /&gt;The final step is to deploy your plugin. Type "grails package-plugin" in the root of your plugin project and Grails will create a .zip file. Then go to your Grails application and type "grails install-plugin &lt;i&gt;path-to-your-zip-file&lt;/i&gt;", and you are ready to go.&lt;br /&gt;&lt;br /&gt;Deploy the jamon.war that comes with the JAMon distribution to your web server then point your browser to /jamon/menu.jsp to view the results. Viola!&lt;br /&gt;&lt;br /&gt;I hope you enjoyed this series. I'll add one more installment about testing your plugin when I have the chance. Meanwhile, have fun!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7546437942865144565-1241520127148497236?l=ericbweimer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='enclosure' type='' href='http://www.grails.org' length='0'/><link rel='replies' type='application/atom+xml' href='http://ericbweimer.blogspot.com/feeds/1241520127148497236/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ericbweimer.blogspot.com/2009/11/jamon-plugin-for-grails-part-4-of-4.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/1241520127148497236'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/1241520127148497236'/><link rel='alternate' type='text/html' href='http://ericbweimer.blogspot.com/2009/11/jamon-plugin-for-grails-part-4-of-4.html' title='JAMon plugin for Grails: Part 4 of 4'/><author><name>Eric Weimer</name><uri>http://www.blogger.com/profile/12419103951437664659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://3.bp.blogspot.com/-w1EAD8kSauk/Ttk-ifkupvI/AAAAAAAAARE/9Dbf5dwiXr4/s220/webpic.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7546437942865144565.post-8727713189145631711</id><published>2009-11-22T14:01:00.050-06:00</published><updated>2010-07-03T15:16:57.523-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='best practices'/><category scheme='http://www.blogger.com/atom/ns#' term='logging'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='Flex'/><category scheme='http://www.blogger.com/atom/ns#' term='JAMon'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>JAMon plugin for Grails: Part 3 of 4</title><content type='html'>In this series we completed steps 1-3 of:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Add jamon.jar to the application classpath&lt;/li&gt;&lt;li&gt;Use JAMon's datasource proxy to monitor SQL&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Implement the JAMonServletFilter to monitor page hits&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Leverage Spring AOP via Spring's JamonPerformanceMonitorInterceptor class to monitor services&lt;/li&gt;&lt;li&gt;Add a Spring filter to monitor Grails controllers.&lt;/li&gt;&lt;/ol&gt;Let's move on to step 4 : "Leverage Spring AOP via Spring's JamonPerformanceMonitorInterceptor class to monitor services."&lt;br /&gt;&lt;br /&gt;We'll add this to the doWithSpring closure. First we'll define a jamonInterceptor bean. It accepts a prefix attribute, which can be set to anything you like:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;def doWithSpring = {&lt;br /&gt;   jamonInterceptor( org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor, true, true ) {&lt;br /&gt;      prefix="Class."&lt;br /&gt;   }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;Next we need to get a list of beans to intercept. Service class beans are named by the class name with the first character set to lower case. Grails provides a list of service classes via the application object:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;def monBeanNames = application.serviceClasses.collect{ it.shortName[0].toLowerCase() + it.shortName[1..-1] }&lt;/pre&gt;&lt;/div&gt;Finally we use Springs BeanNameAutoProxyCreator to add the jamon interceptor to the service classes:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;if (monBeanNames) {&lt;br /&gt;   autoProxyCreator( org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator ) {&lt;br /&gt;      proxyTargetClass="true"&lt;br /&gt;      interceptorNames=["jamonInterceptor"]&lt;br /&gt;      beanNames=monBeanNames as String[]&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Put it all together, it looks like this:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;def doWithSpring = {&lt;br /&gt;   def monBeanNames = application.serviceClasses.collect{ it.shortName[0].toLowerCase() + it.shortName[1..-1] }&lt;br /&gt;&lt;br /&gt;   if (monBeanNames) {&lt;br /&gt;      jamonInterceptor(org.springframework.aop.interceptor.JamonPerformanceMonitorInterceptor, true, true) {&lt;br /&gt;      prefix="Class."&lt;br /&gt;      }&lt;br /&gt;&lt;br /&gt;      autoProxyCreator(org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator) { &lt;br /&gt;      proxyTargetClass="true"&lt;br /&gt;      interceptorNames=["jamonInterceptor"]&lt;br /&gt;      beanNames=monBeanNames as String[]&lt;br /&gt;   }&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;In part 4 of this series, we'll complete task #5 and deploy our JAMon plugin.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7546437942865144565-8727713189145631711?l=ericbweimer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ericbweimer.blogspot.com/feeds/8727713189145631711/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ericbweimer.blogspot.com/2009/11/jamon-plugin-for-grails-part-3-of-4.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/8727713189145631711'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/8727713189145631711'/><link rel='alternate' type='text/html' href='http://ericbweimer.blogspot.com/2009/11/jamon-plugin-for-grails-part-3-of-4.html' title='JAMon plugin for Grails: Part 3 of 4'/><author><name>Eric Weimer</name><uri>http://www.blogger.com/profile/12419103951437664659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://3.bp.blogspot.com/-w1EAD8kSauk/Ttk-ifkupvI/AAAAAAAAARE/9Dbf5dwiXr4/s220/webpic.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7546437942865144565.post-8713781696539277855</id><published>2009-11-22T13:45:00.004-06:00</published><updated>2010-07-03T15:17:13.725-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='best practices'/><category scheme='http://www.blogger.com/atom/ns#' term='logging'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='Flex'/><category scheme='http://www.blogger.com/atom/ns#' term='JAMon'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>JAMon plugin for Grails: Part 2 of 4</title><content type='html'>In part 1 we discussed four tasks needed to create a JAMon plugin. The first task was completed simply by adding jamon.jar to our plugin's lib folder. To review, the steps are:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Add jamon.jar to the application classpath&lt;/li&gt;&lt;li&gt;Use JAMon's datasource proxy to monitor SQL&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Implement the JAMonServletFilter to monitor page hits&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Leverage Spring AOP via Spring's JamonPerformanceMonitorInterceptor class to monitor services&lt;/li&gt;&lt;li&gt;Add a Spring filter to monitor Grails controllers.&lt;/li&gt;&lt;/ol&gt;As I mentioned previously, our plugin project has a file named: JamonGrailsPlugin.groovy. This is where we'll implement steps 2-5.&lt;br /&gt;&lt;br /&gt;JamonGrailsPlugin.groovy comes with a series of closures pre-defined. To change the datasource we add code to the doWithSpring closure. This closure allows you to update your Spring configuration.&lt;br /&gt;&lt;br /&gt;We need to change the driverClassName to "com.jamonapi.proxy.JAMonDriver" and alter the url by adding "jamon:" after "jdbc:" and appending a parameter named "jamonrealdriver".&lt;br /&gt;&lt;br /&gt;First lets add an import:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;import javax.sql.DataSource&lt;/pre&gt;&lt;/div&gt;Then code the closure:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;def doWithSpring = {&lt;br /&gt;   def config = application.config&lt;br /&gt;   def orgUrl = config.dataSource.url&lt;br /&gt;   def driverClassName = config.dataSource.driverClassName&lt;br /&gt;   &lt;br /&gt;   String appendUrl = (orgUrl.contains('?')? '&amp;amp;': '?') + 'jamonrealdriver=' + driverClassName&lt;br /&gt;   if (orgUrl.contains("oracle:")) appendUrl = 'jamonrealdriver=' + driverClassName&lt;br /&gt;   def url = orgUrl.replace("jdbc:","jdbc:jamon:") + appendUrl&lt;br /&gt;&lt;br /&gt;   config.dataSource.url = url&lt;br /&gt;   config.dataSource.driverClassName = "com.jamonapi.proxy.JAMonDriver"&lt;br /&gt;}&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;Step 3 is "implement the JAMonServletFilter to monitor page hits."&lt;br /&gt;&lt;br /&gt;The doWithWebDescriptor closure will allow us to add our filter to the application. We need to append to both the &amp;lt;filter&amp;gt; and &amp;lt;filter-mapping&amp;gt; sections. Note that this is typical Grails builder code. The 'filter-mapping' node needs to be in quotes due to the hyphen in it's name:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;def doWithWebDescriptor = { webXml -&amp;gt;&lt;br /&gt;   def filters = webXml.filter&lt;br /&gt;   filters + {&lt;br /&gt;      filter {&lt;br /&gt;         'filter-name'("jAMonServletFilter")&lt;br /&gt;         'filter-class'("com.jamonapi.http.JAMonServletFilter")&lt;br /&gt;      }&lt;br /&gt;   }&lt;br /&gt;&lt;br /&gt;   def filterMappings = webXml.'filter-mapping'&lt;br /&gt;      filterMappings + {&lt;br /&gt;         'filter-mapping' {&lt;br /&gt;            'filter-name'("jAMonServletFilter")&lt;br /&gt;            'url-pattern'("/*")&lt;br /&gt;          }&lt;br /&gt;      }&lt;br /&gt;   }&lt;/pre&gt;&lt;pre&gt;} &lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;In part 3 we'll move on to step #4.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7546437942865144565-8713781696539277855?l=ericbweimer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ericbweimer.blogspot.com/feeds/8713781696539277855/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ericbweimer.blogspot.com/2009/11/jamon-plugin-for-grails-part-2-of-4.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/8713781696539277855'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/8713781696539277855'/><link rel='alternate' type='text/html' href='http://ericbweimer.blogspot.com/2009/11/jamon-plugin-for-grails-part-2-of-4.html' title='JAMon plugin for Grails: Part 2 of 4'/><author><name>Eric Weimer</name><uri>http://www.blogger.com/profile/12419103951437664659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://3.bp.blogspot.com/-w1EAD8kSauk/Ttk-ifkupvI/AAAAAAAAARE/9Dbf5dwiXr4/s220/webpic.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7546437942865144565.post-3704441906968665331</id><published>2009-11-22T12:01:00.006-06:00</published><updated>2010-07-03T15:18:12.507-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='best practices'/><category scheme='http://www.blogger.com/atom/ns#' term='logging'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='Flex'/><category scheme='http://www.blogger.com/atom/ns#' term='JAMon'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Jamon plugin for Grails: Part 1 of 4</title><content type='html'>&lt;a href="http://jamonapi.sourceforge.net/"&gt;JAMon&lt;/a&gt; is a popular, flexible, lightweight open source Java performance monitor. I won't cover all the features here, but in short JAMon can monitor performance, memory, number of users, basically any quantity you can access in Java.&lt;br /&gt;&lt;br /&gt;To view the statistics JAMon provides a WAR file that you can deploy to your server along with your application. The war provides a set of JSP pages allowing you to view and export the data you are monitoring.&lt;br /&gt;&lt;br /&gt;Another option is to incorporate the WAR into your application. It requires a little more work but you can enhance it to your hearts content.&lt;br /&gt;&lt;br /&gt;Adding JAMon to Grails is really quite simple. What required some time was to experiment with the different methods JAMon can be inserted into your application. I prefer automation over hard-coded solutions.&lt;br /&gt;&lt;br /&gt;Here are the tasks needed to get JAMon set up with an initial set of monitors:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Add jamon.jar to the application classpath&lt;/li&gt;&lt;li&gt;Use JAMon's datasource proxy to monitor SQL&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Implement the JAMonServletFilter to monitor page hits&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Leverage Spring AOP via Spring's JamonPerformanceMonitorInterceptor class to monitor services&lt;/li&gt;&lt;li&gt;Add a Spring filter to monitor Grails controllers.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;Ideally it would be nice to separate this code in a way that JAMon could be applied to any Grails project. In fact, I found that to be the simplest approach! This solution just cries out for a Grails plugin.&lt;br /&gt;&lt;br /&gt;I won't go into all the details regarding plugins. Good references are available &lt;a href="http://grails.org/doc/latest/guide/12.%20Plug-ins.html"&gt;here&lt;/a&gt;, &lt;a href="http://www.ibm.com/developerworks/opensource/library/j-grails09159/index.html"&gt;here&lt;/a&gt; and &lt;a href="http://www.theserverside.com/news/thread.tss?thread_id=47680"&gt;here&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Fist download the &lt;a href="http://jamonapi.sourceforge.net/"&gt;JAMon&lt;/a&gt; distribution and unzip it.&lt;br /&gt;&lt;br /&gt;Assuming you have a target application, let's assume you'll be creating your plugin in the same workspace (i.e. directory). Open a command prompt in that folder and type:&lt;br /&gt;&lt;br /&gt;grails create-plugin jamon&lt;br /&gt;&lt;br /&gt;If you've never created a plugin before you'll notice that Grails creates a typical Grails application with one additional file in the top directory: JamonGrailsPlugin.groovy.&lt;br /&gt;&lt;br /&gt;This file is where we'll be doing most of the work.&lt;br /&gt;&lt;br /&gt;To complete task #1 (add jamon.jar to the classpath), simple copy jamon.jar to jamon/lib. When an application installs the plugin, Grails will add jamon.jar to the classpath. That's all you need to do!&lt;br /&gt;&lt;br /&gt;Next time I'll show how to implement the remaining tasks. Stay tuned.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7546437942865144565-3704441906968665331?l=ericbweimer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ericbweimer.blogspot.com/feeds/3704441906968665331/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ericbweimer.blogspot.com/2009/11/jamon-plugin-for-grails-part-1-of-4.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/3704441906968665331'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/3704441906968665331'/><link rel='alternate' type='text/html' href='http://ericbweimer.blogspot.com/2009/11/jamon-plugin-for-grails-part-1-of-4.html' title='Jamon plugin for Grails: Part 1 of 4'/><author><name>Eric Weimer</name><uri>http://www.blogger.com/profile/12419103951437664659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://3.bp.blogspot.com/-w1EAD8kSauk/Ttk-ifkupvI/AAAAAAAAARE/9Dbf5dwiXr4/s220/webpic.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7546437942865144565.post-7872323473702672422</id><published>2009-11-20T22:44:00.012-06:00</published><updated>2010-07-03T15:18:26.301-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='performance'/><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='best practices'/><category scheme='http://www.blogger.com/atom/ns#' term='logging'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='Flex'/><category scheme='http://www.blogger.com/atom/ns#' term='JAMon'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>JAMon</title><content type='html'>Years ago I discovered a little gem in the world of a free and open source software: &lt;a href="http://jamonapi.sourceforge.net/"&gt;JAMon&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Still in use today, JAMon's mind-numbingly simple API provides a wealth of value for minimal effort. JAMon has now spawned competing products, each with its unique pros and cons.&lt;br /&gt;&lt;br /&gt;JAMon is called a lightweight monitor. This may disappoint those who prefer large, feature-filled enterprise level commercial products, but the reality is JAMon delivers most of the data you need with &lt;span style="font-style: italic;"&gt;minimal impact on performance&lt;/span&gt;. I would never consider developing a Java application without JAMon or some other monitoring solution. (JAMon is available for other languages as well.)&lt;br /&gt;&lt;br /&gt;Best of all, you can have JAMon up and running in a few hours (or less)!&lt;br /&gt;&lt;br /&gt;JAMon excels at timing code execution. Without any code changes you can configure JAMon to monitor SQL, method calls (via Spring AOP),  as well as application entry and exit points.&lt;br /&gt;&lt;br /&gt;In addition to execution time, JAMon allows you to monitor ANY data that can be expressed numerically. Common usage includes the number of users by hour of the day (to find usage peaks), simultaneous users, memory, heap size, session size, # of active sessions, and so on.&lt;br /&gt;&lt;br /&gt;JAMon accumulates statistics rather than details which allows it to minimize its memory footprint. As it turns out, that is an excellent comprimise. JAMon keeps track of the number of invocations, min, max, average and standard deviation, as well as the min, max and average number of simultaneous executions, which is great for bottleneck analysis.&lt;br /&gt;&lt;br /&gt;Although criticized for its inability to save statistics to a persistent store, you can do so with a little work if needed. You can persist statistics to a database, log file, expose them via JMX, etc.&lt;br /&gt;&lt;br /&gt;You can configure JAMon start and stop monitoring dynamically. JAMon is typically measured at less than one percent overhead while turned on, and much less when turned off.&lt;br /&gt;&lt;br /&gt;So if you have no monitoring (or your monitoring solution cannot be run in production), try JAMon or one of it's competitors. Documentation is a bit on the light side but there are plenty of examples on the Web.&lt;br /&gt;&lt;br /&gt;And if you are a Grails developer, look for my posts about how to create a simple plugin to enable JAMon in your Grails applications.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7546437942865144565-7872323473702672422?l=ericbweimer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://jamonapi.sourceforge.net/' title='JAMon'/><link rel='replies' type='application/atom+xml' href='http://ericbweimer.blogspot.com/feeds/7872323473702672422/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ericbweimer.blogspot.com/2009/11/jamon.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/7872323473702672422'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/7872323473702672422'/><link rel='alternate' type='text/html' href='http://ericbweimer.blogspot.com/2009/11/jamon.html' title='JAMon'/><author><name>Eric Weimer</name><uri>http://www.blogger.com/profile/12419103951437664659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://3.bp.blogspot.com/-w1EAD8kSauk/Ttk-ifkupvI/AAAAAAAAARE/9Dbf5dwiXr4/s220/webpic.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7546437942865144565.post-2703231469235329820</id><published>2009-09-25T01:06:00.004-05:00</published><updated>2009-09-25T01:32:50.387-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='tweet'/><category scheme='http://www.blogger.com/atom/ns#' term='social'/><category scheme='http://www.blogger.com/atom/ns#' term='grails podcast'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Grails Tweets</title><content type='html'>Sven Haiges of &lt;a href="http://www.grailspodcast.com/"&gt;grails podcast&lt;/a&gt; fame has created a Groovy/Grails/Griffon tweet aggregator that allows users to "re-tweet" important tweets, providing a community-based, self-organizing tweet prioritizing tweeting community (Getting dizzy. I should tweet about that.)&lt;br /&gt;&lt;br /&gt;Check out &lt;a href="http://www.groovytweets.org/"&gt;http://www.groovytweets.org/&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Not satisfied with this, Sven created a nice "Headline Animator" that you can place on any html page to view the "important" tweets. This is one of three variations:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p style="margin-top: 10px; margin-bottom: 0pt; padding-bottom: 0pt; text-align: center; line-height: 0pt;"&gt;&lt;a target="_blank" href="http://feeds.feedburner.com/%7Er/importantgroovytweets/%7E6/3"&gt;&lt;img src="http://feeds.feedburner.com/importantgroovytweets.3.gif" alt="groovytweets ::: important tweets" style="border: 0pt none ;" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;p style="margin-top: 5px; padding-top: 0pt; font-size: x-small; text-align: center;"&gt;&lt;a href="http://feedburner.google.com/fb/a/headlineanimator/install?id=poj4rupefrgj6m7i2imh4c5gck&amp;amp;w=3" onclick="window.open(this.href, 'haHowto', 'width=520,height=600,toolbar=no,address=no,resizable=yes,scrollbars'); return false" target="_blank"&gt;↑ Grab this Headline Animator&lt;/a&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;Danke&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7546437942865144565-2703231469235329820?l=ericbweimer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ericbweimer.blogspot.com/feeds/2703231469235329820/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ericbweimer.blogspot.com/2009/09/grails-tweets.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/2703231469235329820'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/2703231469235329820'/><link rel='alternate' type='text/html' href='http://ericbweimer.blogspot.com/2009/09/grails-tweets.html' title='Grails Tweets'/><author><name>Eric Weimer</name><uri>http://www.blogger.com/profile/12419103951437664659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://3.bp.blogspot.com/-w1EAD8kSauk/Ttk-ifkupvI/AAAAAAAAARE/9Dbf5dwiXr4/s220/webpic.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7546437942865144565.post-3132508142423169102</id><published>2009-09-24T21:10:00.006-05:00</published><updated>2010-07-03T15:19:23.590-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='IT Management'/><category scheme='http://www.blogger.com/atom/ns#' term='Business of IT'/><title type='text'>The Business of IT - ROI and CBA</title><content type='html'>Two common tools businesses use to aid decision making are Return on Investment (ROI) and Cost Benefit Analysis (CBA). Use these tools to help sell your ideas to your management.&lt;br /&gt;&lt;br /&gt;ROI is used when "spending money to save money". The analysis is simple and the result is a period of time, often expressed in months.&lt;br /&gt;&lt;br /&gt;Simply start with the amount you spend, add up your savings over time, and see when they net out. That will be your ROI. Everything after the ROI is savings, so the analysis typically presents a few years into the future to highlight how much money you'll be ahead (and how clever you are).&lt;br /&gt;&lt;br /&gt;Depending on your management, a simple analysis may be close enough, or they may want a more thorough analysis that includes the time-value of money (i.e. the investment income you'll lose by spending it), tax ramifications and other costs expressed as "present value".&lt;br /&gt;&lt;br /&gt;In that case, delegate to that staffer who whines when they do not get promoted each and every review.&lt;br /&gt;&lt;br /&gt;Cost Benefit Analysis (CBA) is when you weigh expected costs versus expected benefits of one or more options to choose the best one. Both costs and benefits are expressed in money and may be a simple calculation or may include the time value of money expressed as "present value".&lt;br /&gt;&lt;br /&gt;With a CBA benefits need not be restricted to typical expense and revenue concerns such as staff reduction. CBA's can include myriad benefits such as market presence, public relations, recruiting, industry and financial analysts, community contributions, carbon footprint, green initiatives, etc. etc.&lt;br /&gt;&lt;br /&gt;Here it pays to include all realistic benefits.&lt;br /&gt;&lt;br /&gt;Any business analysis must be compelling to be useful, and must be clearly communicated to be compelling. Back up your analysis with industry accepted measures and you'll earn a reputation for "doing your homework" before presenting to management.&lt;br /&gt;&lt;br /&gt;Cheers&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7546437942865144565-3132508142423169102?l=ericbweimer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ericbweimer.blogspot.com/feeds/3132508142423169102/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ericbweimer.blogspot.com/2009/09/business-of-it-roi-and-cba.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/3132508142423169102'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/3132508142423169102'/><link rel='alternate' type='text/html' href='http://ericbweimer.blogspot.com/2009/09/business-of-it-roi-and-cba.html' title='The Business of IT - ROI and CBA'/><author><name>Eric Weimer</name><uri>http://www.blogger.com/profile/12419103951437664659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://3.bp.blogspot.com/-w1EAD8kSauk/Ttk-ifkupvI/AAAAAAAAARE/9Dbf5dwiXr4/s220/webpic.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7546437942865144565.post-130874678294237817</id><published>2009-05-04T00:31:00.009-05:00</published><updated>2010-07-03T15:19:47.014-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='best practices'/><category scheme='http://www.blogger.com/atom/ns#' term='logging'/><category scheme='http://www.blogger.com/atom/ns#' term='Drupal'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='Flex'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Grails Logging</title><content type='html'>I am in the middle of a Grails/Flex project. One of the criteria involved with the selection of Grails was the large number of blogs, articles and documentation available.&lt;br /&gt;&lt;br /&gt;The other criteria was, of course, improved productivity.&lt;br /&gt;&lt;br /&gt;We have an aggressive deadline of eight weeks. Our customer chose the Drupal CMS for the site, but we had concerns about it's suitability and scalability. We ended up using Drupal for it's strengths, like FAQ's, blogs, etc. We selected Grails for the bulk of data handling and Flex for the front end. (No one does "eye candy" as well as Flex. Perhaps JavaFX some day, but today it is Flex.)&lt;br /&gt;&lt;br /&gt;For the most part, Grails has grown so popular it has been easy finding solutions to common problems. However, one area lacking in advice is, oddly enough, basic logging.&lt;br /&gt;&lt;br /&gt;So here is our logging configuration. We use four appenders, the console and three rolling files. The console is designed to make watching the application as painless as possible. Besides the usual Grails output, it displays only error level logging.&lt;br /&gt;&lt;br /&gt;The three rolling file appendars contain error, debug and trace level logging respectively. The error log is great for quickly determining if any errors have occurred.&lt;br /&gt;&lt;br /&gt;The debug log is excellent for researching issues not made obvious by the error log. The trace log adds Hibernate data values to the queries if you really need that level of detail.&lt;br /&gt;&lt;br /&gt;So here it is, a working Grails 1.1 version logging configuration, straight from Config.groovy. As it turns out, the best source for learning about this is the documentation from the Grails web site.&lt;br /&gt;&lt;br /&gt;I hope you find this useful:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;log4j = {&lt;br /&gt;&lt;br /&gt;&amp;nbsp;appenders {&lt;br /&gt;&amp;nbsp;&amp;nbsp;console name:'console', threshold:Level.ERROR,layout:pattern(conversionPattern: '%p %d{ISO8601} %c{4} %m%n')&lt;br /&gt;&amp;nbsp;&amp;nbsp;rollingFile name:"rollingFileTrace", threshold:Level?TRACE, maxFileSize:1048576,&amp;nbsp;&amp;nbsp;file:logFile+'Trace?log', ayout:pattern(conversionPattern: '%p %d{ISO8601} %c{5} %m%n')&lt;br /&gt;&amp;nbsp;&amp;nbsp;rollingFile name:"rollingFileDebug", threshold:Level?DEBUG, axFileSize:1048576,file:logFile+'Debug.log', layout:pattern(conversionPattern: '%p %d{ISO8601} %c{5} %m%n')&lt;br /&gt;&amp;nbsp;&amp;nbsp;rollingFile name:"rollingFileError", threshold:Level.ERROR, axFileSize:1048576,file:logFile+'Error.log', layout:pattern(conversionPattern: '%p %d{ISO8601} %c{5} %m%n')&lt;br /&gt;&amp;nbsp;}&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;error console, rollingFileDebug, rollingFileError, rollingFileTrace:&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;'org.codehaus.groovy.grails.web.servlet',  //  controllers&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;'org.codehaus.groovy.grails.web.pages', //  GSP&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;'org.codehaus.groovy.grails.web.sitemesh', //  layouts&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;'org.codehaus.groovy.grails."web.mapping.filter', // URL mapping&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;'org.codehaus.groovy.grails."web.mapping', // URL mapping&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;'org.codehaus.groovy.grails.commons', // core / classloading&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;'org.codehaus.groovy.grails.plugins', // plugins&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;'org.codehaus.groovy.grails.orm.hibernate', // hibernate integration&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;'org.springframework'&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;debug rollingFileDebug, rollingFileTrace:'org.hibernate',&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;'com.britetab',&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;'BootStrap',&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;'org.apache.ddlutils'&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;trace rollingFileTrace:'org.hibernate.SQL',&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;'org.hibernate.type',&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;'flex.messaging.services'&lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;warn  console,rollingFileDebug,rollingFileTrace:'org.mortbay.log',&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;'org.hibernate.tool.hbm2ddl'&lt;br /&gt;&lt;br /&gt;&amp;nbsp;root {&lt;br /&gt;&amp;nbsp;&amp;nbsp;error 'console','rollingFileError','rollingFileDebug','rollingFileTrace'&lt;br /&gt;&amp;nbsp;&amp;nbsp;additivity = true&lt;br /&gt;&amp;nbsp;}&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7546437942865144565-130874678294237817?l=ericbweimer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://grails.org/' title='Grails Logging'/><link rel='replies' type='application/atom+xml' href='http://ericbweimer.blogspot.com/feeds/130874678294237817/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ericbweimer.blogspot.com/2009/06/grails-logging.html#comment-form' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/130874678294237817'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/130874678294237817'/><link rel='alternate' type='text/html' href='http://ericbweimer.blogspot.com/2009/06/grails-logging.html' title='Grails Logging'/><author><name>Eric Weimer</name><uri>http://www.blogger.com/profile/12419103951437664659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://3.bp.blogspot.com/-w1EAD8kSauk/Ttk-ifkupvI/AAAAAAAAARE/9Dbf5dwiXr4/s220/webpic.jpg'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7546437942865144565.post-4604302836139453611</id><published>2009-03-31T01:45:00.001-05:00</published><updated>2010-07-03T15:20:03.007-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='best practices'/><title type='text'>Problem Resolution</title><content type='html'>I observed a small team that included a very talented developer. They were asked to solve a very nasty production performance issue.&lt;br /&gt;&lt;br /&gt;The developer had a "gut feeling" for the problem and wanted to try his solution.&lt;br /&gt;&lt;br /&gt;This approach is akin to picking the &lt;span style="font-style: italic;"&gt;low hanging fruit.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;To solve this type of issue, it is often wise to attempt to pick the &lt;span style="font-style: italic;"&gt;low hanging fruit&lt;/span&gt; and hope for a quick resolution.&lt;br /&gt;&lt;br /&gt;However you must limit your fruit intake. After a few tries, you need to resort to proper analysis and isolate the problem.&lt;br /&gt;&lt;br /&gt;After his initial effort failed, he again had another "gut feeling" and wanted to try for another quick fix. This pattern repeated itself several more times, until he gave up and quietly moved on.&lt;br /&gt;&lt;br /&gt;Unfortunately the &lt;span style="font-style: italic;"&gt;low hanging fruit&lt;/span&gt; was too appealing, and management was easily sold by the quick solution. The proper analysis was never done. The issue was never resolved.&lt;br /&gt;&lt;br /&gt;Gut feelings often result in brilliant work. When they fail, there must be proper analysis. &lt;span style="font-style: italic;"&gt;&lt;/span&gt;The pragmatic programmer must set aside emotionally-driven behaviors and use a more prudent approach.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7546437942865144565-4604302836139453611?l=ericbweimer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ericbweimer.blogspot.com/feeds/4604302836139453611/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ericbweimer.blogspot.com/2009/03/problem-resolution.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/4604302836139453611'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/4604302836139453611'/><link rel='alternate' type='text/html' href='http://ericbweimer.blogspot.com/2009/03/problem-resolution.html' title='Problem Resolution'/><author><name>Eric Weimer</name><uri>http://www.blogger.com/profile/12419103951437664659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://3.bp.blogspot.com/-w1EAD8kSauk/Ttk-ifkupvI/AAAAAAAAARE/9Dbf5dwiXr4/s220/webpic.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7546437942865144565.post-8536748609921572349</id><published>2009-03-31T01:00:00.001-05:00</published><updated>2010-07-03T15:20:40.418-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='best practices'/><title type='text'>Managing Complexity</title><content type='html'>I was once confronted by a well meaning tech lead who predicted a performance issue and was  "enhancing" the design to circumvent the issue.&lt;br /&gt;&lt;br /&gt;After many years in this field I find it interesting that even very talented developers feel the need to fall prey to one of the oldest anti-patterns: &lt;span style="font-style: italic;"&gt;premature optimization&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;When I requested justification I discovered he had a "gut" feel this operation would take too long. No proof of concept had been done, no estimated timings, just the perception it would take "too long".&lt;br /&gt;&lt;br /&gt;For all I know he could be correct. But years of development have taught me to resist the urge and &lt;span style="font-style: italic;"&gt;keep it simple&lt;/span&gt;. Don't complicate designs until you know you have a real problem.&lt;br /&gt;&lt;br /&gt;My experience is that the vast majority of perceived performance issues never materialize. Assuming a well-designed architecture, simple designs perform well in the vast majority of cases.&lt;br /&gt;&lt;br /&gt;Keeping the design simple and focusing on performance enhancements when they become necessary allows developers to focus their efforts on real problems, rather than perceived issues.&lt;br /&gt;&lt;br /&gt;Don't design in complexity. Save it for when you really need it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7546437942865144565-8536748609921572349?l=ericbweimer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ericbweimer.blogspot.com/feeds/8536748609921572349/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ericbweimer.blogspot.com/2009/03/managing-complexity.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/8536748609921572349'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/8536748609921572349'/><link rel='alternate' type='text/html' href='http://ericbweimer.blogspot.com/2009/03/managing-complexity.html' title='Managing Complexity'/><author><name>Eric Weimer</name><uri>http://www.blogger.com/profile/12419103951437664659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://3.bp.blogspot.com/-w1EAD8kSauk/Ttk-ifkupvI/AAAAAAAAARE/9Dbf5dwiXr4/s220/webpic.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7546437942865144565.post-7551083002665099801</id><published>2009-03-09T20:38:00.001-05:00</published><updated>2010-07-03T15:20:55.109-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>Chicago Groovy User Group</title><content type='html'>Tomorrow I am presenting an intro to Groovy and Grails at the &lt;a href="http://www.cgug.org/"&gt;Chicago Groovy User Group&lt;/a&gt; monthly meeting.&lt;br /&gt;&lt;br /&gt;As usual I have a bad cold and am dead tired. However I'll give it my best effort since the organizers are all great guys and have put a lot of effort into getting this group off the ground.&lt;br /&gt;&lt;br /&gt;There will be free pizza and drinks. Best of all, raffle prizes!&lt;br /&gt;&lt;br /&gt;Slides of the talk are available in &lt;a href="http://www.weimerweb.com/Groovy_and_Grails_Intr_dist.pptx"&gt;pptx&lt;/a&gt; format as well as &lt;a href="http://www.weimerweb.com/Groovy_and_Grails_Intr_dist.pdf"&gt;pdf&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7546437942865144565-7551083002665099801?l=ericbweimer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='related' href='http://www.cgug.org' title='Chicago Groovy User Group'/><link rel='replies' type='application/atom+xml' href='http://ericbweimer.blogspot.com/feeds/7551083002665099801/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ericbweimer.blogspot.com/2009/03/chicago-groovy-user-group.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/7551083002665099801'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/7551083002665099801'/><link rel='alternate' type='text/html' href='http://ericbweimer.blogspot.com/2009/03/chicago-groovy-user-group.html' title='Chicago Groovy User Group'/><author><name>Eric Weimer</name><uri>http://www.blogger.com/profile/12419103951437664659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://3.bp.blogspot.com/-w1EAD8kSauk/Ttk-ifkupvI/AAAAAAAAARE/9Dbf5dwiXr4/s220/webpic.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7546437942865144565.post-7448920231624124881</id><published>2009-03-07T23:31:00.001-06:00</published><updated>2010-07-03T15:21:47.057-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><category scheme='http://www.blogger.com/atom/ns#' term='future state'/><title type='text'>Syntactic Sugar</title><content type='html'>&lt;span style="font-style: italic;"&gt;Syntactic sugar&lt;/span&gt; is a colorful expression that has been popping up in tech circles for the last few years. There is even a &lt;a href="http://en.wikipedia.org/wiki/Syntactic_sugar"&gt;Wikipedia page for it&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Java contains a bit of syntactic sugar. All objects in Java are created through calls to the object model except one: String. Strings can be created directly through Java syntax.&lt;br /&gt;&lt;br /&gt;In Java we can create a String through the object model by calling a constructor:&lt;br /&gt;&lt;br /&gt;String name = new String ("eduardo");&lt;br /&gt;&lt;br /&gt;Or we can use this bit of "syntactic sugar":&lt;br /&gt;&lt;br /&gt;String name = "eduardo";&lt;br /&gt;&lt;br /&gt;As you can see, syntactic sugar gives us two things: clarity and conciseness. It usually does not add any new functionality.&lt;br /&gt;&lt;br /&gt;Groovy expands on syntactic sugar. This allows Groovy code to be expressive and concise. Multiply that by the thousands of lines of code a developer reads and it adds up to real productivity. (Of course, the time saved usually gets blown on things like writing blogs, etc.)&lt;br /&gt;&lt;br /&gt;Take the following Groovy syntax:&lt;br /&gt;&lt;br /&gt;(0..9).times {...}&lt;br /&gt;&lt;br /&gt;Even if you've never seen Groovy syntax it is quite obvious this is iterating from o..9. This is arguably clearer than the Java alternative:&lt;br /&gt;&lt;br /&gt;for (int i = 0; i &amp;lt; 10; i++) { ... }  Groovy makes great use of Syntactic sugar, allowing developers to express their intentions in a more concise and clear manner then legacy Java.  Java simply cannot add many next generation features. Java is hampered by the need to be backwards compatible and it's lack of full object orientation. To remain competitive in the future we need to turn to a new language.  My money is on &lt;a href="http://groovy.codehaus.org/"&gt;Groovy&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7546437942865144565-7448920231624124881?l=ericbweimer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ericbweimer.blogspot.com/feeds/7448920231624124881/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ericbweimer.blogspot.com/2009/03/syntatic-sugar.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/7448920231624124881'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/7448920231624124881'/><link rel='alternate' type='text/html' href='http://ericbweimer.blogspot.com/2009/03/syntatic-sugar.html' title='Syntactic Sugar'/><author><name>Eric Weimer</name><uri>http://www.blogger.com/profile/12419103951437664659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://3.bp.blogspot.com/-w1EAD8kSauk/Ttk-ifkupvI/AAAAAAAAARE/9Dbf5dwiXr4/s220/webpic.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7546437942865144565.post-3221436394551912534</id><published>2009-02-22T17:08:00.001-06:00</published><updated>2010-07-03T15:21:23.310-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='grails'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><category scheme='http://www.blogger.com/atom/ns#' term='future state'/><title type='text'>What is Groovy?</title><content type='html'>What is &lt;a href="http://groovy.codehaus.org/"&gt;Groovy&lt;/a&gt;? Besides being music-inspired slang from the 1960's, Groovy is, in my view, the "next big thing" for the Java platform.&lt;br /&gt;&lt;br /&gt;Why, you may ask? Here are a few reasons:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Groovy is backward-compatible with Java, which translates to real business value.&lt;/li&gt;&lt;li&gt;Groovy is designed to allow developers to be more productive, which also adds real business value.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Groovy has become wildly popular in the recent past.Recent &lt;a href="http://today.java.net/pub/pq/143"&gt;polls&lt;/a&gt; I've seen place Groovy as the most desired language by developers. In the open source world this fact is highly predictive.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Ruby in the lead &lt;span style="font-style: italic;"&gt;if you go by job postings&lt;/span&gt;, and Ruby is an excellent language. However Java developers must learn an entirely new syntax. Groovy is based on Java syntax, making it an easier transition for legacy Java developers.&lt;/li&gt;&lt;li&gt;JRuby can run on the Java platform. However Groovy is built on top of Java and provides access to all the familiar Java api's. In fact Groovy enhances the Java object model, so in reality you are running not only on the Java platform, but you are running on Java standard classes.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Groovy implements all the popular language constructs from Ruby, Smalltalk, Python and others, making it an excellent choice for the enterprise.&lt;/li&gt;&lt;li&gt;New features that show up in Ruby or Groovy are quickly implemented in each other language.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Java is widely perceived to be near sunsetting. Any language can tolerate only so many enhancements until it acquires a reputation of feature bloat. &lt;/li&gt;&lt;li&gt;Groovy improves on Java. Syntactically, Groovy is clearer and more concise. And Groovy eliminates some of the the most common Java bugs.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Grails, a popular application framework for Groovy, leverages RoR's "convention over configuration" approach, which further reduces the code developers need to write.&lt;/li&gt;&lt;li&gt;During the last 12 months, downloads of Grails have grown from 7,000 to 70,000 per month.&lt;/li&gt;&lt;li&gt;Groovy is 100% object-orientated, leaving Java compromises in the past forever.&lt;/li&gt;&lt;li&gt;Groovy and Grails are production ready now, and are showing up in more and more web sites.&lt;/li&gt;&lt;/ol&gt;Whether you manage  or work in a Java shop, you should be watching Groovy's progress very carefully. Your competition may already be making the jump.&lt;br /&gt;&lt;br /&gt;At this point, Groovy and Grails look like excellent bets for future development.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7546437942865144565-3221436394551912534?l=ericbweimer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ericbweimer.blogspot.com/feeds/3221436394551912534/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ericbweimer.blogspot.com/2009/02/what-is-groovy.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/3221436394551912534'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/3221436394551912534'/><link rel='alternate' type='text/html' href='http://ericbweimer.blogspot.com/2009/02/what-is-groovy.html' title='What is Groovy?'/><author><name>Eric Weimer</name><uri>http://www.blogger.com/profile/12419103951437664659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://3.bp.blogspot.com/-w1EAD8kSauk/Ttk-ifkupvI/AAAAAAAAARE/9Dbf5dwiXr4/s220/webpic.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7546437942865144565.post-821865744207914984</id><published>2009-02-16T20:04:00.001-06:00</published><updated>2010-07-03T15:21:07.900-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='groovy'/><title type='text'>The problem with Java Primitives</title><content type='html'>&lt;span style="font-family: times new roman;"&gt;As a long time Java user I have developed a love for the language.&lt;br /&gt;&lt;br /&gt;At least until I found Groovy. Let me explain...&lt;/span&gt;  &lt;span style="font-family: times new roman;"&gt;&lt;br /&gt;&lt;br /&gt;Smalltalk enjoyed a surge of popularity in the early 1990's when the "deep thinkers" of the industry proclaimed OO as the &lt;/span&gt;&lt;span style="font-family: times new roman; font-style: italic;"&gt;next big thing.&lt;/span&gt;  &lt;span style="font-family: times new roman;"&gt;However Smalltalk got stuck with a reputation of being "too slow".&lt;br /&gt;&lt;br /&gt;When Java was designed in the mid 1990's it utilized primitives like int, char, float, etc. for performance.&lt;/span&gt;  &lt;span style="font-family: times new roman;"&gt;But if you think about it, here we have a mostly object-orientated language, where all comparison operators (&amp;gt;, &amp;lt;, ==, etc.) make sense with primitives, not objects!&lt;/span&gt;  &lt;span style="font-family: times new roman;"&gt;&lt;br /&gt;&lt;br /&gt;Groovy designers, on the other hand, realized compiler technology and modern hardware utilize objects with excellent performance. However that leads to a quandary: how do we include operators in a way that makes sense?&lt;/span&gt;  &lt;span style="font-family: times new roman;"&gt;&lt;br /&gt;&lt;br /&gt;The answer is operator overloading. But isn't operator overloading a bad thing? Didn't we learn that from C++?&lt;/span&gt;  &lt;span style="font-family: times new roman;"&gt;&lt;br /&gt;&lt;br /&gt;Well, operator overloading can certainly be abused, but it is a natural way to allow operators to work in a fully object-orientated language.&lt;/span&gt;  &lt;span style="font-family: times new roman;"&gt;&lt;br /&gt;&lt;br /&gt;Examine the following Groovy code:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: courier new;"&gt;public Boolean max(Integer i1, Integer i1) {&lt;br /&gt;(i1 &amp;gt; i2)? i1 : i2&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;&lt;span style="font-family: times new roman;"&gt;Even though i1 and i2 are objects of type Integer, this code works as expected. Why? Groovy overloads the '&amp;gt;' operator to call the compareTo() method. For integers, this works since Groovy has added the compareTo method to make Integers work as expected.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-family: times new roman;"&gt;You see this all over the Groovy language. Instead of having to memorize Java's idiosynchronicies, Groovy works in an intuitive manner. Much like the Unix's RLS (Rule of Least Surprise), Groovy does what you expect.&lt;br /&gt;&lt;br /&gt;Now take what is agruably the most common Java bug: comparing two String objects with '=='. Not only does it compile cleanly but it fails intermittenly, which is the hardest type of failure to cure. Yet it looks fine, passes code reviews, and makes it to production systems all too often. Even experienced Java developers miss it.&lt;br /&gt;&lt;br /&gt;In Groovy, it just works. Groovy calls equals() when you use the '==' syntax. So now we have a language that not only is backward compatible with Java, but fixes common Java bugs!&lt;br /&gt;&lt;br /&gt;All I can say is "Groovy".&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7546437942865144565-821865744207914984?l=ericbweimer.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://ericbweimer.blogspot.com/feeds/821865744207914984/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://ericbweimer.blogspot.com/2009/02/problem-with-java-primitives.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/821865744207914984'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7546437942865144565/posts/default/821865744207914984'/><link rel='alternate' type='text/html' href='http://ericbweimer.blogspot.com/2009/02/problem-with-java-primitives.html' title='The problem with Java Primitives'/><author><name>Eric Weimer</name><uri>http://www.blogger.com/profile/12419103951437664659</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='27' height='32' src='http://3.bp.blogspot.com/-w1EAD8kSauk/Ttk-ifkupvI/AAAAAAAAARE/9Dbf5dwiXr4/s220/webpic.jpg'/></author><thr:total>0</thr:total></entry></feed>
