<?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-7052399</id><updated>2012-01-18T13:56:18.381-05:00</updated><title type='text'>Semprebon on Software</title><subtitle type='html'>The search for better software development tools and techniques</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>30</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7052399.post-9100659136844068393</id><published>2011-04-05T18:51:00.000-04:00</published><updated>2011-04-05T18:52:50.328-04:00</updated><title type='text'>Ruby Nation Roundup</title><content type='html'>&lt;div style="background-color: transparent; font-family: Times; font-size: medium; "&gt;&lt;span id="internal-source-marker_0.011321317870169878" style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;It was a cold and rainy Friday morning when I headed out to Reston, Virginia for &lt;/span&gt;&lt;a href="http://www.rubynation.org/"&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 153); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap; "&gt;RubyNation&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;, a local ruby conference. Attending were hundreds of the Washington area’s finest ruby developers, as well as programmers from as far away as India. What follows are what I consider the highlights of the conference.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;The opening keynote by Ruby godfather &lt;/span&gt;&lt;a href="http://pragdave.pragprog.com/"&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 153); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap; "&gt;Dave Thomas&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt; epitomized one trend I noticed, by not being about Ruby at all. In fact, out of 26 main talks at RubyNation (I didn’t count lightning talk sessions), only 11 were actually about Ruby. Has the rabid enthusiasm for ruby on rails finally abated? At least among the elite developers who actually take the time to attend conferences, this seems to be the case. There was speculation in the hallways as to which big-name ruby guru would be the first to break ranks. Talks by Aaron Bedra on &lt;/span&gt;&lt;a href="http://clojure.org/"&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 153); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap; "&gt;Clojure&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;, Jerry Cheung on &lt;/span&gt;&lt;a href="http://nodejs.org/"&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 153); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap; "&gt;Node,js&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;, and Blake Mizerany on, well, just about everything else, highlighted the advantages of avoiding ruby for tasks it isn’t particularly suited for: low-latency services, concurrency, analytical analysis, and more. Even Joe O’Brien’s talk on Ruby on Android was more about ruby’s failure as a viable Android programming language in comparison to the ruby-like &lt;/span&gt;&lt;a href="http://www.mirah.org/"&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 153); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap; "&gt;Mirah&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt; programming language.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;Of course, if you’re going to go all polyglot on your project, you need a way for those languages to intercommunicate. The preferred lingua franca, at least for lower-level integration, seemed to be the Java Virtual Machine, with &lt;/span&gt;&lt;a href="http://www.jruby.org/"&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 153); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap; "&gt;jRuby&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt; getting several mentions and one full talk by Russ Olson.  Ben Scofield’s lecture on “Thinking Small”, on the other hand, dealt with integrating at a larger scale - in particular, with the value of creating a large system from many smaller, more focused services, communicating via databases and HTTP/REST. You know, we should really be doing more of that here at GeoIQ.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;Second only to Ruby in conference air time, Javascript was well represented. In a pirate-themed talk complete with hats, patches and the shouting of “Arrrg!”, Chris Williams covered the history of JavaScript, from its humble and rushed beginnings to its current effort at world dominance, ending with his call for &lt;/span&gt;&lt;a href="http://en.wikipedia.org/wiki/Google_bomb"&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 153); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap; "&gt;google-bombing&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt; to &lt;/span&gt;&lt;a href="http://promotejs.com/"&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 153); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap; "&gt;promote&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt; good &lt;/span&gt;&lt;a href="https://developer.mozilla.org/en/JavaScript"&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 153); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap; "&gt;JS documentation.&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt; The previously mentioned talk on Node.js covered the growing use of JS on the server, while Trotter Cachion’s talk on doing graphics in &lt;/span&gt;&lt;a href="http://raphaeljs.com/"&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 153); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap; "&gt;Raphaël &lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;covered the client side. My favorite javascript alternative, &lt;/span&gt;&lt;a href="http://jashkenas.github.com/coffee-script/"&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 153); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap; "&gt;coffeescript&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;, seems to be getting some traction as well, with several mentions and one Lightning Talk.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;Avdi Grimm gave an excellent talk on writing “Confident Code” which clearly spelled out how to make ruby more readable by structuring methods in 4 parts: Input,Work, Results, Errors. He also mention a number of neat techniques, like using Null Objects to eliminate nil checks, that I was not familiar with. &lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;As usual, there were a sprinkling of talks on non-programing topics - David Keener’s on business models (money for code!), Keavy McMinn’s talk on training for an ironman triathlon (You think you have it bad?), and Dr. Nic  Williams closing keynote on ruby user groups (We need to talk) were all more or less successfully pitched as relevant to the ruby developer.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;One reason I like going to conferences like RubyNation is to learn about new tools and even old tools that somehow escaped my notice. Some of the those that got my particular attention were &lt;/span&gt;&lt;a href="http://www.mirah.org/"&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 153); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap; "&gt;Mirah&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt; (static ruby for jvm), &lt;/span&gt;&lt;a href="http://code.google.com/p/protobuf/"&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 153); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap; "&gt;Protocol Buffers&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt; (cross-platform binary serialization), &lt;/span&gt;&lt;a href="http://sass-lang.com/"&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 153); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap; "&gt;Sass&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;/&lt;/span&gt;&lt;a href="http://compass-style.org/"&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 153); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap; "&gt;Compass&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt; (programmable css), &lt;/span&gt;&lt;a href="http://railsinstaller.org/"&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 153); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap; "&gt;Rails Installer&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt; (easy Rails for Windows), and &lt;/span&gt;&lt;a href="http://raphaeljs.com/"&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 153); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap; "&gt;Raphaël&lt;/span&gt;&lt;/a&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt; (JS alternative to Flash or Canvas)&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size: 11pt; font-family: Arial; color: rgb(0, 0, 0); background-color: transparent; font-weight: normal; font-style: normal; text-decoration: none; vertical-align: baseline; white-space: pre-wrap; "&gt;Of course, the main reason for a conference is to hang out with like-minded folks for stimulating conversations, and RubyNation didn’t disappoint, whether it was discussing the pros and cons of cross platform applications (Mac/iPhone users are picky, Linux users are happy to have any decent UI) or the best places to live outside the United States (Chile?). One of the great things about these smaller local programming conferences is that you end up knowing a lot more of the people. In all, a successful conference which can be summarized in one word: Arggg!.&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-9100659136844068393?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/9100659136844068393/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=9100659136844068393' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/9100659136844068393'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/9100659136844068393'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2011/04/ruby-nation-roundup.html' title='Ruby Nation Roundup'/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-2624416857023039692</id><published>2011-02-24T18:28:00.002-05:00</published><updated>2011-02-24T20:26:35.781-05:00</updated><title type='text'>Javascript, RIAs and the Future of Software Development</title><content type='html'>&lt;h2&gt;In 5 years, 90% of new code will be written in or compiled into javascript&lt;/h2&gt;A bold statement, no doubt, but the trend is clear. In a few years, "web apps" will be developed as simple static HTML/CSS with business logic written in javascript, supported by a database server serving up &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;JSON&lt;/span&gt;. Mobile apps will be javascript compiled to native code or run in-browser with native add-on code only as needed. This can already be done, and greatly simplifies the development of cloud-based applications that cab be accessed by web, desktop app, or mobile app. And in a year or two, if your mobile app can't be accessed on the web, or your web app can't be accessed on a mobile device, your users are going to go elsewhere.&lt;br /&gt;&lt;h2&gt;The Past&lt;/h2&gt;To understand where we are going, it helps to look at where we came from. Back in the 80's, client server was all the rage. Rich client applications contained all your business logic, and accessed a remote &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;back-end&lt;/span&gt; database for &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_3"&gt;persistence&lt;/span&gt; and &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;interconnectivity&lt;/span&gt;. This worked well, except that distributing the client was a pain in the butt. Within an enterprise, this could be semi-controlled with the appropriate software, but for the general public, it only worked for well-established and fairly static protocols like POP, HTTP, etc.&lt;br /&gt;&lt;br /&gt;In the late 90s, business found they could eliminate the distribution problem by moving to web applications. Unfortunately, these had limited functionality. Web forms &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;were functionally&lt;/span&gt; equivalent to gussied up 3270 screens. In addition to the poor &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;UI&lt;/span&gt;, web sites also required entire pages to be built repeatedly on the server, resulting in higher bandwidth and more load, while increasingly more powerful PC clients sat mostly idle.&lt;br /&gt;&lt;br /&gt;In the mid 2000s, we got Dynamic HTML,  which once it was &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;rebranded&lt;/span&gt; as AJAX, quickly became a popular way to add more functionality to traditional web applications. As AJAX became more prominent, we had to essentially implement two apps in one - one feeding html to the user's browser, and another feeding &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;JSON&lt;/span&gt; to the javascript app.&lt;br /&gt;&lt;br /&gt;Later in the decade, web &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;APIs&lt;/span&gt; became popular, allowing web applications to be integrated with other applications (web or otherwise). If we were extremely lucky and forward-looking, these &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;APIs&lt;/span&gt; just used our existing AJAX interface, but more typically, we had to create yet another http interface in our increasingly overburdened web application.&lt;br /&gt;&lt;br /&gt;So in web development as it stands today, we end up writing server code to generate HTML pages; and more server code to generate AJAX &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_11"&gt;JSON&lt;/span&gt;; and maybe more server code to support our &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;API&lt;/span&gt;, And if we want to support mobile, its another app &lt;span style="font-style:italic;"&gt;for each mobile OS&lt;/span&gt;.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;This is absurd.&lt;br /&gt;&lt;h2&gt;The Future&lt;/h2&gt;The solution is clear. Write the entire app - all the business logic, in javascript or its equivalent. This code should access a &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;RESTful&lt;/span&gt; database server that accepts and serves up &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_14"&gt;JSON&lt;/span&gt;, and can handle security and validation. You will also need a web server to do what web servers do best - serve up static pages (.js, .html, .css, .&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_16"&gt;png&lt;/span&gt;, etc). The javascript will then fetch dynamically fetch non-static data from the database server and update the static page. This is basically the old rich client from the 80s, but implemented in javascript, and using the &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_17"&gt;Internet&lt;/span&gt; for distribution. Our servers now become remarkably simpler. And since we are now using our own &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_18"&gt;API&lt;/span&gt;, there is no extra work implementing an &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_19"&gt;API&lt;/span&gt; for external consumption. In fact, our app is basically on equal footing to those external apps that use our &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_20"&gt;APIs&lt;/span&gt;.&lt;br /&gt;&lt;br /&gt;There are already frameworks like &lt;a href="http://www.sproutcore.com/"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_21"&gt;SproutCore&lt;/span&gt;&lt;/a&gt; for writing these types of applications, and I expect to see more. What we really need is better support for a &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_22"&gt;JSON&lt;/span&gt;-serving database that allows custom validation (triggers implemented in javascript would be ideal) and security. Until then, the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_23"&gt;back-end&lt;/span&gt; will need to be coded using conventional methods.&lt;br /&gt;&lt;br /&gt;There are, of course, some criticisms of this approach:&lt;br /&gt;&lt;h3&gt;Isn't implementing client side javascript insecure?&lt;/h3&gt;If you are going to implement a full and rich external &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_24"&gt;API&lt;/span&gt; anyway, the security has got to be in the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_25"&gt;JSON&lt;/span&gt; server anyway. Because the &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_26"&gt;JSON&lt;/span&gt; server is much simpler than the old-school dynamically generated html server, security should be easier.&lt;br /&gt;&lt;h3&gt;Yuck, I have to write all my code in Javascript?&lt;/h3&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_27"&gt;Javescript&lt;/span&gt; is a semantically powerful object oriented language, saddled with a poor syntax. Fortunately, there are &lt;a href="https://github.com/jashkenas/coffee-script/wiki/List-of-languages-that-compile-to-JS"&gt;languages like &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_28"&gt;coffeescript&lt;/span&gt;&lt;/a&gt; that can be compiled to javascript and offer better syntax. I expect this to be a growing trend, with better languages in the future, and maybe even &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_29"&gt;precompiling&lt;/span&gt; into an abstract syntax tree that is sent to the browser.&lt;br /&gt;&lt;h3&gt;What about mobile &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_30"&gt;development&lt;/span&gt;?&lt;/h3&gt;Frameworks like &lt;a href="http://www.appcelerator.com/"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_31"&gt;Appcelerator&lt;/span&gt;&lt;/a&gt; and &lt;a href="http://www.phonegap.com/"&gt;&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_32"&gt;Phonegap&lt;/span&gt;&lt;/a&gt; allow you to create mobile applications for a variety of mobile &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_33"&gt;OSs&lt;/span&gt; from javascript code, so much less work is needed compared to developing a fully native app for each mobile OS. While these environments don't give you the same level of control and access to features as native apps, I expect that this will be less a problem as these platforms mature. And you always have the option of enhancing your javascript-based app with native code where its really needed&lt;br /&gt;&lt;h3&gt;Where does flash fit in?&lt;/h3&gt;Flash is basically the browser equivalent to native app code - used only as necessary, and increasingly replaced by javascript functionality.&lt;br /&gt;&lt;br /&gt;So that's where I think web development is going. Now all we need is a catchy  name...&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-2624416857023039692?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/2624416857023039692/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=2624416857023039692' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/2624416857023039692'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/2624416857023039692'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2011/02/javascript-rias-and-future-of-software.html' title='Javascript, RIAs and the Future of Software Development'/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-7244524409959250011</id><published>2011-01-04T20:51:00.003-05:00</published><updated>2011-01-04T21:20:29.627-05:00</updated><title type='text'>Playing With CoffeeScript and HTML5</title><content type='html'>I spent today playing around with &lt;a href="http://jashkenas.github.com/coffee-script/"&gt;CoffeeScript&lt;/a&gt;, a nice little pythonesque language that is compiled into javascript. Very nice. This was for a little mini wiki app I'm working on as a learning exercise. The idea originally was to have a &lt;a href="http://www.scala-lang.org/"&gt;Scala&lt;/a&gt;-based server side running on Google App Engine that acted as a simple  RESTful JSON database. All the processing is done in the browser with javascript (i.e., CoffeeScript), using HTML5 storage for off-line availability with eventual synchronization when the server becomes available.&lt;br /&gt;&lt;br /&gt;Unfortunately, I ended up abandoning the idea of using scala for the backend part - doing Java (i.e., Scala) development on Google App Engine turned out to be rather slow and tedious, partially due to broken (or at least not well documented) APIs, but mostly due to tools that didn't quite work together. I did get it to work, barely, but after a day and a half of frustration, I switched to Python and got the whole server side part done in a couple of hours. Much easier and simpler.&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-7244524409959250011?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/7244524409959250011/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=7244524409959250011' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/7244524409959250011'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/7244524409959250011'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2011/01/playing-with-coffeescript-and-html5.html' title='Playing With CoffeeScript and HTML5'/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-7287328090099373144</id><published>2010-02-28T02:53:00.003-05:00</published><updated>2011-01-09T13:26:35.282-05:00</updated><title type='text'>Javascript Idioms - Namespaces</title><content type='html'>This is brain-dead simple. In order to avoid sticking everything in the public namespace, we just create an object to hold it, and add our name-spaced objects to it:&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;var mystuff;&lt;br /&gt;if (mystuff === undefined) { mystuff = {}; }&lt;br /&gt;&lt;br /&gt;mystuff.foo = function() { return "Hello!"; };&lt;br /&gt;&lt;br /&gt;mystuff.foo(); # =&gt; "Hello!"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;I define it this way so that I can add things to the namespace in multiple files without having to worry about what's included or which is first. For more complex module-like behavior with private variables and such, see my previous post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-7287328090099373144?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/7287328090099373144/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=7287328090099373144' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/7287328090099373144'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/7287328090099373144'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2010/02/javascript-idioms-namespaces.html' title='Javascript Idioms - Namespaces'/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-5292596255608650819</id><published>2010-02-28T02:30:00.002-05:00</published><updated>2011-01-09T13:31:43.972-05:00</updated><title type='text'>Javascript Idioms - Private Attributes and Modules</title><content type='html'>Ok, I admit my Javascript skills are a bit lacking, and I've recently been doing more of it, so after watching &lt;a href="http://javascript.crockford.com/"&gt;Douglas Crockford&lt;/a&gt;&lt;a href="http://googlecode.blogspot.com/2009/03/doug-crockford-javascript-good-parts.html"&gt; talk about the good parts&lt;/a&gt;, and reading up a bit, I think I now understand some of the stuff going on those javascript libraries. So there are more or less notes to myself so I don't forget.&lt;br/&gt;&lt;h2&gt;Closures&lt;/h2&gt;&lt;br/&gt;So to really understand what's going on, you have to know a little bit about closures. Now some people seem to be under the impression that a closure is just an anonymous function, but its a little more complex - its an an anonymous function that has access to the context in which it was defined. The reason that last bit is important is that it lets you maintain state outside the function itself. For example:&lt;br/&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;var x=5&lt;br /&gt;function foo() { ++x; return x; }&lt;br /&gt;foo(); // returns 6&lt;br /&gt;foo(); // returns 7&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br/&gt;You can even share state between funtions:&lt;br/&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;function bar() {--x; return x; }&lt;br /&gt;bar();  // returns 6&lt;br /&gt;bar(); // returns 5&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br/&gt;&lt;h2&gt;Dynamic Contexts for Closures&lt;/h2&gt;&lt;br/&gt;In this case, the context is just a global variable, so this probably doesn't look too impressive, but we can actually create some context dynamically using a "self-invoking function' (which strikes me as a bit of a misnomer, as the function isn't invoking itself, its returning a function that is then invoked. Anyway, in simplest (and most useless) form, it looks like this:&lt;br/&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;(function() { /* stuff */ }) ()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br/&gt;So why would we do that? Well, in that little region I've put the "stuff" comment is actually a context where we can define variables and functions. Now, ordinarily, all that context would disappear once the function completes running, but if we define another function in there and make it available outside our bit of code, it actually has access to the "stuff" (since its really a closure) even after the function returns. This allows us to create private data and functions that are only accessible by the "public" functions we make available. For example, we can define a function that can access some private data:&lt;br/&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;var normalize = function {&lt;br /&gt;  var DELIM = /\W+/&lt;br /&gt;  return function(s) { s.split(DELIM).join('_'); };&lt;br /&gt;} ();&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br/&gt;In this case, we can access the internally defined function because its returned by our context-creating anonymous function, but we could also assign it to some other object in the global scope, like window. The internally defined DELIM is private to the function.&lt;br/&gt;&lt;h2&gt;The Revealing Module&lt;/h2&gt;&lt;br/&gt;So now we can use  the closure to create a module that has private and public functions and variables. There are a couple of ways of structuring the code, but I think the Revealing Module Pattern is one of the better ones I've seen:&lt;br/&gt;&lt;br /&gt;&lt;pre class="prettyprint"&gt;&lt;br /&gt;var foo = (function() {&lt;br /&gt;  var DELIM = /\W+/&lt;br /&gt;  function normalize(s) { s.split(DELIM).join('_'); };&lt;br /&gt;  function capitalize(s) { toUpperCase(s.charAt(0)) + s.slice(1); }&lt;br /&gt;  function mixed_case(s) {&lt;br /&gt;    var arr = s.split(DELIM);&lt;br /&gt;    for (var i = 0; i &amp;lt; s.length; ++i) { arr[i] = capitalize(arr[i]); }&lt;br /&gt;    return arr.join();&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  // constructor should return object with public parts&lt;br /&gt;  return { normalize: normalize, mixed_case: mixed_case }; }&lt;br /&gt;}();&lt;br /&gt;&lt;br /&gt;// how to use it:&lt;br /&gt;foo.mixedCase('hello world!'); # =&amp;gt; 'Hello World!'&lt;br /&gt;foo.normalize('Hello world!); # =&amp;gt; 'Hello_world'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br/&gt;So what this is doing is creating a private context, defining some variables and functions in that private context, then returning an object with just the parts (in this case, the normalize and mixed_case functions) that we want to have as the public api. These functions are then assigned to the public variable foo.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-5292596255608650819?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/5292596255608650819/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=5292596255608650819' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/5292596255608650819'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/5292596255608650819'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2010/02/javascript-idioms-private-attributes.html' title='Javascript Idioms - Private Attributes and Modules'/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-8792636814819519017</id><published>2009-12-18T05:53:00.002-05:00</published><updated>2009-12-18T06:05:40.598-05:00</updated><title type='text'>DroidDice open sourced and now on github</title><content type='html'>I've open-sourced my DroidDice android application under the GPL. It is available at &lt;a href="http://github.com/semprebon/DroidDice"&gt;GutHub&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-8792636814819519017?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/8792636814819519017/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=8792636814819519017' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/8792636814819519017'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/8792636814819519017'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2009/12/droiddice-open-sourced-and-now-on.html' title='DroidDice open sourced and now on github'/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-6792808096146849384</id><published>2009-06-04T09:53:00.003-04:00</published><updated>2009-06-04T10:01:13.958-04:00</updated><title type='text'>Seting Custom Headers in ActiveResource Requests</title><content type='html'>Recently had to figure out how to send a custom http header when accessing a resource through ActiveResource. Basically, you need to add the header to the connections default header hash. In your active resource class:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class ActiveResource::Connection&lt;br /&gt;  alias :static_default_header :default_header&lt;br /&gt;&lt;br /&gt;  def set_header(key, value)&lt;br /&gt;    default_header.update(key =&gt; value)&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;class FunkyResource &lt; ActiveResource::Base&lt;br /&gt;  ...&lt;br /&gt;  connection.set_header('SHOE_SIZE', '12')&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now all HTTP requests for that resource will include the HTTP header SHOE_SIZE.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-6792808096146849384?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/6792808096146849384/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=6792808096146849384' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/6792808096146849384'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/6792808096146849384'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2009/06/seting-custom-headers-in-activeresource.html' title='Seting Custom Headers in ActiveResource Requests'/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-1424971515222755579</id><published>2009-02-22T07:31:00.003-05:00</published><updated>2009-02-22T08:13:04.817-05:00</updated><title type='text'>Taming Shoulda</title><content type='html'>&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;Ok&lt;/span&gt;, so I've been using &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;shoulda&lt;/span&gt; for the last couple of weeks, and while its certainly reduced the &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_2"&gt;amount&lt;/span&gt; of duplicated code in my test, and given me more meaningful test descriptions, I've also noticed that its a little hard to find things with all the indented levels of contexts, setups, and &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;shouldas&lt;/span&gt;. And I find that I still end up with duplicated setup and testing code. Fortunately, this is fairly easy to address by writing your own shoulds and context methods.&lt;br /&gt;&lt;h3&gt;Custom &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_4"&gt;shoulda's&lt;/span&gt;&lt;/h3&gt;Lets look first at writing your own &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;shoulda&lt;/span&gt; method. Lets say you are testing a method that parses some file and returns the extracted data, along with a lit of any errors it found:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;result, errors = MyClass.parse(file)&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;We want to test this with a number of different test files, so we end up with tests looking like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;context "when parsing &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;abc&lt;/span&gt;.&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;tst&lt;/span&gt;" do&lt;br /&gt; setup do&lt;br /&gt;   @result, @errors = &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;MyClass&lt;/span&gt;.parse("&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_9"&gt;abc&lt;/span&gt;.&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_10"&gt;tst&lt;/span&gt;")&lt;br /&gt; end&lt;br /&gt; should "have no errors" do&lt;br /&gt;   assert @errors.empty?&lt;br /&gt; end&lt;br /&gt; should "have some expected result" do&lt;br /&gt;   ....&lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;So a number of our tests is  going to be checking that @errors is empty. While its only a few lines, it does add some &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_11"&gt;visual&lt;/span&gt; clutter, and is easy to clean up with our own &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_12"&gt;shoulda&lt;/span&gt; method:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def self.should_have_no_errors&lt;br /&gt; should "have no errors" do&lt;br /&gt;   assert @errors.empty?&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This needs to be before your tests are defined, since it is a class method which will be executed during the loading of the class. Now, we can replace three lines with one:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;context "when parsing &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_13"&gt;abc&lt;/span&gt;.&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_14"&gt;tst&lt;/span&gt;" do&lt;br /&gt; setup do&lt;br /&gt;   @result, @errors = &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_15"&gt;MyClass&lt;/span&gt;.parse("&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_16"&gt;abc&lt;/span&gt;.&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_17"&gt;tst&lt;/span&gt;")&lt;br /&gt; end&lt;br /&gt; should_have_no_errors&lt;br /&gt; should "have some expected result" do&lt;br /&gt;   ....&lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Our &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_18"&gt;shoulda&lt;/span&gt; methods can also take parameters, so if we wanted to test for the presence of errors, we could add a should_have_error method:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def self.should_have_error(&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_19"&gt;regex&lt;/span&gt;)&lt;br /&gt; should "have error matching #{&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_20"&gt;regex&lt;/span&gt;.to_s}" do&lt;br /&gt;   assert_match &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_21"&gt;regex&lt;/span&gt;, @errors.first&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;which we would use with&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;should_have_error /Invalid Attribute/&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h3&gt;Custom Contexts&lt;/h3&gt;The next thing we notice is that a lot of our tests are going to have similar setup sections, but we can't use a common context because the file names are different. To address this, we can create a custom context:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def self.when_parsing(&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_22"&gt;filename&lt;/span&gt;, &amp;amp;block)&lt;br /&gt; context "when parsing #{&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_23"&gt;filename&lt;/span&gt;}" do&lt;br /&gt;   setup do&lt;br /&gt;     @result, @errors = &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_24"&gt;MyClass&lt;/span&gt;.parse(&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_25"&gt;filename&lt;/span&gt;)&lt;br /&gt;   end&lt;br /&gt;   block.bind(self).call&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now, our tests look like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;when_parsing("&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_26"&gt;abc&lt;/span&gt;.&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_27"&gt;tst&lt;/span&gt;") do&lt;br /&gt; should_have_no_errors&lt;br /&gt; should "have some expected result" do&lt;br /&gt;   ...&lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I find this &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_28"&gt;particularly&lt;/span&gt; convenient  for handling &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_30"&gt;logins &lt;/span&gt;when testing rails &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_29"&gt;functional&lt;/span&gt; tests&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_30"&gt;&lt;/span&gt;:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def self.logged_in_as(&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_31"&gt;sym&lt;/span&gt;, &amp;amp;block)&lt;br /&gt; context "logged in as #{&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_32"&gt;sym&lt;/span&gt;.to_s}" do&lt;br /&gt;   &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_33"&gt;login&lt;/span&gt;_as(&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_34"&gt;sym&lt;/span&gt;)&lt;br /&gt; end&lt;br /&gt; block.bind(self).call&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;logged_in_as(:&lt;span class="blsp-spelling-error" id="SPELLING_ERROR_35"&gt;quentin&lt;/span&gt;) do&lt;br /&gt; [test normal user stuff]&lt;br /&gt;end&lt;br /&gt;&lt;br /&gt;logged_in_as(:admin) do&lt;br /&gt; [test admin access]&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-1424971515222755579?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/1424971515222755579/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=1424971515222755579' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/1424971515222755579'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/1424971515222755579'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2009/02/taming-shoulda.html' title='Taming Shoulda'/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-1762096548935571365</id><published>2009-02-05T18:27:00.004-05:00</published><updated>2009-02-10T20:09:13.272-05:00</updated><title type='text'>Shoulda</title><content type='html'>Recently, I've been using &lt;a href="http://thoughtbot.com/projects/shoulda/"&gt;shoulda&lt;/a&gt; for improving my test code. There are a number of things I like about shoulda:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Unlike rspec, shoulda works with your existing tests&lt;/li&gt;&lt;li&gt;It lets you separate out common set-up and tear-down code that isn't needed for every test&lt;/li&gt;&lt;li&gt;Adds some organization to your test files, making it easier to find things&lt;/li&gt;&lt;li&gt;Allows you to describe test cases in real English, insteadOfMixedCaseIdentifiers&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;When I first started using shoulda, I organized my tests the same way I had in my pre-shoulda days - be method tested, so I might have:&lt;br /&gt;&lt;pre style=""&gt;&lt;br /&gt;class StackTest&lt;br /&gt; context "Stack" do&lt;br /&gt;   setup { @stack = Stack.new }&lt;br /&gt; context ".pop" do&lt;br /&gt;   should "Return nil if stack empty" do ...&lt;br /&gt;   should "Return top of stack" do...&lt;br /&gt;   ...&lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;However, I have come to the conclusion that a better approach is to organize by the state of the object under test, since this will allow you consolidate your setup/teardone code more effectively, and also force you to think in terms of the object rather than the individual methods:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;class StackTest&lt;br /&gt; context "An empty stack" do&lt;br /&gt;   setup { @stack = Stack.new }&lt;br /&gt;   should "Return nil on pop" do&lt;br /&gt;   should "Have one item after a push" do ...&lt;br /&gt;   should "return top of stack" do...&lt;br /&gt;   ...&lt;br /&gt; end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;There are a number of other things that make shoulda tests more maintainable:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Don't nest contexts too deeply, as it makes it harder to find things&lt;/li&gt;&lt;li&gt;Don't just throw tests together in the same context because they happen to share some setup code - think in terms of the state of the object or class being tested&lt;/li&gt;&lt;li&gt;You can use contexts without setup to organize - like having a context for grouping together class methods&lt;/li&gt;&lt;li&gt;Write your own shoulda clauses for commonly tested conditions&lt;/li&gt;&lt;li&gt;You can make it easier to parse output into contexts/shouldas by capitalizing each description&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-1762096548935571365?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/1762096548935571365/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=1762096548935571365' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/1762096548935571365'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/1762096548935571365'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2009/02/shoulda.html' title='Shoulda'/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-4286022183297607831</id><published>2008-11-28T13:13:00.004-05:00</published><updated>2008-12-14T20:20:28.883-05:00</updated><title type='text'>Android Applications</title><content type='html'>So I've spent the last month writing a few of applications for the Android phone. I got a TMobile G1 a couple of months ago, and I have to say, its very neat to program for.&lt;br /&gt;&lt;br /&gt;This means that, with a few exceptions, there will probably be very little money in writing Android applications. As we have seen with the iPhone, expect a flood of free/cheap apps drive user expectations as to what an Android app should cost. The lower barrier to entry for Android development as compared with the iPhone means that developers will flock to the platform, so there will be plenty of competition driving prices down, as well as open source efforts.&lt;br /&gt;&lt;br /&gt;There may still be a few ways to make some decent money as an Android developer, but none are particularly easy:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Make up for low price by being very popular - yeah, much easier said than done.&lt;/li&gt;&lt;li&gt;Provide a combined web/android service that people are willing to pay a subscription for - of course, you'll still be competing with a lot of low price/free offerings, but at least you'll be getting a steady revenue stream from your users.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Develop custom enterprise applications - not particularly fun, but it pays the rent&lt;/li&gt;&lt;li&gt;Get someone else other than the user to foot the bill, advertising being the most obvious way to do this.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;Still, I plan to write some more apps. For one thing, its a lot of fun. For another, I'm not impressed by very many of the Android programs I've tried out so far. More about that later.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-4286022183297607831?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/4286022183297607831/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=4286022183297607831' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/4286022183297607831'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/4286022183297607831'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2008/11/android-applications.html' title='Android Applications'/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-3328665614716151425</id><published>2008-11-09T22:16:00.002-05:00</published><updated>2008-11-09T22:23:11.441-05:00</updated><title type='text'></title><content type='html'>So I just got myself a T-Mobile G1 Android phone. I don't know how it will fare against the iPhone, which in many ways is better designed (but alas, not open source), but I'm guessing it will do well against its other competitors.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-3328665614716151425?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/3328665614716151425/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=3328665614716151425' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/3328665614716151425'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/3328665614716151425'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2008/11/so-i-just-got-myself-t-mobile-g1.html' title=''/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-139493259149198928</id><published>2008-10-23T11:03:00.002-04:00</published><updated>2008-10-23T11:40:39.573-04:00</updated><title type='text'>Android</title><content type='html'>I started playing with &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;Google's&lt;/span&gt; &lt;a href="http://code.google.com/android/index.html"&gt;Android &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;SDK&lt;/span&gt;&lt;/a&gt; today - long enough to implement a simple "Hello World" app. Unfortunately, between the android emulator, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;firefox&lt;/span&gt;, and &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;NetBeans&lt;/span&gt;, my four-year-old laptop is struggling to keep up. While android in not as popular as the iPhone (and may never be), writing in Java  has got to be better than working in Objective-C - an ugly languange from what I've seen, at least syntactically. And with android, there is at least some hope that other languages would be available - although the only success I've heard of is with scala.&lt;br /&gt;&lt;br /&gt;Another posibility, is, of course, javascript, especially once Google ports Google Gears to Android, although the only problem there is that it won't neccessarily have acess to all the phone's features.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-139493259149198928?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/139493259149198928/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=139493259149198928' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/139493259149198928'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/139493259149198928'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2008/10/android.html' title='Android'/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-439095691242810803</id><published>2008-10-13T08:33:00.000-04:00</published><updated>2008-10-13T08:51:15.904-04:00</updated><title type='text'></title><content type='html'>The consensus at Ruby DCamp this weekend was that we should be using gems rather than plugins for sharing rails code (of course, not everyone agrees. This was primarily because gems are versioned and handle dependencies automatically. This being the case, why are so many rails enhancements packaged as only plugins? Couldn't we do everything as gems?&lt;br /&gt;&lt;br /&gt;I think a lot of people view plugins as specific to a specific rails application while gems apply to ruby as a whole. I guess a lot of people don't know how easy it is to set up a separate gem repository for your application. With plugins, you can also easily identify which plugins an application uses. A new change to rails, &lt;a href="http://ryandaigle.com/articles/2008/4/1/what-s-new-in-edge-rails-gem-dependencies"&gt;gem dependencies&lt;/a&gt;, makes this even easier, and allows you to specify what gems your application depends on, and even gives you a task to install any required gems.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-439095691242810803?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/439095691242810803/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=439095691242810803' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/439095691242810803'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/439095691242810803'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2008/10/consensus-at-ruby-dcamp-this-weekend.html' title=''/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-6391055326900687517</id><published>2008-09-16T07:07:00.009-04:00</published><updated>2008-10-03T09:11:33.101-04:00</updated><title type='text'>Writing Good Rails Tests</title><content type='html'>Some automated testing strategies I've seen implemented on various projects:&lt;br /&gt;&lt;h3&gt;The Nil Strategy&lt;/h3&gt;I see this all too often. It is exemplified by the Rails test class below:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;require File.dirname(__FILE__) + '/../test_helper'&lt;br /&gt;&lt;br /&gt;  class RecommendationTest&lt;br /&gt;&lt;br /&gt;  # Replace this with your real tests.&lt;br /&gt;  def test_truth&lt;br /&gt;    assert true&lt;br /&gt;  end&lt;br /&gt;&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Enough said. You know who you are.&lt;br /&gt;&lt;h3&gt;One Test Per Method&lt;/h3&gt;I used to see this done all the time on java projects. For each method in the class you wan to test, you have a single test method. This simplistic approach may work for fairly simple methods, but for a method of any complexity, they are nearly always inadequate. They just test the most obvious test case for the method in question.&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;def test_add&lt;br /&gt;  set = OrderedSet.new&lt;br /&gt;  set.add("X")&lt;br /&gt;  set.add("Y")&lt;br /&gt;  set.add("X")&lt;br /&gt;  assert_equal ["X", "Y"], set.to_a&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Now obviously, you COULD put all sorts of tests in that single test method:&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;def test_add&lt;br /&gt;  set = OrderedSet.new&lt;br /&gt;  // adding to an empty set&lt;br /&gt;  set.add("X")&lt;br /&gt;  assert_true set.include? "X"&lt;br /&gt;  assert_equal 1, set.size&lt;br /&gt;&lt;br /&gt;  // adding item to set that doesn't contain it&lt;br /&gt;  set.add("Y")&lt;br /&gt;  assert_true set.include? "Y"&lt;br /&gt;  assert_equal 2, set.size&lt;br /&gt;&lt;br /&gt;  // adding item to set that does contain it&lt;br /&gt;  set.add("X")&lt;br /&gt;  assert_equal 2, set.size&lt;br /&gt;&lt;br /&gt;  // ensure that added items preserve order&lt;br /&gt;  100.times do { |i| set.add(i.to_s) }&lt;br /&gt;  assert_equal set.to_a.sort, set.to_a&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;But now its harder to determine what exactly we are testing for. Its not too bad for this method, but its still a fairly simple method. What we really need to do is refactor the test into several tests, but we can't do that if we cling to OTPM. Which leads to&lt;br /&gt;&lt;h3&gt;One Test Per Assertion&lt;/h3&gt;The way I usually test is to have a method for each test condition I'm trying to test for. By convention, I name this method in a form like&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;def test_add_should_not_add_item_if_its_in_set&lt;br /&gt;  set = OrderedSet.new&lt;br /&gt;  set.add("X")&lt;br /&gt;  set.add("X")&lt;br /&gt;  assert_true set.include? "X"&lt;br /&gt;  assert_equal 1, set.size&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The method name includes both the name of the method I'm testing and what condition is being tested. The test itself sets up, calls the method, and checks a single fact about what the method under test should do.&lt;br /&gt;&lt;br /&gt;Note that this may not literally be a single assertion. Sometimes I use several assertions to verify a single fact. I also sometimes use assertions to verify my assumptions about the setup conditions - this is particularly useful in Rails to verify some assumption about your test fixtures before you use them:&lt;br /&gt;&lt;br /&gt;&lt;pre name="code" class="ruby"&gt;&lt;br /&gt;def test_member_in_good_standing_gets_discount&lt;br /&gt;  assert_true @user.in_good_standing?&lt;br /&gt;  ...&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The main reason to do this is not to let you know if you inadvertently screwed up your fixture (although it will do that), but to serve as documentation of the assumptions the test is making if it isn't obvious elsewhere in the code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-6391055326900687517?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/6391055326900687517/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=6391055326900687517' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/6391055326900687517'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/6391055326900687517'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2008/09/writing-good-rails-tests.html' title='Writing Good Rails Tests'/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-5363434376976376577</id><published>2007-08-16T19:57:00.001-04:00</published><updated>2007-08-16T21:29:10.815-04:00</updated><title type='text'>Rails Unit Testing Without Fixtures</title><content type='html'>When testing models with complex relationships, fixtures can be a real pain. They require the details of a single test to be spread around several files; they aren't very dry, since you have to repeat a lot of details in each instance that may not be relevant to the situation you are trying to set up, and you are forced into putting a bunch of for unrelated tests into a single file.&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);font-size:130%;" &gt;The Test With Fixtures&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;Lets take the classic example of an Order item, that has_one product. If you are testing to ensure that the correct total is computed. With fixtures, it might look like:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def test_total_should_return_price_times_quantity&lt;br /&gt;assert_equal 33.00, order_items(:first).total&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;To see that this is valid, you would have to look in order_items.yml to find out the quantity for item :first is 3, then look in products.yml to find that the price is 11.00.&lt;br /&gt;&lt;br /&gt;There have been a number of alternatives to fixtures proposed, including Jay Fields' idea of &lt;a href="http://blog.jayfields.com/2006/06/ruby-on-rails-unit-tests.html"&gt;using mocks to avoid database access&lt;/a&gt;, which seems like going a bit too far for my tastes; and &lt;a href="http://code.google.com/p/fixture-scenarios/"&gt;fixture scenarios&lt;/a&gt;, which only solve part of the problem. Here's what I do:&lt;br /&gt;&lt;br /&gt;&lt;span style="color: rgb(0, 0, 0);font-size:130%;" &gt;The Test Without Fixtures&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;First, I create a build method for each of my model objects. This method will create a valid object with reasonable default values, except as modified by a hash parameter. For simple objects with no associations, it looks like this:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def build_product(attrs = {})&lt;br /&gt;Product.new({&lt;br /&gt;  :name =&gt; "Test Product",&lt;br /&gt;  :price =&gt; 10.00,&lt;br /&gt;}.merge(attrs))&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;For more complex objects, the builder should create any reasonable associated objects or use those past in:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def build_order_item(attrs = {})&lt;br /&gt;OrderItem.new({&lt;br /&gt;  :quantity =&gt; 1,&lt;br /&gt;  :product =&gt; build_product,&lt;br /&gt;}.merge(attrs))&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;These builder methods I usually put in test_helper.rb, since they ussualy need to be called from multiple test files. With these in place, out total test becomes:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;def test_total_should_return_price_times_quantity&lt;br /&gt;order_item = build_order_item(&lt;br /&gt;  :quantity =&gt; 3,&lt;br /&gt;  :product =&gt; build_product(:price =&gt; 11))&lt;br /&gt;assert_equal 33.00, order_item.total&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This test doesn't touch the database, and all the details relevant to what is begin tested are in one place.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-5363434376976376577?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/5363434376976376577/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=5363434376976376577' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/5363434376976376577'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/5363434376976376577'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2007/08/rails-unit-testing-without-fixtures.html' title='Rails Unit Testing Without Fixtures'/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-954790116478162646</id><published>2007-04-17T11:45:00.000-04:00</published><updated>2007-04-17T11:50:53.229-04:00</updated><title type='text'>Unproductive Haiku</title><content type='html'>No work done today.&lt;br /&gt;The parts in which it's been cut&lt;br /&gt;Are less than the whole.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-954790116478162646?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/954790116478162646/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=954790116478162646' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/954790116478162646'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/954790116478162646'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2007/04/unproductive-haiku.html' title='Unproductive Haiku'/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-3998957494985978687</id><published>2007-04-16T15:21:00.000-04:00</published><updated>2007-04-16T21:00:57.739-04:00</updated><title type='text'></title><content type='html'>My contract at a large government agency recently came to an end, and while I've been working on a project of my own which will hopefully be in beta soon, I've also been looking for more regular work. In the process, I've noticed an interesting dichotomy.&lt;br /&gt;&lt;br /&gt;Most of the companies I've talked to have been unimpressive. Although their websites claim that they are passionate about quality, enhancing the customer experience, and hiring only the best and brightest, that's not the impression you get from talking to them. Their ads on one of the big job sites have a long list of technologies you are expected to have mastered. They do little to sell you on why you should be working for them and not one of the other body shops. The recruiter gives the impression they are just trying to find the right peg for the staffing hole in some large bureaucracy.&lt;br /&gt;&lt;br /&gt;Two companies so far have stood out. Interestingly enough, I didn't hear about any of them from a job board. One, a group at &lt;a href="http://www.boozallen.com/"&gt;Booz Allen&lt;/a&gt;, I heard about through a friend. Sure, they do typical government work, but the developers I talked to were all really pretty sharp. The other was at &lt;a href="http://www.browsermedia.com/"&gt;BrowserMedia&lt;/a&gt;, and although the location is not quite ideal (but doable), they sound like they do a lot of interesting work and really made me want to work there. I had heard about them from a post on the local ruby users group, but I notice they also have an ad on Joel on Software's job site, so I'm guessing their's going to be stiff competition.&lt;br /&gt;&lt;br /&gt;I think I'm going to have to start paying more attention to the more focused job lists like Joel's.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-3998957494985978687?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/3998957494985978687/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=3998957494985978687' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/3998957494985978687'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/3998957494985978687'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2007/04/my-contract-at-large-government-agency.html' title=''/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-4305551660977484967</id><published>2007-04-03T14:31:00.000-04:00</published><updated>2007-04-12T14:57:49.004-04:00</updated><title type='text'>Managing User Attention</title><content type='html'>One feature of the web application I helped developed for a client was a list of messages that was displayed when you first logged in. This feature had been in the system since day one, and included both system-wide messages entered by management, as well as messages auto-generated by the system. I wasn't originally responsible for the message feature, but when I first saw it, I estimated that, since most of the messages were not actionable, it would only be a matter of weeks before employees became habituated to the messages and ignored them. Sure enough, that is exactly what happened.&lt;br /&gt;&lt;br /&gt;Although most of the messages were fairly irrelevant, roughly twice a year, management would put out an important messages that everyone was supposed to read. Once the managers realized that users were ignoring the message, they requested the feature be changed to make it more prominent. First, my coworker moved it to a separate page you had to click through before you got to the main page of the application. And of course, after a while, users became habituated to that as well. Then we started adding extra code to highlight the most important messages on the login page, which required the source that generated that page to be edited and redeployed each time the message was changed. Then we had to put them in bright colors. Almost a year ago when we got another request to change the login page message, and I decided to put an end to this attention arms race.&lt;br /&gt;&lt;br /&gt;I modified the original message scheme to show messages in large, red letters or the first few weeks, then revert to the normal font. And I got rid of the other places we were displaying "special" messages. This actually went well beyond the user's original request, but in the change request form, I carefully documented what I was doing, and why. The system-wide message would be displayed prominently, and we wouldn't need to redeploy the application each time the message was changed.&lt;br /&gt;&lt;br /&gt;Some time after putting that change in, I get a system change request asking us to modify the message. "We don't need a change request for this" I replied, "it isn't a software change - they can do it themselves now". I was told it had to go through the CR process anyway. After a bit of questioning, it comes out - apparently, management doesn't actually read the change requests that they routinely approve, and had no idea of what I had done. They too had become habituated.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-4305551660977484967?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/4305551660977484967/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=4305551660977484967' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/4305551660977484967'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/4305551660977484967'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2007/04/managing-user-attention.html' title='Managing User Attention'/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-3077389027573475390</id><published>2007-03-10T09:21:00.001-05:00</published><updated>2007-03-10T13:20:04.331-05:00</updated><title type='text'>Cleaning Up Code</title><content type='html'>It was a single, 6000 line module, and it was a mess. The original developer had been gone for 6 months, and it had gone through several hands since then. It was constantly having problems, with new bugs discovered weekly, but nobody wanted to touch it because every time someone did, they would break something else. It landed on my desk with several as yet unfixed bug reports attached to it.&lt;br /&gt;&lt;br /&gt;After looking through it I came to the conclusion that there was a relatively simple program buried inside, and went to work. There were no unit tests, but the main function of the program was to generate a number of output files. I could compare the correctness of my revised version by running both it and the original on the same data, and then comparing the output files.&lt;br /&gt;&lt;br /&gt;I deleted redundant and unused code, &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;refactored&lt;/span&gt;, and generally cleaned up the program. After untangling a particularly convoluted bit of logic, my comparison test failed. After half a day of research, I came to the conclusion that in this particular case, the original program had been in error. Two weeks later, I checked in a program that was 30% smaller, better documented, and much easier to follow.&lt;br /&gt;&lt;br /&gt;The supervisor was a bit suspicious of this. His philosophy was that we should be changing just the bare minimum needed to implement a fix, since previous changes had a high probability of introducing new bugs. After the program passed the first round of verification using a single run (about 8000 records) with flying colors, he insisted on testing a whole two week cycle. Since I had been testing with several months worth of data, I wasn't particularly worried. When it passed that test, he finally authorized it to be moved into production.&lt;br /&gt;&lt;br /&gt;Unfortunately, I never got a chance to finish cleaning up the code, since there were no additional bug reports in the six months that followed.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-3077389027573475390?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/3077389027573475390/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=3077389027573475390' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/3077389027573475390'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/3077389027573475390'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2007/03/cleaning-up-code.html' title='Cleaning Up Code'/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-2417902233073742208</id><published>2007-03-09T11:08:00.000-05:00</published><updated>2007-03-09T13:51:52.072-05:00</updated><title type='text'>Feedback</title><content type='html'>I suppose we've all been in this situation. We have done something (revised our resume, changed hairstyles, whatever) and we ask a friend how it looks. "looks fine" we hear, or maybe they make some minor criticism - "you have a mispelling in the third sentance". The fact is, the people we deal with on a daily basis want to be nice to us, and are therefor reluctant to criticise or suggest improvements, even when that criticism is what we really need to do better.&lt;br /&gt;&lt;br /&gt;Getting good feedback is hard, and yet it is extremely important to any effort to improve, whether improving your image or your software development process. And yet, so many organizations not only don't &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_0"&gt;encourage&lt;/span&gt; feedback, they actively discourage it. This can be done in both subtle, and unsubtle ways.&lt;br /&gt;&lt;br /&gt;One manager I know would dominate the conversation during the status meetings he held. He would prompt his underlings with specific questions about their work, then quickly move on. While this did help to keep the amount of wasted time down, it meant that issues that were not on the manager's agenda never got aired at all.&lt;br /&gt;&lt;br /&gt;Now it is certainly true that developers with some problem to be addressed could have sent an email, or otherwise brought it to the managers attention, but "process" is one of those things the project manager is supposed to be in charge of this requires the developers to both recognize that there is a problem that can be solved or an improvement that can be made, and take the initiative to raise it. This is one of the reasons I think the sadly underused "retrospective" meeting can be so effective. It creates a forum specifically for addressing project wide and process issues that are often ignored in the heat of development.&lt;br /&gt;&lt;br /&gt;Sometimes, even when issues are raised, they are repeatedly ignored by management, either by being put off "for later" or by not responding at all. &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_1"&gt;Management&lt;/span&gt; in this case is sending a clear message that feedback is not wanted.&lt;br /&gt;&lt;br /&gt;While not &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_2"&gt;encouraging&lt;/span&gt; feedback can be a problem, even worse is discouraging it. At one organization I know of, a friend of mine once suggested some improvements to the current development process, and was told in no uncertain &lt;span class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;terms&lt;/span&gt; that his role was to accept the process as handed down by management, not to suggest improvements, and that if he continued with this "insubordination", he would be terminated. Needless to say, this organization was inefficient, had a lot of communications problems, and morale was poor to boot. Managers would complain that they had a hard time keeping track of the status of things. Hardly &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_4"&gt;surprising&lt;/span&gt; if developers were fearful of giving any more &lt;span class="blsp-spelling-corrected" id="SPELLING_ERROR_5"&gt;information&lt;/span&gt; than what they had been specifically asked for.&lt;br /&gt;&lt;br /&gt;Remember, everyone can have good ideas, and so its important to capture those ideas. Feedback is vital to any effort to improve. Encourage it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-2417902233073742208?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/2417902233073742208/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=2417902233073742208' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/2417902233073742208'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/2417902233073742208'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2007/03/feedback.html' title='Feedback'/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-7354309744655484783</id><published>2006-12-15T15:04:00.000-05:00</published><updated>2006-12-15T15:17:09.160-05:00</updated><title type='text'>rspec</title><content type='html'>After hearing &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_0"&gt;Aslak&lt;/span&gt; &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_1"&gt;Hellesoy&lt;/span&gt; talk about &lt;a href="http://rspec.rubyforge.org/"&gt;&lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_2"&gt;rspec&lt;/span&gt;&lt;/a&gt; on the &lt;a href="http://podcast.rubyonrails.org/programs/1/episodes/aslak_hellesoy"&gt;rails podcast&lt;/a&gt;&lt;span style="font-weight: bold;"&gt;&lt;/span&gt; I figured I would give it a try. Its a neat way of seeing test driven development from a different perspective.&lt;br /&gt;&lt;br /&gt;First, I tried creating a new spec for an existing model using the &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_3"&gt;rspec&lt;/span&gt;_model generator, but this hung up (maybe because of some &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-corrected" id="SPELLING_ERROR_4"&gt;configuration&lt;/span&gt; issues on my &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_5"&gt;XP&lt;/span&gt; box).&lt;br /&gt;&lt;br /&gt;Then I got the following error when running a test:&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:85%;"&gt;c:/ruby/lib/ruby/gems/1.8/gems/sqlite3-ruby-1.1.0-mswin32/lib/sqlite3/errors.rb:94:in `check': &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_6"&gt;SQL&lt;/span&gt; logic error or missing database (&lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_7"&gt;SQLite&lt;/span&gt;3::&lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-error" id="SPELLING_ERROR_8"&gt;SQLException&lt;/span&gt;)&lt;br /&gt;    from c:/ruby/lib/ruby/gems/1.8/gems/sqlite3-ruby-1.1.0-mswin32/lib/sqlite3/resultset.rb:76:in `check'&lt;br /&gt;    from c:/ruby/lib/ruby/gems/1.8/gems/sqlite3-ruby-1.1.0-mswin32/lib/sqlite3/resultset.rb:68:in `commence'&lt;br /&gt;    from c:/ruby/lib/ruby/gems/1.8/gems/sqlite3-ruby-1.1.0-mswin32/lib/sqlite3/resultset.rb:61:in `initialize'&lt;br /&gt;    from c:/ruby/lib/ruby/gems/1.8/gems/sqlite3-ruby-1.1.0-mswin32/lib/sqlite3/statement.rb:158:in `execute'&lt;br /&gt;    from c:/ruby/lib/ruby/gems/1.8/gems/sqlite3-ruby-1.1.0-mswin32/lib/sqlite3/database.rb:211:in `execute'&lt;br /&gt;    from c:/ruby/lib/ruby/gems/1.8/gems/sqlite3-ruby-1.1.0-mswin32/lib/sqlite3/database.rb:186:in `prepare'&lt;br /&gt;    from c:/ruby/lib/ruby/gems/1.8/gems/sqlite3-ruby-1.1.0-mswin32/lib/sqlite3/database.rb:210:in `execute'&lt;br /&gt;    from c:/ruby/lib/ruby/gems/1.8/gems/sqlite3-ruby-1.1.0-mswin32/lib/sqlite3/database.rb:620:in `rollback'&lt;br /&gt;     ... 11 levels...&lt;br /&gt;    from c:/ruby/lib/ruby/gems/1.8/gems/rspec-0.7.4/lib/spec/runner/context_runner.rb:22:in `run'&lt;br /&gt;    from c:/ruby/lib/ruby/gems/1.8/gems/rspec-0.7.4/lib/spec/runner/command_line.rb:26:in `run'&lt;br /&gt;    from c:/ruby/lib/ruby/gems/1.8/gems/rspec-0.7.4/bin/spec:4&lt;br /&gt;    from c:/ruby/bin/spec:18&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The problem was apparently related to using &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-corrected" id="SPELLING_ERROR_9"&gt;embedded&lt;/span&gt; ruby expressions which used the model I had previously tried to create a spec for. The generator had overwritten my old model with a new blank model (I though generators were supposed to prompt before overwriting files), so the &lt;span onclick="BLOG_clickHandler(this)" class="blsp-spelling-corrected" id="SPELLING_ERROR_10"&gt;embedded&lt;/span&gt; ruby expression was not valid. Anyway, thinks seem to be working now.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-7354309744655484783?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/7354309744655484783/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=7354309744655484783' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/7354309744655484783'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/7354309744655484783'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2006/12/rspec.html' title='rspec'/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-115871231721719000</id><published>2006-09-19T19:54:00.000-04:00</published><updated>2006-10-09T05:21:06.066-04:00</updated><title type='text'>Rails Woes</title><content type='html'>I read somewhere (yeah, I know, I should have a link, but I forget) that to have a really effective, widely read blog, you need to blog every day. So here I am. The problem I have is that, during the day, I'm always coming up with great ideas for something to blog about, but by the time I actually have to sit down and write something, I forget what I was so worked up about.&lt;br /&gt;&lt;br /&gt;Anyway, my friend George, recently forcibly retired, was asking me some questions about PHP, and so I pointed out to him that all the cool geeks now use Ruby on Rails (and not just because I don't know diddly about PHP), and he ought to give that a try. So he's been trying to get it installed, and he's even forsaken his corporate Windows security blanket and is actually trying to do this on Linux, and he's been trying for two weeks, and still hasn't gotten past the install yet. Despite the fact that he's been a manager for the last few years, George is a real smart guy, and if he can't get this thing working, then its TOO DAMNED HARD!&lt;br /&gt;&lt;br /&gt;Unfortunately, I've been of limited help here. One of his main problems has been with MySQL, and for quick toy databases I use SqlLite (zero configuration and I can check the entire database file into subversion) and if I need a real database than, as a long time Oracle expert, I use PostgreSQL. He's also running on Fedora, and I tried to explain that all the cool geeks are running Ubuntu these days (except for those who have gone to the dark side and embraced OS X, but that just wasn't an option for a guy who has two dozen old Windows XP boxes of various vintages in his garage).  Well, it turns out that a former employee is also using Fedora and swears by it, and ol' George wants to stay compatible, so that's fine. But between Yum and RPM and Gem something is just not right (and thank god he didn't ask me why Linux needed three different package managers to install a simple application - I kept my mouth shut about apt and aptitude...)&lt;br /&gt;&lt;br /&gt;To be quite honest, a lot of this is just growing pains. In a year, all the top Linux distributions will have their own Rails package and he'll be able to type &lt;package&gt; install rails and be there, but in the mean time, ITS A PAIN IN THE BUTT! And its not like my choice of SqlLite is that much better - I had to go through the dance of getting just the right packages installed so the gem could compile too. But I guess I knew a little bit better what to do, and as a long time Linux user, I knew how to use Google for my tech support. George, having recently come from a windows background, didn't quite have the hang of that.&lt;br /&gt;&lt;br /&gt;If he calls tomorrow, I'll suggest he just compile from scratch. Or buy a Mac. Or use Windows.&lt;/package&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-115871231721719000?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/115871231721719000/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=115871231721719000' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/115871231721719000'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/115871231721719000'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2006/09/rails-woes.html' title='Rails Woes'/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-115573945744929493</id><published>2006-08-16T10:28:00.000-04:00</published><updated>2006-09-21T05:59:23.923-04:00</updated><title type='text'>Striving Forward, Dragged Back</title><content type='html'>&lt;span style="font-size:130%;"&gt;A Tragedy in Three Acts&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-weight: bold;"&gt;Act I - Java&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The existing system I helped develop and currently maintain (as I write this in the Summer of 2002) is a Java/J2EE based web application that supports around 16,000 users.  The Organization I work for hasn't gotten the Agile message yet, so its been up to individual developers to  use agile techniques or not. The proprietary development tool they chose precludes writing automated unit tests, but I've got a good collection of automated functional tests now. The tool-generated code is highly coupled, but I've been refactoring where I can. We've been using CVS for version control since we first started developing the system five years ago. The Java culture values things like automated testing, refactoring, and version control. Not all our tools were perfect, but the Java developers on our project at least understood the reasoning behind agile development.&lt;br /&gt;&lt;br /&gt;The system has very few reported bugs. I don't get many enhancement suggestions from users, but not because its perfect, or even particularly good. The Organization had gotten very good at saying "No" to users. If the response is always "No", you give up asking.&lt;br /&gt;&lt;br /&gt;So for a while, I found myself with not much to do. Every month or so, The Organization would mandate some change. I'd spend a few hours or days implementing it. The help desk still got plenty of calls from confused users about how to use the system. To me, these were usability bugs; the valuable feedback I needed to keep improving the system.  But The Organization discouraged dangerous things like user input. The help desk calls were summarily dismissed as "enhancements" or "user training issues". The system met its requirement. No software change was required.&lt;br /&gt;&lt;br /&gt;Instead, I worked on honing my software development skills and improving what I could that wasn't part of the system proper. I automated (to the extent possible) the migration and deployment process. I wrote additional functional tests. I taught myself ruby and started doing some data conversion, analysis, and ad-hoc reporting with it. I found the Ruby culture much like the Java culture, but with more focus on simplicity and elegance. And Ruby tools were certainly better at agile development than Java tools. Work life wasn't perfect, but it wasn't so bad.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Act II - PeopleSoft&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The Organization has another big system - PeopleSoft. It doesn't support as many users, but it seems to have a lot more change requests and bugs. The Organization completed a big system change over a year ago, and a lot of  the changes these days are fallout from that. It was supposed to simply things by out-sourcing the payroll functionality, but the PeopleSoft team is busier than ever. And with all the bug fixes and contractually or legally mandated changes, there just isn't time to make any enhancements to that system. This is why The Organization have gotten very good at saying "No" to users. Its an effective way to manage the schedule when you are swamped with changes.&lt;br /&gt;&lt;br /&gt;Besides, The Organization plans to throw the system out in a few years anyway, and out-source the rest of the PeopleSoft functionality. They don't want to invest any more than they have to on the PeopleSoft system.&lt;br /&gt;&lt;br /&gt;Many years ago, I too had been a PeopleSoft developer. It was back in the days when the web was in its infancy. Companies were tossing out their old main-frame systems and buying newfangled client-server applications like PeopleSoft. There was plenty of contractor money to be made for those with "PeopleSoft" on their resume, and for several years, I rode that gravy train. But it wore me down -- the proprietary, non-object-oriented languages; the existing code base of poorly structured code; the culture of ad-hoc testing; the problems of deploying client software on dozens, if not hundreds of desktops. It was obvious to me that the future was the web. I had to leave my job and take a significant pay cut in order to get into web development (with Pearl at first, then later Java), but I was a lot happier, and I never regretted taking that step.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Act III - The Tradgedy&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Despite my efforts to keep it secret, The Organization eventually found out about my previous PeopleSoft experience. It was little things at first - helping someone with a bit of SQL; or making a minor change to an SQR. I can hardly blame them - a resource sitting idle, and them having so much PeopleSoft work to do.&lt;br /&gt;&lt;br /&gt;Now, most of what I do here at The Organization is PeopleSoft. Eight years, and I'm back to where I started. The PeopleSoft culture hasn't changed much in that time. They don't use automated tests or use version control effectively. The culture is "change as few lines as possible", rather than refactoring, and "cut-and-paste" rather than "Don't Repeat Yourself". Massive change take months to implement. The tools have changed little, or not at all. The Organization is running an obsolete version of PeopleSoft, because they don't see the need to invest in an upgrade.&lt;br /&gt;&lt;br /&gt;Instead of pushing my skills to the next level, I have to struggle just to make them relevent.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Epilogue&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Its clearly time for me to move on. I have lived in the Java culture too long to tolerate the culture and tools of the PeopleSoft team. Unfortunately, that culture is way too common. I struggled with it when we first started our Java development.  Deciding to leave is easy. Finding a new job where they really believe in the culture of agile development is less so. I had a phone interview with one place where a friend worked. They claimed to be doing XP, but were working 80 hour weeks, lied to the client about what they were actually working on, and had a massive list of requirements that they were trying to shoe-horn into their 6 month scheduled delivery date. Didn't sound too agile to me.&lt;br /&gt;&lt;br /&gt;In the mean time, at least The Organization is paying me well.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-115573945744929493?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/115573945744929493/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=115573945744929493' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/115573945744929493'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/115573945744929493'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2006/08/striving-forward-dragged-back.html' title='Striving Forward, Dragged Back'/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-114789753244819876</id><published>2006-05-17T16:10:00.000-04:00</published><updated>2006-09-21T06:00:13.626-04:00</updated><title type='text'>Oracle 10g Express up on Debian</title><content type='html'>After a bit of work, I've got Oracle's new &lt;a href="http://www.oracle.com/technology/products/database/xe/index.html"&gt;10g Express&lt;/a&gt; database up on my debian server! Now I can start playing around with some &lt;a href="http://www.rubyonrails.org/"&gt;rails&lt;/a&gt; applications that use Oracle on the back end.  The main difficulty is that Oracle (as with their previous versions) always seems to assume that you are running X Windows on your server box. In the case of 10g Express, they provide a web application for administration, but it requires a graphical browser and can only be accessed from the local machine. Fortunately, there was a way to open it up so I could access it from my workstation:&lt;br /&gt;&lt;br /&gt;$ &lt;span style="font-weight: bold;"&gt;su oracle&lt;/span&gt;&lt;br /&gt;$ &lt;span style="font-weight: bold;"&gt;cd /usr/lib/oracle/xe/app/oracle/product/10.2.0/server/bin&lt;/span&gt;&lt;br /&gt;  $ .&lt;span style="font-weight: bold;"&gt;/oracle_enc.sh&lt;/span&gt;&lt;br /&gt;  $ &lt;span style="font-weight: bold;"&gt;./sqlplus / as sysdba&lt;/span&gt;&lt;br /&gt;  sql&gt; &lt;span style="font-weight: bold;"&gt;exec dbms_xdb.setlistenerlocalaccess(false);&lt;/span&gt;&lt;br /&gt;  sql&gt; &lt;span style="font-weight: bold;"&gt;exit&lt;/span&gt;&lt;br /&gt;  $&lt;br /&gt;&lt;br /&gt;When I tried Rails with Oracle several months ago, I found Rails' oracle support to be a bit lacking. The SQL it generated was slow, and not very flexable. Apparently, that situation has improved somewhat, so I'd like to try it out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-114789753244819876?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/114789753244819876/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=114789753244819876' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/114789753244819876'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/114789753244819876'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2006/05/oracle-10g-express-up-on-debian.html' title='Oracle 10g Express up on Debian'/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-114200740837922490</id><published>2006-03-10T11:04:00.000-05:00</published><updated>2006-09-21T06:01:35.180-04:00</updated><title type='text'>In the Belly of the Beast</title><content type='html'>I can almost feel the enthusiasm being crushed from me. Some people think I have a great job - I don't have much work to do, and the pay is really great. But its so friggin boring.  Developers are stuffed two at a time in grey featureless cubes. The organization is so risk-averse any new changes are difficult to get approved. The development process in place requires that even a minor 2o minute fix requires a two week turn-around time when it does get approved. All the software we work with is years out of date, and they end up paying license fees for software the vendor no longer even supports.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-114200740837922490?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/114200740837922490/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=114200740837922490' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/114200740837922490'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/114200740837922490'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2006/03/in-belly-of-beast.html' title='In the Belly of the Beast'/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-114140232255689423</id><published>2006-03-03T11:09:00.000-05:00</published><updated>2006-03-03T11:12:02.556-05:00</updated><title type='text'>Wow</title><content type='html'>I thought &lt;a href="http://www.oreillynet.com/ruby/blog/2006/03/transformation.html"&gt;Steve Yegge's article on Ruby&lt;/a&gt; was a pretty amazing piece of writing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-114140232255689423?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/114140232255689423/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=114140232255689423' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/114140232255689423'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/114140232255689423'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2006/03/wow.html' title='Wow'/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-114140213897315543</id><published>2006-03-03T11:05:00.000-05:00</published><updated>2006-09-21T06:02:44.330-04:00</updated><title type='text'>The Annual Blog Post</title><content type='html'>Hmm, only one post in 2005. Well, that's because I was hosting a blog on my corporate website, &lt;a href="http://www.eqsystems.com/"&gt;www.eqsystems.com&lt;/a&gt;, but I've decided maintaining something there is more trouble than its worth.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-114140213897315543?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/114140213897315543/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=114140213897315543' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/114140213897315543'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/114140213897315543'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2006/03/annual-blog-post.html' title='The Annual Blog Post'/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-109044013685678532</id><published>2004-07-21T15:59:00.000-04:00</published><updated>2004-07-21T16:02:16.856-04:00</updated><title type='text'></title><content type='html'>Figures. A day after putting out that last post about Java alternatives, I come across &lt;a href="http://www.linuxjournal.com/article.php?sid=3882"&gt;this&lt;/a&gt; article by Eric Raymond, who comes to the same conclusion, but is much more convincing.&lt;br /&gt; &lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-109044013685678532?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/109044013685678532/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=109044013685678532' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/109044013685678532'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/109044013685678532'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2004/07/figures.html' title=''/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-108894743906905909</id><published>2004-07-20T09:32:00.000-04:00</published><updated>2004-07-20T09:35:54.086-04:00</updated><title type='text'>Beyond Java</title><content type='html'>In my previous post, I described some of the reasons I felt that Java was lacking when using agile development methods. In this article, I'll go over some of the alternatives. Each of these languages has more expressive power than Java, but each has its own particular advantages and disadvantages. &lt;br /&gt; &lt;h2&gt;Lisp and Scheme&lt;/h2&gt;Putting &lt;a href="http://eksl-www.cs.umass.edu/lisp-resources/index.html"&gt;Lisp&lt;/a&gt; on this list might be surprising, but it has long been held in esteem by digital cognoscenti. It was, of course, conceived in the fabled early days of computers - one of only handful of programming languages that are older than I am. Despite this, Lisp adherents today assert that it is more powerful than any other language out there. I had spent a few weeks trying to learn Lisp in high school 25 years ago, but never really saw the point of it. My recent interest was sparked after reading several articles in its favor by &lt;a href="http://www.paulgraham.com/articles.html"&gt;Paul Graham&lt;/a&gt;. Lisp, and its more modern cousin, &lt;a href="http://www.schemers.org/"&gt;Scheme&lt;/a&gt;, are blessed with a trivially simple syntax, along with very powerful features such as macros and continuations that take advantage of that simple syntax. There are plenty of packages that extend the language. &lt;br /&gt; &lt;br /&gt; So, if Lisp is so great, why hasn't it swept the world by storm. First of all, with dozens of different implementations of Common Lisp, and dozens more of Scheme, the Lisp world appears fragmented. While there appears to be plenty of modules out there for doing things such as HTTP servers, graphics, GUIs, and such, many appear to be specific to some implementation or another. Also, while its support for programming in the small are quite impressive, its not clear that it offers the same advantages for programming in the large. Finally, Lisp's culture of terse and often obscure naming conventions and reliance on tricky, if concise programming techniques probably works against it. Paul Graham argues that, because of the simple syntax, Lisp is easy to learn. The problem is not the syntax, its the concepts. Functional programming, continuations, macro-programming, and recursion as a replacement for loops are all going to be hurdles for the average corporate programmer. Not that these are difficult to learn per-se, just that they are far from the coding mainstream. I may come back to Lisp/Scheme some day, but for now the effort required to assembly the pieces I need, and learn the techniques, is too great. &lt;br /&gt;&lt;h2&gt;Python&lt;/h2&gt;I've been working with &lt;a href="http://www.python.org/"&gt;Python&lt;/a&gt; quite a bit recently, and like it a lot. The syntax is elegant and consistent. It provides metaprogramming facilities. Python also comes with a lot of useful libraries provides everything from HTML and XML parsing, to graphics, to an interface to Tk (Tkinter) for doing GUI applications. &lt;br /&gt;&lt;h2&gt;Perl&lt;/h2&gt;I've never been much of a fan of &lt;a href="http://www.perl.com/"&gt;Perl&lt;/a&gt;, although I used it extensively in one major project I worked on. It works, but the syntax rules are confusing. In the version I was using (5.6), object-oriented programming was more effort than it should have been. The best thing Perl has going for it is &lt;a href="http://www.cpan.org/"&gt;CPAN&lt;/a&gt;, which serves as a clearinghouse for Perl modules. Its cool because Perl comes with a program for automatically installing modules from CPAN, which makings taking advantage of this resource a snap. One of the reasons I've liked &lt;a href="http://www.jedit.org/"&gt;jEdit&lt;/a&gt; is the automated installation of plugins. More developers need to do this kind of thing. &lt;br /&gt;&lt;h2&gt;Ruby&lt;/h2&gt;The &lt;a href="http://www.pragmaticprogrammer.com/"&gt;Pragmatic Programmers&lt;/a&gt; recommend &lt;a href="http://www.ruby-lang.org/en/"&gt;Ruby&lt;/a&gt; as a great programming language. While it seems a bit less wordy than Python, I don't really see that it has much advantage over that language.&lt;a href="http://www.pragmaticprogrammer.com/"&gt; &lt;br /&gt; &lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-108894743906905909?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/108894743906905909/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=108894743906905909' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/108894743906905909'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/108894743906905909'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2004/07/beyond-java.html' title='Beyond Java'/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7052399.post-108880731242088939</id><published>2004-07-02T18:22:00.000-04:00</published><updated>2004-07-03T08:46:14.366-04:00</updated><title type='text'>The Rise and Fall of Java </title><content type='html'>&lt;h2&gt;The Early Promise&lt;/h2&gt;&lt;br /&gt;Nearly a decade ago, I slung code in C, C++, and Object Pascal. C was a decent language, if somewhat hard to debug, and it put food on the table. But as I adopted the OOP mind-set, C became less and less appealing. I moved on to C++. It was James Coplien's &lt;a href="http://www.amazon.com/exec/obidos/ASIN/0201548550/eqsysteinc"&gt;Advanced C++ Programming Styles and Idioms&lt;/a&gt; that really clued me in to both the real advantages of object oriented programming, as well as how best to code C++ classes. But I wondered, why did I have to build all that code for every class? Shouldn't the system be doing that kind of rote coding for me? It seemed to me that C++ always involved a lot more work than it should. &lt;br /&gt;&lt;br /&gt;I played a bit with Object Pascal, to be specific, Borland's Delphi product. Object Pascal had automatic memory management, and a much simpler object model than C++. You could whip up a nice, GUI app in no time compared to C++. It was easy. It was fun. Alas, it was also Windows only, and proprietary.&lt;br /&gt;&lt;br /&gt;Then, around 1996, came Java. It did objects and managed memory for you. It did cross-platform GUI applications. It came with a great class library. Java seemed perfect. I switched over to java for all my own development Java quickly started accumulating an impressive collection of library classes as Java mind-share grew. Life was good. And it looked like you good actually make a living doing this java stuff to boot! When it came to getting things done, Java was a sailboat to C++'s rowboat. Sure, there were some places you couldn't get to with Java, but for those you could, you could do it with much less effort and a lot more speed and style.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;The Decline and Fall&lt;/h2&gt;&lt;br /&gt;But in the last few years, the sail has started to tatter. I've done some coding in Perl, and marveled at the ease of moving data into and out of methods. I played around a bit with Python, and was impressed with the depth and flexibility of its object model and the cleanness of its syntax. I've struggled with Java APIs that were much more complex than they should have been. I've seen how poor Java has evolved to keep up with changing development techniques. Coding in Java today, I'm beginning to feel the same way I felt 10 years ago coding in C++ - wondering why I need all this extra crap to express what I wanted to. Java was becoming more an anchor than a sail.&lt;br /&gt;&lt;br /&gt;Java just doesn't fit my more agile style of development. I do a lot more refactoring and automated unit testing now, and as a result, I've changed sides on the debate between static and dynamic typing. I've seen the work required to get a fairly inflexible language like Java to do things like database persistence well. The increase in computer power has reduced the risk of using interpreted pure object-oriented languages. Short turn-around times has put a premium on developing quick, functional code that doesn't require a lot of extra scaffolding.&lt;br /&gt;&lt;br /&gt;The developer community seems to be coming around to this view as well. Those that came to Java from Smalltalk have always complained, of course. At a recent Java conference, there were a lot of complaints about the complexity of enterprise Java, and EJBs in particular. The latest 1.5 version of Java does address some of these concerns. Autoboxing of primitives, for example, is a nice addition, as is variable-length parameter lists. But ultimately, I feel this is too little, too late. I'll still be doing most of my coding in Java, since its paying the rent, but my heart is just not in it anymore. I've come to the conclusion that Java is not part of the best way to develop software. It still has a great class library and unparalleled third-party support, so it will remain a tool in my toolbox. Just not my favorite.&lt;br /&gt;&lt;br /&gt;Next... Beyond Java - A look at some alternatives&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7052399-108880731242088939?l=semprebon.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://semprebon.blogspot.com/feeds/108880731242088939/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=7052399&amp;postID=108880731242088939' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/108880731242088939'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7052399/posts/default/108880731242088939'/><link rel='alternate' type='text/html' href='http://semprebon.blogspot.com/2004/07/rise-and-fall-of-java.html' title='The Rise and Fall of Java '/><author><name>Semprebon</name><uri>http://www.blogger.com/profile/17295229776903272919</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://4.bp.blogspot.com/_GKTUfsWnwtI/TCteNg1Q07I/AAAAAAAACJ8/zuoZJoYHuNs/S220/red_andrew.jpg'/></author><thr:total>0</thr:total></entry></feed>
