24 February 2008

Readable Specifications : Hpricot and RSpec

I use FIT and HTMLUnit during the day for really, truly testing my web application. At night, when I transform myself into a Ruby monster, it's RSpec and Hpricot (the "enjoyable" HTML parser). I had tried before with assert_select, but I ended up with a zillion nested with_tag statements that didn't help my digestion.

At work, we have written a little bit of transformation so that the tables we see in our FIT tests look pretty similar to the tables we are testing in our application. I wanted to do the same with RSpec so it would look like this:

table = doc.search("//table[@id='invitations']").first

table.should_match([
  [ "email",            "sent",        "accepted",    "login"   ],
  [ "foo@bar",          "2008-02-10",  "2008-02-16",  "foobar"  ],
  [ "yoyo@toto",        "2008-02-15",  "2008-02-17",  "yoyo"    ],
  [ "will@not.accept",  "2008-02-15",  "",            ""        ],
])

The following little bit of code does the job (I dropped it into my spec_helper)

module Hpricot
  class Elem
    def should_match(array)
      array.each_with_index { |row_data, row_index|
        if (row_index == 0)
          cell_tag = "th"
          row = 1
        else
          cell_tag = "td"
          row = row_index
        end
        row_data.each_with_index { |cell_text, column_index|
          q = "//tr[#{row}]/#{cell_tag}[#{column_index + 1}]"
          self.search(q).inner_html.strip.should == cell_text
        }
      }
    end
  end
end

This is a really basic solution ... there's lots of work before I can use it to test attributes and nested markup in an equally readable way. And it assumes the first row is in a <thead> and contains <th> elements; and that the remainder is under a <tbody> element (this is how Markaby generates markup (it also happens to be correct, if you have a header row)).

I'm a total Hpricot n00b, so there's probably a better way to implement this, but I'm enjoying it for now ... please let me know if you have a better way :)

14 February 2008

Markaby vs templating, with a remark on DSLs

I tried out Markaby ("MARKup As ruBY") the other day because I was getting completely tangled in my rhtml. It's a DSL for generating HTML from Ruby. I like it: it's much less verbose than templating, and it's a lot easier to read. Template enthusiasts might argue that Markaby does not enforce proper separation between markup and content - so a UI designer will be unable to work properly. Sorry. I only know of projects where the developers are also the HTML/CSS designers. This seems to be standard practice for in-house projects at large organisations, as well as a necessity for tiny organisations who can't afford more people. The mythical UI designers - so real in the Freemarker manual I start to worry they'll grab my keyboard - haven't turned up for work yet ...

Unfortunately, it's not so easy to write. At the risk of being scorned by the rails community I will dare to mention that I use Intellij for all my ruby coding (yes, ruby coding. I know it's the "intelligent java editor"), and it has great support for HTML - it autocompletes html tags, attributes, a little bit of javascript, and a heap of CSS. Even colours. It's, like, awesome.

But I'm not talking about Intellij today, I'm talking about Markaby. The problem is, Intellij doesn't know (yet) how to autocomplete Markaby. When I write


div.selected(:id => "foo_#{foo.id}", :style => "position:abs___

and try to complete from here, Intellij doesn't realise this is the position property of a HTML style attribute, and it can't tell me that the valid completion is absolute. What's more, I can't control-click selected to navigate to the definition for this CSS class.

I'm sure the smart guys at Intellij will have this one figured out pretty quickly if Markaby gains market share. As Martin Fowler discusses in detail at Language Workbenches, tool support for DSLs is a general problem. But this absence of support doesn't mean we should reject either Markaby or DSLs generally.

One of the reasons we choose one programming language over another is because of how it helps us think. Lisp/Smalltalk/Ruby are powerful because they get completely out of the way. Well-designed DSLs are useful because they focus our attention on the problem at hand. The languages that win are those that allow us focus while staying out of our way. The value of the language is independent of the availability of tools for it. Java was around for a long time before Intellij, and indeed Spring and Hibernate were around for quite a while before Intellij provided specific tool support for those frameworks.

Tool support for a DSL is often more expensive than the DSL itself - so it will be unsurprising to continue seeing new unsupported DSLs for the foreseeable future. That way the industry invests in tool support only for those DSLs that actually take off.

Which I hope Markaby does.

Database Connection pooling with Oracle and Hibernate

We were getting a lot of ORA-00020: maximum number of processes (%s) exceeded, and we were also using apache commons dbcp for connection pooling. I can't say that the oracle error message is at all related to dbcp, but after a little hunting I found that the Oracle jdbc driver natively supports pooling - you don't need a 3rd-party pooling provider. This is how we have our Hibernate datasource set up now (in our Spring application context) -


<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
   <property name="dataSource">
        <bean class="oracle.jdbc.pool.OracleDataSource">
            <property name="URL" value="${datasource.url}"/>
            <property name="user" value="${datasource.user}"/>
            <property name="password" value="${datasource.password}"/>
            <property name="connectionCachingEnabled" value="true" />
            <property name="connectionCacheName" value="my_connection_pool" />
            <property name="connectionCacheProperties">
                <value>
                    MinLimit: 5
                    MaxLimit: 25
                    InitialLimit: 5
                </value>
            </property>
        </bean>
    </property>

  ... other stuff ...

</bean>

"oracle.jdbc.pool.OracleDataSource" is shipped with the Oracle driver (ojdbc14.jar). Our friend ORA-00020 hasn't appeared again in the last couple of days, so we might be in luck.

You might argue that the project now has a hard-coded dependency on Oracle - but, honestly, the Universe will die its heat death long before this project switches database.

On a completely separate note, the ${substitutions} are replaced by a Spring PropertyPlaceholderConfigurer at runtime, and we are using a jasypt implementation so we can even encrypt the database password. Nice stuff ...

04 February 2008

CVs and CVS, part II (the other side of the coin)

As ├ętienne commented, (and I paraphrase) CV authors include a lot of keywords in order to game CV indexing engines. In a sense, the CV authors and the JD (Job Description) authors are in a kind of arms race. Of the pointless, self-defeating kind.

Dear JD authors:

There are a million CVs out there that match your JD. How about writing something with a little more focus? You would need to know what you really want ... not just what are the technologies on your project.

It's true that if you have a project that's all java, struts, oracle and whatnot, it's quicker to integrate someone who's all java, struts, oracle and whatnot. But that still leaves a million CVs. What can you do to bring that down to, say, 50?

First of all, how can you tell whether the java, struts, etc mentioned on the CV are real skills rather than just technologies used on the project your candidate has been "involved in"? What would you expect to find in the CV of someone really, truly, deeply skilled with java, compared to someone who has poked around with the language for a year?

Secondly, how can you tell this person really wants to deliver value on your project, and isn't just looking for another job to keep going for the next few months? How do you feel when you read the CV of someone who is obsessed with delivering great software, compared to someone who would be bored without a job and wouldn't know what to do outside a cubicle?

Thirdly, if you will forgive me for smashing the stereotype of the antisocial nerd, the geek that can't speak (I imagine this is why Dilbert is rarely drawn with a mouth) - the primary job of a software developer is communication with other human beings. We spend ages just trying to find the right name for things. The best software speaks first of all to the team that develops it; and only secondarily to the machine that runs it. What picture forms in your mind as you read the CV of a great communicator, compared to the picture that develops (if at all) as you read the CV of a ... um, you know, those people who, sort of, can't really express themselves really well, like.

Fourthly, why are you reading CVs? Haven't you heard of Google? It's your CV :)