<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><!-- generator="wordpress/2.0.1" --><rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0">

<channel>
	<title>SpencerUresk</title>
	<link>http://www.spenceruresk.com</link>
	<description>Random posts about Java, software development, politics, and economics</description>
	<pubDate>Mon, 09 Nov 2009 02:38:51 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.0.1</generator>
	<language>en</language>
			<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" href="http://feeds.feedburner.com/Spenceruresk" type="application/rss+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><item>
		<title>Infinity Ward/Activision get hit with DMCA notice on YouTube</title>
		<link>http://feedproxy.google.com/~r/Spenceruresk/~3/Hyy-jYMtgoQ/</link>
		<comments>http://www.spenceruresk.com/2009/11/08/infinity-wardactivision-get-hit-with-dmca-notice-on-youtube/#comments</comments>
		<pubDate>Mon, 09 Nov 2009 02:38:51 +0000</pubDate>
		<dc:creator>suresk</dc:creator>
		
	<category>Technology</category>
	<category>Funny</category>
	<category>Gaming</category>
		<guid isPermaLink="false">http://www.spenceruresk.com/2009/11/08/infinity-wardactivision-get-hit-with-dmca-notice-on-youtube/</guid>
		<description><![CDATA[Yesterday, I posted about Infinity Ward&#8217;s unpopular changes to multiplayer gameplay in Modern Warfare 2. I alluded to allegations by members of the modding community that IW had taken a lot of ideas from mod makers (such as the AC-130 kill streak reward and the tactical nuke) and haven&#8217;t even informally acknowledged the influence mods [...]]]></description>
			<content:encoded><![CDATA[<p>Yesterday, I <a href="http://www.spenceruresk.com/2009/11/07/infinity-ward-gives-pc-users-the-finger-a-sign-of-things-to-come/">posted</a> about Infinity Ward&#8217;s unpopular changes to multiplayer gameplay in Modern Warfare 2. I alluded to allegations by members of the modding community that IW had taken a lot of ideas from mod makers (such as the AC-130 kill streak reward and the tactical nuke) and haven&#8217;t even informally acknowledged the influence mods had on Modern Warfare 2. To make matters worse, they have removed the ability to use mods at all in Modern Warfare 2.</p>
<p>In a somewhat humorous development, Activision/IW have had one of their gameplay movies (of said AC-130 in action) on YouTube taken down due to a DMCA request, apparently filed by one of the more popular mod makers, PST Joker (Sam Babbitt).</p>
<p>As of this posting, their <a href="http://www.youtube.com/watch?v=ZBJcOy6iuUc">video</a> has been replaced with the notice: &#8220;This video is no longer available due to a copyright claim by Sam Babbitt. &#8220;.</p>
<p>I assume once Activion/Infinity Ward get their lawyers on the case, a counter notice will be quickly submitted and the video will be reinstated within the next day or so. Still, it is kind of funny to see a big company on the receiving end of the DMCA for once, and I&#8217;m glad to see people people standing up for PC gamers.
</p>
]]></content:encoded>
			<wfw:commentRSS>http://www.spenceruresk.com/2009/11/08/infinity-wardactivision-get-hit-with-dmca-notice-on-youtube/feed/</wfw:commentRSS>
		<feedburner:origLink>http://www.spenceruresk.com/2009/11/08/infinity-wardactivision-get-hit-with-dmca-notice-on-youtube/</feedburner:origLink></item>
		<item>
		<title>Infinity Ward gives PC users the finger - A sign of things to come?</title>
		<link>http://feedproxy.google.com/~r/Spenceruresk/~3/HlynXpkgLnU/</link>
		<comments>http://www.spenceruresk.com/2009/11/07/infinity-ward-gives-pc-users-the-finger-a-sign-of-things-to-come/#comments</comments>
		<pubDate>Sun, 08 Nov 2009 02:36:58 +0000</pubDate>
		<dc:creator>suresk</dc:creator>
		
	<category>Technology</category>
	<category>Software Development</category>
	<category>Gaming</category>
		<guid isPermaLink="false">http://www.spenceruresk.com/2009/11/07/infinity-ward-gives-pc-users-the-finger-a-sign-of-things-to-come/</guid>
		<description><![CDATA[I&#8217;ve been sick and recovering from surgery the last month or so, so I&#8217;ve been kind of out of the loop when it comes to gaming news. Yesterday, I found out about Infinity Ward&#8217;s decision to not support dedicated servers in Modern Warfare 2, and instead rely on their new peer-to-peer technology, IW.net. This is [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been sick and recovering from surgery the last month or so, so I&#8217;ve been kind of out of the loop when it comes to gaming news. Yesterday, I found out about Infinity Ward&#8217;s decision to not support dedicated servers in Modern Warfare 2, and instead rely on their new peer-to-peer technology, IW.net. This is horrible news, for a few reasons:</p>
<ol>
<li>Peer-to-peer supports fewer players. Indeed, the maximum game size has been disclosed as 9v9, which is significantly smaller than what you currently see on CoD 4 servers. Even worse, 9v9 is only available on a few game types - on others, the maximum is a paltry 6v6.</li>
<li>Peer-to-peer is almost guaranteed to offer worse performance than a dedicated server. Dedicated servers are run on dedicated hardware and are connected via business-class internet connections. Peer-to-peer relies on less stable hardware and an internet connection that is less stable, has less throughput, and is subject to QoS and other interference from ISPs.</li>
<li>It kills the community around the game. CoD4, like other games that rely on dedicated servers, has a large community of clans who host public servers. There you can hang out with people who share a similar play style and who you get along with. It is an enjoyable experience to play and hang out with regulars on a server.</li>
<li>Peer-to-peer lacks any kind of policing abilities. Many servers would kick/ban players who used racial slurs or excessive profanity. Players who griefed or caused problems were similarly kicked/banned.</li>
<li>Finally, there is the cheating/hacking angle. IW plans to rely 100% on VAC for this. The problem is that automated cheating/hacking prevention tools are sometimes behind the cheaters. This means there are often a handful of hacks in the wild that are not currently detected by them. On a dedicated server, the admins would be quick to ban someone for this and everyone could go on with the game - on IW.net, you just have to deal with it.</li>
</ul>
<p>To add insult to injury, the PC game also lacks the popular &#8216;lean&#8217; feature that was in the original Modern Warfare, lacks any modding tools (a particular slap in the face if you believe those <a href="http://bashandslash.com/index.php?option=com_content&#038;task=view&#038;id=772&#038;Itemid=111">claiming</a> that many of MW:2&#8217;s new features came directly from the modding community), and lacks a console for customizing certain aspects of the game.</p>
<p>The worst part is how this whole thing has been handled by Infinity Ward. In a <a href="http://forums.bestbuy.com/t5/Gaming/Call-of-Duty-Modern-Warfare-2-Live-Chat-Session-Transcript/td-p/67692">Best Buy Chat</a> with the developers, IW representatives repeatedly sidestepped questions about the dedicated server issues. Some notable (and often humorous) examples:</p>
<blockquote><p>
<strong>TRU-Jennifer:</strong> Are you considering dedicated servers for the PC gamer in the near future?</p>
<p><strong>Mackey-IW:</strong> Our main focus right now is on making sure the game will work well when it is released (on all platforms).</p></blockquote>
<p>Our secondary focus is avoiding having to answer questions about dedicated servers..</p>
<blockquote>
<p><strong>DudezTY:</strong> Since we can not kick people in ranked matches, how will we stop hackers who get past VAC?</p>
<p><strong>Mackey-IW:</strong> Our goal is to ban hackers from the game.
</p></blockquote>
<p>Well, that sounds like a nice goal! And until you manage to do so, I guess we just deal with them? Awesome.</p>
<blockquote><p>
<strong>krm2014:</strong> Will the IWNET multiplayer system compensate for the undoubtly low ping that the host computer will have for the other players, or will the host have an advantage over the other players? Also, going back to clans&#8230;Is there a way to have more than 18 people in a server, because my clan has at least 100 members and we like to get 20-30 on our servers at the same time.</p>
<p><strong>Mackey-IW:</strong> Games cap out at 9v9. The software has great latency tolerance. See above!
</p></blockquote>
<p>Performance is not going to be a problem! Just trust us, it&#8217;s great! (insert Baghdad Bob picture)</p>
<blockquote><p>
<strong>zach426: </strong>What was your guy&#8217;s logic behind removing the lean feature for PC, a feature that was a mainstay from all of your previous call of duty titles?</p>
<p><strong>Mackey-IW:</strong> The game is not balanced for lean.
</p></blockquote>
<p>Not balanced for lean? Wtf does that mean?</p>
<blockquote><p>
<strong>Torinir:</strong> How does IWNet plan to address serious griefing, such as intentional teamkilling, voice/chat spamming, and other unwanted behaviours in public matchmade games? This includes organized griefing from groups like myg0t.</p>
<p><strong>Mackey-IW:</strong> You can easily mute players, and hardcore (friendly fire enabled ) SD has &#8220;ricochet&#8221; which makes you hurt yourself instead.
</p></blockquote>
<p>Way to avoid answering most of the question.</p>
<blockquote><p>
<strong>Vince-IW:</strong> Multiplayer is incredible, you should not be worried!
</p></blockquote>
<p>Just trust us! It will be awesome! If not, oh well, at least you can return the game, right? Oh.</p>
<blockquote><p>
<strong>maniac1969:</strong> Vince, there are 178,000 voices that say you need dedicated servers for the PC. COD4 is the bigest online game in history! Why in the world would you take away dedicated servers and change the whole MP experience for us? And Mackey, the PC version with dedicated servers is already the best experience the way it is!</p>
<p><strong>Vince-IW: </strong>All I can say is that we changed it to make it a better and easier experience. Also, not all of the names on that list are legit. :smileywink:</p>
<p><strong>Mackey-IW:</strong> 402 signed it 4 times I heard.</p></blockquote>
<p>They try to cutely sidestep the issue of a large number of PC users being pissed off. Are some of the signatures on the petition fake? Undoubtedly. But a large number are, in fact, real. They need only step into their own <a href="http://www.infinityward.com/forum/viewforum.php?f=24">forums</a>, or the forums of popular clans to see how many people are unhappy about this.</p>
<blockquote><p>
<strong>Axen:</strong> Please explain how a 9v9 match is a multiplayer experience? I&#8217;d have more fun serving lunch at a local nursing home.</p>
<p><strong>Vince-IW:</strong> Sounds like are a very compassionate and giving person. I hope the people at the nursing home appreciate you.
</p></blockquote>
<p>Ok, that was kind of funny :)</p>
<blockquote><p>
<strong>Moriarte:</strong> Ignoring IW.net, is the PC version a direct port of the console version?</p>
<p><strong>Mackey-IW:</strong> No, PC has custom stuff like mouse control, text chat in game, and graphics settings.
</p></blockquote>
<p>Umm.. Isn&#8217;t that basically the definition of a port? Who the hell let these idiots represnt IW? This is the last quote I&#8217;ll use, because it brings me to another quote from <a href="http://www.fourzerotwo.com/?p=745">fourzerotwo</a>:</p>
<blockquote><p>
Call of Duty: Modern Warfare 2 is actually the biggest investment Infinity Ward has ever made into the PC version of our games. It’s also the most feature-rich PC version we’ve ever made.
</p></blockquote>
<p>Really? So the biggest investment you&#8217;ve made in a PC game so far is adding &#8220;&#8230; custom stuff like mouse control, text chat in game, and graphics settings.&#8221; These two statements, both made by people representing Infinity Ward, don&#8217;t make very much sense. One has to assume that fourzerotwo is referring solely to the addition of IW.net. If this is the case - that Infinity Ward invested a huge amount of money into a multiplayer setup that is actually a giant step backwards for PC gamers - then that is absolutely hilarious. It appears as though they&#8217;ve decided to approach the PC market in a similar way to the console market, which is a huge mistake.</p>
<p>This brings me to the greater concern I have - that this is the beginning of a new trend. Shitty P2P lagfest games, lots of DLC, and the destruction of communities around PC gaming. id Software <a href="http://kotaku.com/5398270/id-probably-no-dedicated-servers-for-rage">recently announced</a> that they are likely not going to support dedicated servers for their newest title, RAGE. If this becomes the new thing for PC gaming, many of the benefits of the platform are gone for good.
</p>
]]></content:encoded>
			<wfw:commentRSS>http://www.spenceruresk.com/2009/11/07/infinity-ward-gives-pc-users-the-finger-a-sign-of-things-to-come/feed/</wfw:commentRSS>
		<feedburner:origLink>http://www.spenceruresk.com/2009/11/07/infinity-ward-gives-pc-users-the-finger-a-sign-of-things-to-come/</feedburner:origLink></item>
		<item>
		<title>Why URL shortening services suck</title>
		<link>http://feedproxy.google.com/~r/Spenceruresk/~3/nrkdF0PcnZ8/</link>
		<comments>http://www.spenceruresk.com/2009/08/10/why-url-shortening-services-suck/#comments</comments>
		<pubDate>Tue, 11 Aug 2009 05:29:13 +0000</pubDate>
		<dc:creator>suresk</dc:creator>
		
	<category>Technology</category>
	<category>Enterprise Development</category>
	<category>Software Development</category>
	<category>Websites</category>
		<guid isPermaLink="false">http://www.spenceruresk.com/2009/08/10/why-url-shortening-services-suck/</guid>
		<description><![CDATA[The closing of tr.im has, for a day at least, shone a little bit of light on the URL shortening industry. It has also shed light on one of several problems with URL shortening - an idea with good intentions, but potentially bad results. 
When tr.im shuts down for good on December 31, 2009, any [...]]]></description>
			<content:encoded><![CDATA[<p>The closing of <a href="http://www.tr.im/">tr.im</a> has, for a day at least, shone a little bit of light on the URL shortening industry. It has also shed light on one of several problems with URL shortening - an idea with good intentions, but potentially bad results. </p>
<p>When tr.im shuts down for good on December 31, 2009, any links that were created using it will cease to work. Actually, that is the best-case scenario - the worst-case would be the domain falling into the hands of folks with malicious intent and old links suddenly becoming a trail to malware. One would hope that the people behind these URL shortening services have the foresight to register the domain for several years and allow it to just sit there dormant. However, if there are creditors involved, it won&#8217;t be that simple - a domain with thousands or millions of links pointing to it has a fair amount of economic value and would be sold off to help satisfy debts.</p>
<p>This is a scene that is likely to be replayed many times in the future - there are a plethora of URL shortening services, and no apparent ways to make money off the concept. This in itself could be another entire post, but let&#8217;s just leave it at &#8220;Hmm&#8230; Where have I seen this pattern before?&#8221;</p>
<p>This isn&#8217;t the only problem with URL shortening services - if it were, they wouldn&#8217;t be so bad. A lot of these services see the most use on Twitter, where the average link has a shelf life of about 38 seconds (I made that up), which mitigates the problems that occur when they die out to a degree. Lots of the links do hang around in other places, however, so we can&#8217;t ignore this problem, but let&#8217;s look at a few more:<br />
<strong><br />
1. They obscure what you are clicking on</strong></p>
<p>This is probably the worst problem. For any given hot Twitter topic, there may be hundreds of tweets flying by per minute - many of them containing links. It would be easy for someone to slip in a link to that says &#8220;Click here to see pics from the Iranian riots&#8221;, but is really a link to porn, a rickroll, or some malware. When you see the actual URL of the website, there is a small amount of security in being able to see where you are heading. By every link looking exactly the same (ie, bit.ly/ followed by a few random characters), this first line of defense is circumvented completely.<br />
<strong><br />
2. They are an extra link in the chain</strong></p>
<p>There are no shortage of things that can go wrong and make your website inaccessible to end-users. Power outages, network outages, hardware problems, DNS issues - just to name a few. Adding a URL shortening service into the mix is just one more link in the chain where a user can be frustrated by a website that doesn&#8217;t load.<br />
<strong><br />
An important lesson for webmasters and web framework developers</strong></p>
<p>If anything, the fact that an entire industry has sprung up around shortening URLs so they aren&#8217;t impossible to even copy &#038; paste effectively should serve as giant clue to web developers everywhere - your URLs are too damn long. We should be mindful of this when designing websites, web frameworks, and web applications (ie, CMS apps). A lot of new frameworks already are - Rails, Grails, an Lift all spring to mind as having nice facilities for making reasonably short URLs.</p>
<p>Some websites have necessarily long URLs because that is how they maintain state - this is unavoidable in some cases, but you can still provide a nice button or something in a prominent location on every page that has a shorter version of the link for people to use.</p>
<p>Small measures like these can help alleviate the need for URL shortening services and the problems that accompany them.
</p>
]]></content:encoded>
			<wfw:commentRSS>http://www.spenceruresk.com/2009/08/10/why-url-shortening-services-suck/feed/</wfw:commentRSS>
		<feedburner:origLink>http://www.spenceruresk.com/2009/08/10/why-url-shortening-services-suck/</feedburner:origLink></item>
		<item>
		<title>Using run mode and properties in Lift</title>
		<link>http://feedproxy.google.com/~r/Spenceruresk/~3/IIjezaVy_AI/</link>
		<comments>http://www.spenceruresk.com/2009/07/14/using-run-mode-and-properties-in-lift/#comments</comments>
		<pubDate>Tue, 14 Jul 2009 20:38:03 +0000</pubDate>
		<dc:creator>suresk</dc:creator>
		
	<category>Scala</category>
	<category>Lift</category>
		<guid isPermaLink="false">http://www.spenceruresk.com/2009/07/14/using-run-mode-and-properties-in-lift/</guid>
		<description><![CDATA[I&#8217;ve been using Lift and Scala for a few weeks now to build my scala job site. I&#8217;ve been incrementally adding features ever since I first opened the site a week ago. Two of those features I added today involved utilizing the runtime environment support in Lift, so I thought I&#8217;d write up a quick [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been using Lift and Scala for a few weeks now to build my <a href="http://www.scalacareers.com/">scala job site</a>. I&#8217;ve been incrementally adding features ever since I first opened the site a week ago. Two of those features I added today involved utilizing the runtime environment support in Lift, so I thought I&#8217;d write up a quick tutorial on how you can use it. Making your web application behave differently based on whether it is in development or production is incredibly important, and fortunately Lift makes it easy.</p>
<p>The first thing I had to add was a Google AdSense ad box. My designer left room for ads on the website, but I didn&#8217;t initially implement them and instead just mapped them to a snippet that returned a comment. Now I&#8217;d like to put the ads on the page so I can start earning my internet millions. However, I don&#8217;t want them to show in development mode because they will throw off my stats and because Google and/or the advertisers don&#8217;t appreciate me racking up thousands of ad impressions while developing my own site. Let&#8217;s see how we do this:</p>
<div class="codesnip-container" >
<div class="codesnip">def ad<span class="br0">&#40;</span>in: NodeSeq<span class="br0">&#41;</span> : NodeSeq = net.<span class="me1">liftweb</span>.<span class="me1">util</span>.<span class="me1">Props</span>.<span class="me1">productionMode</span> match <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; <span class="kw1">case</span> <span class="kw2">true</span> =&gt; &lt;real adsense code goes here /&gt;<br />
&nbsp; &nbsp; &nbsp; <span class="kw1">case</span> <span class="kw2">false</span> =&gt; &lt;!&#8211;Google Ad Goes Here&#8211;&gt;<br />
<span class="br0">&#125;</span></div>
</div>
<p>This calls the funcion <em>productionMode </em> on the Props class that is part of Lift. This tells us whether we are in production or not - if true, it will show an ad, otherwise it just sticks a comment in the HTML. But, how does Lift know if we are in production or not? Good question. When you run the application you can tell it what environment you are in by setting the <em>run.mode</em> property. If you run Lift with mvn jetty:run, it will assume you are in the default (development) environment. If you run Lift with mvn jetty:run -Drun.mode=production, it will assume you are in production. On my production Tomcat server that this app runs on, I just added a startup property to set the run mode to production.</p>
<p>Now let&#8217;s move to something a little more complicated. Whenever a new job is posted, I want to update the Twitter status for my site (<a href="http://www.twitter.com/scalacareers">@scalacareers</a>) so that everyone following it will know that there is a new job to check out. In development mode, I don&#8217;t want to post to the same Twitter account, though, as that would really confuse and frustrate my followers! I created another account (scalacareersdev) that my app will use in development, but how do I make sure the app is using the proper account? Here is where the property support comes to the rescue. Lift will load property files based on my environment - it will look in /default.props for the default (development) mode, and in production.default.props for production. So I create both of these files, and in default.props I put:</p>
<div class="codesnip-container" >
<div class="codesnip">twitter.<span class="me1">account</span>=scalacareersdev<br />
twitter.<span class="me1">password</span>=devpassword</div>
</div>
<p>in production.default.props, I use:</p>
<div class="codesnip-container" >
<div class="codesnip">twitter.<span class="me1">account</span>=scalacareers<br />
twitter.<span class="me1">password</span>=realpassword</div>
</div>
<p>Now, how do we use these? I have a twitter actor that updates the status:</p>
<div class="codesnip-container" >
<div class="codesnip">val session = <span class="kw2">new</span> AuthenticatedSession<span class="br0">&#40;</span><span class="st0">&#8220;scalacareers&#8221;</span>, <span class="st0">&#8220;realpassword&#8221;</span><span class="br0">&#41;</span><br />
session.<span class="me1">updateStatus</span><span class="br0">&#40;</span><span class="st0">&#8220;New Scala job posted - &#8220;</span> + job.<span class="me1">jobTitle</span> + <span class="st0">&#8221; - more info at: &#8220;</span> + job.<span class="me1">buildUrl</span><span class="br0">&#41;</span></div>
</div>
<p>I just need to refactor it to not have a hardcoded username/password, and instead get the values from the Props class:</p>
<div class="codesnip-container" >
<div class="codesnip">val account = Props.<span class="me1">get</span><span class="br0">&#40;</span><span class="st0">&#8220;twitter.account&#8221;</span><span class="br0">&#41;</span>.<span class="me1">open_</span>!<br />
val password = Props.<span class="me1">get</span><span class="br0">&#40;</span><span class="st0">&#8220;twitter.password&#8221;</span><span class="br0">&#41;</span>.<span class="me1">open_</span>!</div>
</div>
<p>This will look up the properties correctly for the environment, and I will be posting to the proper Twitter account. Note that by using open_!, my app will fail if the properties aren&#8217;t there, which is probably sensible in this case.</p>
<p>As you can see, the property support in Lift is quite easy to use and is incredibly useful when you have functionality that needs to change based on the environment.
</p>
]]></content:encoded>
			<wfw:commentRSS>http://www.spenceruresk.com/2009/07/14/using-run-mode-and-properties-in-lift/feed/</wfw:commentRSS>
		<feedburner:origLink>http://www.spenceruresk.com/2009/07/14/using-run-mode-and-properties-in-lift/</feedburner:origLink></item>
		<item>
		<title>Scala Job site + My experiences with Lift</title>
		<link>http://feedproxy.google.com/~r/Spenceruresk/~3/vL1T5jVV9yo/</link>
		<comments>http://www.spenceruresk.com/2009/07/06/scala-job-site-my-experiences-with-lift/#comments</comments>
		<pubDate>Tue, 07 Jul 2009 04:16:26 +0000</pubDate>
		<dc:creator>suresk</dc:creator>
		
	<category>Technology</category>
	<category>Enterprise Development</category>
	<category>Websites</category>
	<category>Scala</category>
	<category>Lift</category>
		<guid isPermaLink="false">http://www.spenceruresk.com/2009/07/06/scala-job-site-my-experiences-with-lift/</guid>
		<description><![CDATA[I&#8217;ve played around with Scala off and on for over a year now, and also looked at Lift once or twice during that time. After going to David Pollak&#8217;s session at JavaOne about Lift, I decided to buckle down and actually create something with Scala and Lift, as I usually learn new things best by [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve played around with <a href="http://www.scala-lang.org">Scala</a> off and on for over a year now, and also looked at <a href="http://www.liftweb.net/">Lift</a> once or twice during that time. After going to David Pollak&#8217;s session at JavaOne about Lift, I decided to buckle down and actually create something with Scala and Lift, as I usually learn new things best by trying to create something useful. Looking around, I noticed there weren&#8217;t any Scala-specific job sites and thought it might be nice to create one.</p>
<p>The site is here: <a href="http://www.scalacareers.com/">ScalaCareers.com</a>, and you can follow on Twitter for announcements of new jobs posted and other things <a href="http://www.twitter.com/scalacareers">@scalacareers</a></p>
<p>In my opinion, jobs for a new language are extremely important in helping it get to the next level of adoption. Scala is already pretty popular and Lift is gaining in popularity, so I hope we start to see a lot more jobs that involve Scala and Lift.</p>
<p>I&#8217;m going to be posting some short tutorials and other things related to my experience in the coming weeks, but I thought I would share a few quick, high-level thoughts.</p>
<p>1) Lift is a solid, production-ready framework. I was able to learn enough of it to build a functional, albeit small, web application over the 4th of July weekend. Despite using a snapshot of the 1.1 release, I didn&#8217;t run into any bugs or severely out-of-date documentation.  I mention this because it has been a slight problem when I&#8217;ve been an early adopter of frameworks in the past.</p>
<p>2) The Lift community is incredibly friendly and helpful. Going back through several months of activity on the Google Group, they are generally accepting of criticism, quick to offer help, and even commit changes to the trunk quickly to help folks out. A good community is very important to newcomers to a new language or framework.</p>
<p>3) Using Lift requires a good knowledge of Scala to really be effective. Don&#8217;t get me wrong - learning Scala is well worth the effort - but it was a bit of a change for me, coming from Grails where I was able to sort of ease into it.</p>
<p>4) IDE support for Scala is still a little disappointing. Even though I love Groovy, I generally prefer static typed languages to dynamic typed ones, which is why I was interested in Scala in the first place. One of the big benefits of static typed languages is that you can theoretically get better IDE support. I shelled out a few hundred bucks for IntelliJ for this purpose, and while it was marginally better than the others, I still found lots of cases where auto-complete simply didn&#8217;t work and plenty more cases where it didn&#8217;t catch compile errors. It probably cost me a few hours on the project. A good IDE doesn&#8217;t make you a better developer, but it does make you faster :)</p>
<p>Overall, I think Scala and Lift have bright futures and are worth checking out.
</p>
]]></content:encoded>
			<wfw:commentRSS>http://www.spenceruresk.com/2009/07/06/scala-job-site-my-experiences-with-lift/feed/</wfw:commentRSS>
		<feedburner:origLink>http://www.spenceruresk.com/2009/07/06/scala-job-site-my-experiences-with-lift/</feedburner:origLink></item>
		<item>
		<title>Bad API examples: java.util.Calendar</title>
		<link>http://feedproxy.google.com/~r/Spenceruresk/~3/Mdf3hyui5nk/</link>
		<comments>http://www.spenceruresk.com/2008/08/16/bad-api-examples-javautilcalendar/#comments</comments>
		<pubDate>Sat, 16 Aug 2008 22:28:33 +0000</pubDate>
		<dc:creator>suresk</dc:creator>
		
	<category>Uncategorized</category>
	<category>Software Development</category>
	<category>Java</category>
		<guid isPermaLink="false">http://www.spenceruresk.com/2008/08/16/bad-api-examples-javautilcalendar/</guid>
		<description><![CDATA[Take a look at the following code, and try to guess what is printed:

public static void main&#40;String&#91;&#93; args&#41; &#123;
&#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; Date today = new Date&#40;&#41;;
&#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; 
&#160; &#160; &#160; &#160; &#160; &#160; &#160; &#160; Calendar c = new GregorianCalendar&#40;&#41;;
&#160; &#160; &#160; &#160; &#160; [...]]]></description>
			<content:encoded><![CDATA[<p>Take a look at the following code, and try to guess what is printed:</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="kw2">public</span> <span class="kw4">static</span> <span class="kw4">void</span> main<span class="br0">&#40;</span><a href="http://www.google.com/search?q=allinurl%3AString+java.sun.com&#038;bntl=1"><span class="kw3">String</span></a><span class="br0">&#91;</span><span class="br0">&#93;</span> args<span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.google.com/search?q=allinurl%3ADate+java.sun.com&#038;bntl=1"><span class="kw3">Date</span></a> today = <span class="kw2">new</span> <a href="http://www.google.com/search?q=allinurl%3ADate+java.sun.com&#038;bntl=1"><span class="kw3">Date</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.google.com/search?q=allinurl%3ACalendar+java.sun.com&#038;bntl=1"><span class="kw3">Calendar</span></a> c = <span class="kw2">new</span> <a href="http://www.google.com/search?q=allinurl%3AGregorianCalendar+java.sun.com&#038;bntl=1"><span class="kw3">GregorianCalendar</span></a><span class="br0">&#40;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; c.<span class="me1">add</span><span class="br0">&#40;</span><a href="http://www.google.com/search?q=allinurl%3ACalendar+java.sun.com&#038;bntl=1"><span class="kw3">Calendar</span></a>.<span class="me1">DAY_OF_YEAR</span>, <span class="nu0">10</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.google.com/search?q=allinurl%3ASystem+java.sun.com&#038;bntl=1"><span class="kw3">System</span></a>.<span class="me1">out</span>.<span class="me1">println</span><span class="br0">&#40;</span>c.<span class="me1">after</span><span class="br0">&#40;</span>today<span class="br0">&#41;</span><span class="br0">&#41;</span>;<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</div>
<p>What is printed?</p>
<p>1. true<br />
2. false<br />
3. It doesn&#8217;t compile<br />
4. Runtime error</p>
<p>From a logical perspective, #1 is right - 10 days from now is after now, so you&#8217;d expect to see &#8216;true&#8217; printed. From a language perspective, you may think &#8220;you are passing in a java.util.Date to a function on java.util.Calendar, so it wouldn&#8217;t compile&#8221;, and choose #3. Neither of these are correct - the block of code above completes normally and prints &#8216;false&#8217;, which is not what we wanted.</p>
<p>If you take a look at the javadocs for <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/util/Calendar.html#after(java.lang.Object)">java.util.Calendar</a>, it is easy to see why. The signature for after (and before) is <em>public boolean after(Object when)</em>, but if you pass anything but a java.util.Calendar in, it will *always* return false. This is an unfortunate api design problem - it is reasonable to expect that you could pass in a java.util.Date, or even a long representing a timestamp to compare to the Calendar instance and it would work normally. The fact that either of those options compiles and runs without error can cover up the flaw in your code, and be difficult to track down (which is how I came across it and decided to write this post).</p>
<p>I am stumped trying to come up for a good reason for the method to accept Object (which means anything can be passed in - even primitives from Java 5 on) only to return false if it is anything other than java.util.Calendar. The method signature should be <em>public boolean after(java.util.Calendar when)</em>, so that you get a compile error instead of a silent failure at runtime. </p>
<p>Now, this library has been around since JDK 1.1, so I&#8217;m not exposing a new design flaw or anything. I am, however, curious as to how something so clearly anti-idiomatic Java (and anti-static typing) made it into a core Java library. Anyone have any ideas? The Date/Time APIs in Java are generally pretty bad anyway, but this seems especially poorly done.</p>
<p>I mostly write business code, and not much in the way of API code, but I have been reading the 2nd edition of Josh Bloch&#8217;s <a href="http://www.amazon.com/gp/redirect.html?ie=UTF8&#038;location=http%3A%2F%2Fwww.amazon.com%2FEffective-Java-2nd-Joshua-Bloch%2Fdp%2F0321356683%3Fie%3DUTF8%26s%3Dbooks%26qid%3D1218919613%26sr%3D8-1&#038;tag=uresknetworks&#038;linkCode=ur2&#038;camp=1789&#038;creative=9325">Effective Java</a> and it has given me a better appreciation for the thought and effort that goes into creating useful APIs. It is always interesting to see some of the really good *and* really bad examples of API design in the core Java libraries.
</p>
]]></content:encoded>
			<wfw:commentRSS>http://www.spenceruresk.com/2008/08/16/bad-api-examples-javautilcalendar/feed/</wfw:commentRSS>
		<feedburner:origLink>http://www.spenceruresk.com/2008/08/16/bad-api-examples-javautilcalendar/</feedburner:origLink></item>
		<item>
		<title>Quickly Redeploying Grails Apps</title>
		<link>http://feedproxy.google.com/~r/Spenceruresk/~3/M0GOTnqQ1C8/</link>
		<comments>http://www.spenceruresk.com/2008/07/02/quickly-redeploying-grails-apps/#comments</comments>
		<pubDate>Wed, 02 Jul 2008 06:30:53 +0000</pubDate>
		<dc:creator>suresk</dc:creator>
		
	<category>Software Development</category>
	<category>Websites</category>
	<category>Groovy</category>
	<category>Grails</category>
		<guid isPermaLink="false">http://www.spenceruresk.com/2008/07/02/quickly-redeploying-grails-apps/</guid>
		<description><![CDATA[I&#8217;ve been developing a bunch of small Grails apps lately, and I end up deploying them to my production box fairly frequently. This is kind of annoying because the upload speed on my home internet connection is terrible - it sometimes takes 7 or 8 minutes to upload a new WAR and during that time, [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been developing a bunch of small Grails apps lately, and I end up deploying them to my production box fairly frequently. This is kind of annoying because the upload speed on my home internet connection is terrible - it sometimes takes 7 or 8 minutes to upload a new WAR and during that time, my internet connection is unusable for anything else. I wanted a simple way to push new code to production without uploading a new WAR every time, and I know a few other people were looking for something similar, so here it is. It is pretty boring but it does the job. In my case, I deploy all of mine as ROOT.war, because they are always the default app for their domain. If yours is setup different, just replace ROOT.war with whatever your war should be named.</p>
<p>1. Check your code into Subversion (or CVS or whatever SCM of your choice - this guide assumes Subversion, however).</p>
<p>2. Add a build directory on your prod box (I have mine at /home/build/) - then check out individual projects under it (ie, /home/build/wiifit/).</p>
<p>3. In each project, add a property to application.properties for the deployment directory (ie - deploy.dir=/home/tc6/server/wiifit).</p>
<p>4. In grails, you can add groovy scripts to the /scripts/ directory, and then run them with grails <script-name>, ie, ProdPush.groovy can be called with &#8216;grails prod-push&#8217;. Let&#8217;s add a script in to do the following things:</p>
<p>- Do a subversion checkout to get our latest changes.<br />
- Build the war<br />
- Copy it to our directory</p>
<p>This is what I came up with:</p>
<div class="codesnip-container" >
<div class="codesnip">grailsHome = Ant.<span class="me1">project</span>.<span class="me1">properties</span>.<span class="st0">&#8220;environment.GRAILS_HOME&#8221;</span></p>
<p>includeTargets &lt;&lt; <span class="kw2">new</span> <a href="http://www.google.com/search?q=allinurl%3AFile+java.sun.com&#038;bntl=1"><span class="kw3">File</span></a> <span class="br0">&#40;</span> <span class="st0">&#8220;${grailsHome}/scripts/War.groovy&#8221;</span><span class="br0">&#41;</span></p>
<p>target<span class="br0">&#40;</span><span class="st0">&#8216;default&#8217;</span>: <span class="st0">&#8220;Push a war to prod&#8221;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;println <span class="st0">&#8220;svn up&#8221;</span>.<span class="me1">execute</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">text</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;war<span class="br0">&#40;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;Ant.<span class="me1">copy</span><span class="br0">&#40;</span>todir:Ant.<span class="me1">antProject</span>.<span class="me1">properties</span>.<span class="st0">&#8216;deploy.dir&#8217;</span>, overwrite:<span class="kw2">true</span><span class="br0">&#41;</span> <span class="br0">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;fileset<span class="br0">&#40;</span>dir:<span class="st0">&#8220;.&#8221;</span>, includes:<span class="st0">&#8220;ROOT.war&#8221;</span><span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp;<span class="br0">&#125;</span><br />
<span class="br0">&#125;</span></div>
</div>
<p>Your script can have multiple targets. If you specify a &#8216;default&#8217; one, like I have above, it is what will be run if you supply no target (which is what we want).</p>
<p>5. Now I have a simple shell script on my server to setup the environment variables and run the build.</p>
<div class="codesnip-container" >
<div class="codesnip"><span class="co1">#!/bin/bash</span></p>
<p><span class="kw3">export</span> <span class="re2">GROOVY_HOME=</span>/usr/share/groovy<br />
<span class="kw3">export</span> <span class="re2">GRAIILS_HOME=</span>/usr/share/grails<br />
<span class="kw3">export</span> <span class="re2">JAVA_HOME=</span>/usr/java/jdk<br />
<span class="kw3">export</span> <span class="re2">GWT_HOME=</span>/usr/share/gwt</p>
<p><span class="kw3">cd</span> $<span class="nu0">1</span></p>
<p><span class="re1">$GRAILS_HOME</span>/bin/grails -Dgrails.<span class="re2">env=</span>production prod-push ROOT.war</div>
</div>
<p>This script can then be re-used for all projects on the server.</p>
<p>6. To update our app, we simply do the following:</p>
<p>- Check our changes into Subversion<br />
- SSH into our server and go to our /build/ directory<br />
- Run the build script (ie, ./build.sh wiifit)</p>
<p>Our new app is live in less than a minute and we don&#8217;t kill our home internet connection :)</p>
<p>This solution may not be very good for high-usage, critical apps - if I were building (and leaving code) on a production app server at my day job, I&#8217;d be fired (and deserve it!) - but for small apps like I build, it is a good solution. This solution is pretty simple, but I&#8217;m working on a full deployment plugin for grails - fewer setup steps, tomcat management, etc.. If you have any suggestions or ideas, let me know.
</p>
]]></content:encoded>
			<wfw:commentRSS>http://www.spenceruresk.com/2008/07/02/quickly-redeploying-grails-apps/feed/</wfw:commentRSS>
		<feedburner:origLink>http://www.spenceruresk.com/2008/07/02/quickly-redeploying-grails-apps/</feedburner:origLink></item>
		<item>
		<title>Grails + GWT with GWT-EXT + GoogleMaps + MaxMind sample application</title>
		<link>http://feedproxy.google.com/~r/Spenceruresk/~3/ydQC-rhvISY/</link>
		<comments>http://www.spenceruresk.com/2008/06/15/grails-gwt-with-gwt-ext-googlemaps-maxmind-sample-application/#comments</comments>
		<pubDate>Sun, 15 Jun 2008 06:04:38 +0000</pubDate>
		<dc:creator>suresk</dc:creator>
		
	<category>Software Development</category>
	<category>Java</category>
	<category>Groovy</category>
	<category>Grails</category>
	<category>GWT</category>
		<guid isPermaLink="false">http://www.spenceruresk.com/2008/06/15/grails-gwt-with-gwt-ext-googlemaps-maxmind-sample-application/</guid>
		<description><![CDATA[I&#8217;ve been playing around with Grails and a bit of GWT lately, and it sure is a lot of fun. I&#8217;ve made some applications that use Grails, GWT, and GoogleMaps (see: Find A Wii Fit), and thought I&#8217;d write a quick tutorial on how to do it - it can be a little tricky.
This application [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been playing around with Grails and a bit of GWT lately, and it sure is a lot of fun. I&#8217;ve made some applications that use <a href="http://www.grails.org/">Grails</a>, <a href="http://code.google.com/webtoolkit/">GWT</a>, and <a href="http://code.google.com/apis/maps/">GoogleMaps</a> (see: <a href="http://www.findawiifit.com/site/map">Find A Wii Fit</a>), and thought I&#8217;d write a quick tutorial on how to do it - it can be a little tricky.</p>
<p>This application is fairly simple - it displays a google map view that is centered on the user&#8217;s location, and inserts a marker where they are located. I am using <a href="http://www.maxmind.com/?rId=uresk">MaxMind</a> to turn an IP into latitude and longitude coordinates. They cost money and you may be able to find a free one, but they aren&#8217;t that expensive (something like $20 for 50,000 lookups) and I&#8217;ve been pretty happy with them so far.</p>
<p>There is a <a href="http://www.grails.org/GWT+Plugin">GWT+Grails</a> plugin that makes it easy for Grails and GWT to work together. I am also using <a href="http://gwt-ext.com/">GWT-EXT</a> to make it look nice, and to make the GoogleMaps integration a little easier. If you want to see this app in action, you can see it <a href="http://www.maptutorials.com/">here</a> (it may not match the example exactly - I&#8217;m actively developing it). I&#8217;ve also made the entire project available for free, <a href="http://www.spenceruresk.com/findme.zip">here</a>.</p>
<p>1.Create a new Grails application (grails create-app findme)</p>
<p>2.Install the Grails + GWT plugin (grails install-plugin gwt)</p>
<p>3.Create your Grails Module (grails create-gwt-module net.uresk.FindMe)</p>
<p>4. Create your page (grails create-gwt-page main/index.gsp net.uresk.FindMe, answer yes when it asks if you want it to create the controller)</p>
<p>5. Download GWT-EXT (<a href="http://gwt-ext.com/download/">http://gwt-ext.com/download/</a>), put gwtext.jar in your project’s lib/gwt directory (ie, $PROJECT_NAME/lib/gwt). You’ll also have to put it into the plugins/gwt-0.2.4/lib directory.</p>
<p>6. We&#8217;ll then have to hack _Internal in the /plugins/gwt-0.2.4/scripts/ directory (hopefully this won&#8217;t be necessary in the next version of the plugin). Around line 89, you&#8217;ll have to add in another include entry after the others:</p>
<p>Include(name: &#8216;gwtext.jar&#8217;);</p>
<p>We&#8217;ll also need to go down a few more lines, and before &#8216;pathElement(location: &#8220;${basedir}/${srcDir}&#8221;)&#8217;, add &#8216;pathElement(location: &#8220;${basedir}/lib/gwt/gwtext.jar&#8221;)&#8217;.</p>
<p>Lastly, if you get an error about heap space, you&#8217;ll need to give the gwt compiler more heap space. Do this by adding in &#8216;jvmarg(value: &#8216;-Xmx256M&#8217;)&#8217; a few lines down (around line 102), just above where the other arg() lines start. Not sure if this is related to using gwt-ext, running on Mac OS X, or what, but I did run into it a few times.</p>
<p>7. Download EXT 2.0.2 (<a href="http://yogurtearl.com/ext-2.0.2.zip">http://yogurtearl.com/ext-2.0.2.zip</a>), copy the &#8216;adapter&#8217; and &#8216;resources&#8217; directory, along with the &#8216;ext-all.js&#8217;, &#8216;ext-all-debug.js&#8217;, &#8216;ext-core.js&#8217;,  and &#8216;ext-core-debug.js&#8217; into your project&#8217;s /web-app/js/ directory.</p>
<p>8. Download mapstraction (<a href="http://mapstraction.com/svn/source/mapstraction.js">http://mapstraction.com/svn/source/mapstraction.js</a>) and copy it into your applications web-app/js directory as well.</p>
<p>9. Open up your Grails project (I prefer IntelliJ for Groovy/Grails development at the moment, btw) and find the FindMe.gwt.xml file (it is in /src/java/net/uresk directory). Add in the following:</p>
<pre>
<div class="codesnip-container" >
<div class="codesnip"><span class="sc2">&lt;inherits <span class="kw3">name</span>=<span class="st0">&#8220;com.gwtext.GwtExt&#8221;</span> /<span class="kw2">&gt;</span></a></span>
<span class="sc2">&lt;stylesheet <span class="kw3">src</span>=<span class="st0">&#8220;/findme/js/resources/css/ext-all.css&#8221;</span> /<span class="kw2">&gt;</span></a></span>
<span class="sc2"><a href="http://december.com/html/4/element/script.html"><span class="kw2">&lt;script</span></a> <span class="kw3">src</span>=<span class="st0">&#8220;/findme/js/adapter/ext/ext-base.js&#8221;</span> /<span class="kw2">&gt;</span></a></span>
<span class="sc2"><a href="http://december.com/html/4/element/script.html"><span class="kw2">&lt;script</span></a> <span class="kw3">src</span>=<span class="st0">&#8220;/findme/js/ext-all.js&#8221;</span> /<span class="kw2">&gt;</span></a></span></div>
</div>
</pre>
<p>10. Add the following entries in:<br />
Create your Google Maps keys for localhost and for your production domain. To make things easy, I added a config property in called &#8216;googlemaps.key&#8217;, and then added this into my controller to get it for the right environment:[key: grailsApplication.config.googlemaps.key]12. In your index.gsp, add in the following:</p>
<p>A reference to mapstraction: &lt;script type=&#8221;text/javascript&#8221; src=&#8221;/findme/js/map/mapstraction.js&#8221;&gt;&lt;/script></pre>
<p>The google maps js include: &lt;script type=&#8221;text/javascript&#8221; src=&#8221;http://maps.google.com/maps?file=api&#038;v=2.x&#038;key=${key}&#8221;&gt;&lt;/script&gt;</pre>
<p>13. Now create a service called something like LookupService, and add in the following code to access MaxMind:</p>
<pre>
<div class="codesnip-container" >
<div class="codesnip"><span class="kw2">class</span> LookupService <span class="br0">&#123;</span>

&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw4">static</span> expose = <span class="br0">&#91;</span><span class="st0">&#8216;gwt:net.uresk.client&#8217;</span><span class="br0">&#93;</span>

&nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.google.com/search?q=allinurl%3ADouble+java.sun.com&#038;bntl=1"><span class="kw3">Double</span></a><span class="br0">&#91;</span><span class="br0">&#93;</span> getLatLonFromIp<span class="br0">&#40;</span><a href="http://www.google.com/search?q=allinurl%3AString+java.sun.com&#038;bntl=1"><span class="kw3">String</span></a> ip<span class="br0">&#41;</span><span class="br0">&#123;</span>

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span><span class="br0">&#40;</span>!<span class="br0">&#40;</span>ip ==~ /bd<span class="br0">&#123;</span><span class="nu0">1</span>,<span class="nu0">3</span><span class="br0">&#125;</span>.d<span class="br0">&#123;</span><span class="nu0">1</span>,<span class="nu0">3</span><span class="br0">&#125;</span>.d<span class="br0">&#123;</span><span class="nu0">1</span>,<span class="nu0">3</span><span class="br0">&#125;</span>.d<span class="br0">&#123;</span><span class="nu0">1</span>,<span class="nu0">3</span><span class="br0">&#125;</span>b/<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ip = defaultIp
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; def res = <span class="st0">&#8220;http://geoip1.maxmind.com/b?l=${maxMindKey}&amp;i=${ip}&#8221;</span>.<span class="me1">toURL</span><span class="br0">&#40;</span><span class="br0">&#41;</span>.<span class="me1">text</span>.<span class="me1">split</span><span class="br0">&#40;</span><span class="st0">&#8220;,&#8221;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.google.com/search?q=allinurl%3ADouble+java.sun.com&#038;bntl=1"><span class="kw3">Double</span></a><span class="br0">&#91;</span><span class="br0">&#93;</span> result = <span class="kw2">new</span> <a href="http://www.google.com/search?q=allinurl%3ADouble+java.sun.com&#038;bntl=1"><span class="kw3">Double</span></a><span class="br0">&#91;</span><span class="nu0">2</span><span class="br0">&#93;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span> = <a href="http://www.google.com/search?q=allinurl%3ADouble+java.sun.com&#038;bntl=1"><span class="kw3">Double</span></a>.<span class="me1">parseDouble</span><span class="br0">&#40;</span>res<span class="br0">&#91;</span><span class="nu0">3</span><span class="br0">&#93;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result<span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span> = <a href="http://www.google.com/search?q=allinurl%3ADouble+java.sun.com&#038;bntl=1"><span class="kw3">Double</span></a>.<span class="me1">parseDouble</span><span class="br0">&#40;</span>res<span class="br0">&#91;</span><span class="nu0">4</span><span class="br0">&#93;</span><span class="br0">&#41;</span>

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">return</span> result
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span></div>
</div>
</pre>
<p>You can swap out <a href="http://www.maxmind.com/?rId=uresk">MaxMind</a> with any other service. I added a maxMindKey config property in Config.groovy, but you can easily hard-code it.</p>
<p>14. Now create your GWT client code, something like this:</p>
<pre>
<div class="codesnip-container" >
<div class="codesnip">GoogleMap mainPanel;

&nbsp; &nbsp; <span class="coMULTI">/**
&nbsp; &nbsp; &nbsp;* This is the entry point method.
&nbsp; &nbsp; &nbsp;*/</span>
&nbsp; &nbsp; <span class="kw2">public</span> <span class="kw4">void</span> onModuleLoad<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; createPanel<span class="br0">&#40;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp;<span class="kw2">new</span> Viewport<span class="br0">&#40;</span>mainPanel<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp;updateLatLonFromMaxMind<span class="br0">&#40;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; <span class="br0">&#125;</span>

&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> <span class="kw4">void</span> updateLatLonFromMaxMind<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LookupServiceAsync myService = <span class="br0">&#40;</span>LookupServiceAsync<span class="br0">&#41;</span> GWT.<span class="me1">create</span><span class="br0">&#40;</span>LookupService.<span class="kw2">class</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ServiceDefTarget endpoint = <span class="br0">&#40;</span>ServiceDefTarget<span class="br0">&#41;</span> myService;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <a href="http://www.google.com/search?q=allinurl%3AString+java.sun.com&#038;bntl=1"><span class="kw3">String</span></a> moduleRelativeURL = GWT.<span class="me1">getModuleBaseURL</span><span class="br0">&#40;</span><span class="br0">&#41;</span> + <span class="st0">&#8220;rpc&#8221;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; endpoint.<span class="me1">setServiceEntryPoint</span><span class="br0">&#40;</span>moduleRelativeURL<span class="br0">&#41;</span>;

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; AsyncCallback callback = <span class="kw2">new</span> AsyncCallback<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;<span class="kw2">public</span> <span class="kw4">void</span> onSuccess<span class="br0">&#40;</span><a href="http://www.google.com/search?q=allinurl%3AObject+java.sun.com&#038;bntl=1"><span class="kw3">Object</span></a> result<span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp;<a href="http://www.google.com/search?q=allinurl%3ADouble+java.sun.com&#038;bntl=1"><span class="kw3">Double</span></a><span class="br0">&#91;</span><span class="br0">&#93;</span> latLon = <span class="br0">&#40;</span><a href="http://www.google.com/search?q=allinurl%3ADouble+java.sun.com&#038;bntl=1"><span class="kw3">Double</span></a><span class="br0">&#91;</span><span class="br0">&#93;</span><span class="br0">&#41;</span>result;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setLatLong<span class="br0">&#40;</span>latLon<span class="br0">&#91;</span><span class="nu0">0</span><span class="br0">&#93;</span>, latLon<span class="br0">&#91;</span><span class="nu0">1</span><span class="br0">&#93;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span>

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;<span class="kw2">public</span> <span class="kw4">void</span> onFailure<span class="br0">&#40;</span><a href="http://www.google.com/search?q=allinurl%3AThrowable+java.sun.com&#038;bntl=1"><span class="kw3">Throwable</span></a> caught<span class="br0">&#41;</span> <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp;<span class="co1">// do some UI stuff to show failure</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; &nbsp;<span class="br0">&#125;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>;

&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; myService.<span class="me1">getLatLonFromIp</span><span class="br0">&#40;</span>callback<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>

&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> <span class="kw4">void</span> setLatLong<span class="br0">&#40;</span><a href="http://www.google.com/search?q=allinurl%3ADouble+java.sun.com&#038;bntl=1"><span class="kw3">Double</span></a> lat, <a href="http://www.google.com/search?q=allinurl%3ADouble+java.sun.com&#038;bntl=1"><span class="kw3">Double</span></a> lon<span class="br0">&#41;</span><span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; LatLonPoint llp = <span class="kw2">new</span> LatLonPoint<span class="br0">&#40;</span>lat.<span class="me1">doubleValue</span><span class="br0">&#40;</span><span class="br0">&#41;</span>, lon.<span class="me1">doubleValue</span><span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Marker m = <span class="kw2">new</span> Marker<span class="br0">&#40;</span>llp<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; m.<span class="me1">setInfoBubble</span><span class="br0">&#40;</span><span class="st0">&#8220;&lt;div&gt;You are here!&lt;/div&gt;&#8221;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mainPanel.<span class="me1">setCenterAndZoom</span><span class="br0">&#40;</span>llp, <span class="nu0">10</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mainPanel.<span class="me1">addMarker</span><span class="br0">&#40;</span>m<span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span>

&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw2">private</span> <span class="kw4">void</span> createPanel<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mainPanel = <span class="kw2">new</span> GoogleMap<span class="br0">&#40;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mainPanel.<span class="me1">setTitle</span><span class="br0">&#40;</span><span class="st0">&#8220;Spencer&#8217;s Google Map Page&#8221;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; mainPanel.<span class="me1">addLargeControls</span><span class="br0">&#40;</span><span class="br0">&#41;</span>;
&nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#125;</span></div>
</div>
</pre>
<p>15. Now, we need to create the stubs for this service so that GWT can use it. Do this by running &#8216;grails run-app&#8217;.</p>
<p>16. Unfortunately, there currently isn&#8217;t an easy way to get at the HttpRequest object inside our service. There is a <a href="http://jira.codehaus.org/browse/GRAILSPLUGINS-386">JIRA item</a> open for this, and I&#8217;m working on a potential solution. In the meantime, we’ll have to do a bit of hacking.</p>
<p>First, we&#8217;ll need to open up the LookupService and LookupServiceAsync java files that the plugin generated – they are in /src/net/uresk/client in this example. Modify the method signatures so they don’t take a String object (the IP). They should look like: java.lang.Double[] getLatLonFromIp(); and void getLatLonFromIp(AsyncCallback callback);</p>
<p>Next, we&#8217;ll need to modify the GrailsRemoteServiceServlet (in /plugins/gwt-0.2.4/src/groovy/org/codehaus/groovy/grails/plugins/gwt). On line 53, we are going to modify the method call so that it explicitly passes in the ip address, by changing it to say this:</p>
<p>def retval = service.invokeMethod(serviceMethod.name, this.getThreadLocalRequest().getRemoteAddr())</p>
<p>If you are using this behind a proxy (ie, behind Apache HTTPD with mod_proxy), getRemoteAddr() won&#8217;t work – you&#8217;ll have to instead get the X-Forwarded-For header value.</p>
<p>This is a nasty hack, and will break all your other GWT RPC calls, so if you are going to do more with this example, you&#8217;ll have to do something a little smarter to inject the IP (contact me if you want some ideas, and also keep an eye on the JIRA item mentioned above). Hopefully it won&#8217;t be necessary much longer.</p>
<p>You should be able to run your application now! Do &#8216;grails run-app&#8217; again and browse to <a mce_href="http://localhost:8080/findme/main" xhref="http://localhost:8080/findme/main">http://localhost:8080/findme/main</a>.</p>
<p>Let me know if you have any questions or suggestions. I also hang out on the #groovy IRC channel on the evenings and weekends (GMT -700) if you need help.</p>
<p>Have fun :)</p>
<p>Special Thanks to <a href="http://abhijeetmaharana.com/blog/2008/04/07/gwt-ext-and-google-maps/">Abhijeet Maharana</a> who provided an excellent how-to for using GoogleMaps with Gwt-Ext.</p>
<p><b>Update:</b> Sorry, I forgot to include the GWT client code in the original post. It is in there, step 14 now. Let me know if I missed anything else.
</p>
]]></content:encoded>
			<wfw:commentRSS>http://www.spenceruresk.com/2008/06/15/grails-gwt-with-gwt-ext-googlemaps-maxmind-sample-application/feed/</wfw:commentRSS>
		<feedburner:origLink>http://www.spenceruresk.com/2008/06/15/grails-gwt-with-gwt-ext-googlemaps-maxmind-sample-application/</feedburner:origLink></item>
		<item>
		<title>Running Grails applications on a VPS</title>
		<link>http://feedproxy.google.com/~r/Spenceruresk/~3/XwnFAkQHRWY/</link>
		<comments>http://www.spenceruresk.com/2008/06/12/running-grails-applications-on-a-vps/#comments</comments>
		<pubDate>Fri, 13 Jun 2008 04:02:49 +0000</pubDate>
		<dc:creator>suresk</dc:creator>
		
	<category>Technology</category>
	<category>Enterprise Development</category>
	<category>Websites</category>
	<category>Groovy</category>
	<category>Grails</category>
		<guid isPermaLink="false">http://www.spenceruresk.com/2008/06/12/running-grails-applications-on-a-vps/</guid>
		<description><![CDATA[For some time, it has been one of my dreams to see Java-based web applications be more viable for small websites. This means two things: rapid development capabilities (like Ruby on Rails), and inexpensive, reliable, and economical hosting options.
For goal #1, Grails is clearly fitting the bill. I spent the last year or so developing [...]]]></description>
			<content:encoded><![CDATA[<p>For some time, it has been one of my dreams to see Java-based web applications be more viable for small websites. This means two things: rapid development capabilities (like Ruby on Rails), and inexpensive, reliable, and economical hosting options.</p>
<p>For goal #1, <a href="http://www.grails.org/">Grails</a> is clearly fitting the bill. I spent the last year or so developing Rails apps, and Grails feels almost as productive. The community around it is getting quite active and there are some excellent plugins.</p>
<p>Reaching Goal #2 is going to be a bit trickier, but I think we are getting close. I am able to deploy 3 or 4 Grails applications on a 256 MB VPS now, and they work reasonably well. The good thing is that VPS&#8217; are getting quite cheap, and a VPS with 256 MB of memory can easily be had for less than $20/month. (Shameless plug - I am putting together a site - <a href="http://www.vps-hosting-reviews.com/">VPS hosting reviews</a> - that lists vps providers, their plans, prices, and reviews. And it is developed with Grails and running on a VPS :) )That said, you wouldn&#8217;t want to do this if your applications get a ton of traffic, and hosting a Java application will never be as cheap as hosting PHP applications.</p>
<p>Getting several Grails/Java applictions deployed on a server with only 256 MB of RAM (and on a VPS, no less, where getting a big block of contiguous memory can be tricky) takes a bit of work, so I&#8217;ve decided to detail a few things I&#8217;ve learned. This is specifically for Grails applications, although most of the tips should be helpful for any other Java application deployment as well. It also assumes you are using Tomcat as your app server.</p>
<p><strong>1. Dump Apache HTTP server</strong></p>
<p>A lot of people (including me for the longest time) would use Apache to forward requests to Tomcat. There is nothing wrong with Apache HTTP server itself, but in this setup, it can eat up a bunch of memory and really isn&#8217;t necessary. You can use iptables or xinetd to forward requests from port 80 to your app server. A good tutorial for these options can be found <a href="http://www.ibm.com/developerworks/linux/library/l-secjav.html">here</a>. Doing this should free up a bit more precious memory for your app server.</p>
<p><strong>2. Make sure you are using the server JVM</strong></p>
<p>This is easy to forget to do - HotSpot will automatically choose which vm to run based on server attributes, so on a real production box, it will choose the server vm automatically. On a VPS, you&#8217;ll need to manually do this by adding &#8220;-server&#8221; to CATALINA_OPTS.</p>
<p><strong>3. Give you server more PermGen space</strong></p>
<p>Groovy uses a bit more PermGen space than normal, due to all the classloading it does. This means you&#8217;ll probably want to configure your vm to use a bit more PermGen space than usual by doing -XX:MaxPermSize=m. On my server, setting this to about half of the overall memory allocated seemed to be the best, but your results may vary.</p>
<p><strong>4. Experiment</strong></p>
<p>Ideally, you&#8217;d just upload your apps and not worry about tuning, but when you are trying to squeeze the most out of a VPS, this isn&#8217;t the case. Play around with different memory settings and other vm options to see what gets your particular setup the best performance and stability. Feel free to share what works well for you :)
</p>
]]></content:encoded>
			<wfw:commentRSS>http://www.spenceruresk.com/2008/06/12/running-grails-applications-on-a-vps/feed/</wfw:commentRSS>
		<feedburner:origLink>http://www.spenceruresk.com/2008/06/12/running-grails-applications-on-a-vps/</feedburner:origLink></item>
		<item>
		<title>Avoiding unpleasant code with peer reviews</title>
		<link>http://feedproxy.google.com/~r/Spenceruresk/~3/s7Nak7JVI9M/</link>
		<comments>http://www.spenceruresk.com/2008/05/26/avoiding-unpleasant-code-with-peer-reviews/#comments</comments>
		<pubDate>Mon, 26 May 2008 23:07:20 +0000</pubDate>
		<dc:creator>suresk</dc:creator>
		
	<category>Technology</category>
	<category>Enterprise Development</category>
	<category>Software Development</category>
		<guid isPermaLink="false">http://www.spenceruresk.com/2008/05/26/avoiding-unpleasant-code-with-peer-reviews/</guid>
		<description><![CDATA[
Ah, the smell of a fresh codebase.
I’m certain most software developers who have been around for any amount of time have had to work on “The Project”. This project has probably been going for years, has had a fair amount of turnover on the development team, and has had a handful of architects (with their [...]]]></description>
			<content:encoded><![CDATA[<div class="Section1">
<p class="MsoNormal">Ah, the smell of a fresh codebase.</p>
<p class="MsoNormal">I’m certain most software developers who have been around for any amount of time have had to work on “The Project”. This project has probably been going for years, has had a fair amount of turnover on the development team, and has had a handful of architects (with their own way of doing things).</p>
<p class="MsoNormal">Projects like this may work wonderfully and be very successful from a business standpoint, and the individuals working on them are likely quite competent. Yet, from a development perspective, they are a nightmare. They contain difficult to understand code, lots of unused (or commented out) code, little testing, little adherence to good development practices, few comments, and a general feeling of brittleness.</p>
<p class="MsoNormal">Code like this may work exactly as intended, but when a codebase gets disorganized, chaotic, and sloppy it can lead to other problems, such as:</p>
<ul>
<li><!--[if !supportLists]--><span />An unpleasant experience for developers</li>
</ul>
<ul>
<li><!--[if !supportLists]--><span />High cost to refactor code</li>
</ul>
<ul>
<li><!--[if !supportLists]--><span />More bugs</li>
</ul>
<p class="MsoNormal">I’ve worked on a few projects like this over the last 5 years or so, and was naturally excited when I found we were going to be starting with a fresh codebase. At last, all of this cruft that has accumulated over the half a decade this project has been going will no more!</p>
<p class="MsoNormal">Imagine my surprise (and dismay) a month after the new project started when I found most of the symptoms of “The Project” starting to present themselves in the new codebase. Looking through our project and the reports we generate (PMD, CPD, Clover), I saw:</p>
<ul>
<li><!--[if !supportLists]--><span />Lots of untested code</li>
</ul>
<ul>
<li><!--[if !supportLists]--><span />Lots of bad practices and sloppy coding (as shown by PMD – we really pared down the ruleset so we don’t get a ton of false positives)</li>
</ul>
<ul>
<li><!--[if !supportLists]--><span />Unused code (already, after less than a month!?)</li>
</ul>
<ul>
<li><!--[if !supportLists]--><span />Commented-out code</li>
</ul>
<ul>
<li><!--[if !supportLists]--><span />Methods that were too big, hard to understand, or uncommented</li>
</ul>
<p class="MsoNormal">Part of this was due to spikes being done for the new project, which led me to conclude that spikes or experimental work of any kind should always be done in a branch. I also became interested in how code gets to this state so quickly, and of far more importance, how to keep it from reaching this state.</p>
<p class="MsoNormal">I don’t think this happens because people are bad developers necessarily, but because it requires a large degree of diligence and policing to keep a codebase clean and well-organized. It is easy to let organizational or quality issues fall to the wayside when working on functionality, and timelines sometimes leave little time for these tasks.</p>
<p class="MsoNormal">Some people offer up pair programming as a way to avoid this, but I don’t particular care for it (see my comments on <a href="http://www.spenceruresk.com/2007/03/25/impaired-programming-how-neither-of-us-is-as-dumb-as-both-of-us/">pair programming</a>). I think situational pair programming is an excellent practice, but I think full-time pair programming is, besides a terrible waste of time, largely ineffective.</p>
<p class="MsoNormal">After doing some research and analysis of how we work, I’m beginning to think that peer reviews are an excellent solution and practice. They provide most of the benefits of pair programming with few of the drawbacks. You still have someone examining your code, asking questions, and offering feedback, but instead of doing it for an entire iteration or whatever (where one of you will likely be bored for a good portion of the time), you do it for an hour or whatever is necessary. The only potential drawback is that if someone is totally off on their approach and it isn’t noticed until the end, it could be costly to refactor (so costly, in some cases, that it may be left in its sub-optimal state).</p>
<p class="MsoNormal">With that in mind, I set out to attempt to come up with good practices for conducting code reviews, and also best practices we should be following to keep our codebase clean and easy to work with. I’m wondering what other organizations are doing for peer reviews, and what I can do to improve the stuff I came up with.</p>
<p class="MsoNormal">It should be noted that a peer review is largely orthogonal from a QA review – a particular block of work can pass the QA review with flying colors and totally fail the peer review. The way I see it, QA reviews inspect the interface, peer reviews inspect the implementation.</p>
<p class="MsoNormal">Here is the document I came up with:</p>
<p class="MsoNormal">&#8211;</p>
<p class="MsoNormal">The peer review should occur prior to resolving a story or bug. At least 30 minutes should be set aside for a peer review, to allow for a thorough review. Once the review has been completed and the reviewer is satisfied, they should leave a comment on the JIRA entry stating that they have peer reviewed the unit of work.</p>
<p class="MsoNormal">Besides following this checklist, you both should go over all the code you wrote for this story. The reviewer should not hesitate to point out how something could have been done in a better way. If the reviewer cannot figure out what a particular piece of code does in a relatively short amount of time, it should be re-written or comments should be added in the code.</p>
<p class="MsoNormal"><strong>1. Metrics / Standards </strong></p>
<p class="MsoNormal">- (<span style="font-size: 11pt; line-height: 115%; font-family: "Calibri","sans-serif"">any coding metrics – code coverage, static analysis, etc)</span></p>
<p class="MsoNormal">- Test coverage should be meaningful – ie, don’t just check that a method executed without throwing an exception</p>
<p class="MsoNormal">- Use the right kind of test for your code (ie, some code may need just unit tests, others may need integration tests, and some might need functional tests)</p>
<p class="MsoNormal">- Business logic is properly tested with unit tests</p>
<p class="MsoNormal">- If this is a bug, was a unit test specifically for that bug created?</p>
<p class="MsoNormal"><strong>2. Code Style </strong></p>
<p class="MsoNormal">- Properly formatted Java code</p>
<p class="MsoNormal">- No commented-out code</p>
<p class="MsoNormal">- No unused code</p>
<p class="MsoNormal">- JPA standards followed (we have a separate document for this)</p>
<p class="MsoNormal">- If you have to explain a piece of code to your reviewer, that piece of code should be documented</p>
<p class="MsoNormal">- If your code is meant to be re-used throughout the app (ie, a utility class) it should have descriptive and useful JavaDocs</p>
<p class="MsoNormal">- Classes should be fewer than 500 lines of code, and any over 250 lines should be scrutinized closely</p>
<p class="MsoNormal"><strong>3. View </strong></p>
<p class="MsoNormal">- All JSF controls have explicit ids</p>
<p class="MsoNormal">- Everything works in IE (firefox support is strongly recommended, as well)</p>
</div>
<p class="MsoNormal">- All fields validate properly (ie, no 500 errors when you put in invalid values)</p>
<p class="MsoNormal">- JSF pages named consistently</p>
<p class="MsoNormal">&#8211;</p>
<p class="MsoNormal">This is part policing – making sure people are following best practices we’ve set forth, and that part of it kind of sucks. It is also part informative, however. Ideally, both the reviewer and the developer are learning from the experience. The reviewer may see a way to do something better and thereby make the code better and increase the skill of the developer. The reviewer may also see something that educates them as well.</p>
<p class="MsoNormal">In the limited testing I’ve done with this, it has worked well. I personally like having someone look at my code with me and let me know what I could have done better, or what piece of code is not quite as intuitive as I thought it was (everything I write is totally intuitive – to me!). I’m curious as to what other people’s thoughts and experiences with regards to peer reviews are, however.</p>
]]></content:encoded>
			<wfw:commentRSS>http://www.spenceruresk.com/2008/05/26/avoiding-unpleasant-code-with-peer-reviews/feed/</wfw:commentRSS>
		<feedburner:origLink>http://www.spenceruresk.com/2008/05/26/avoiding-unpleasant-code-with-peer-reviews/</feedburner:origLink></item>
	</channel>
</rss>
