Wednesday, December 22, 2010

6 git lessons for git beginners from a git beginner

1) Bookmark this: http://book.git-scm.com/ Just do it.

2) Branching is awesome and mentally cheap right now, but can be confusing and cognitively expensive in 5 weeks time. Try to keep your commit history clean (eg. with rebase), your git log will love you for the decrease in merge commits.

3) For god's sake do most of your work in a branch. Getting merge issues when you pull just before beer o'clock will ruin your weekend. Keep your master branch looking as much like origin/master as possible.

4) Merge master into your branches often if you're planning to merge back later.

5) Merging is shit no matter how you do it. Use a tool whenever possible (try lots) but learn to do it manually too, that way you'll never have a problem when your tool of choice can't handle gnarly 3 way merge issues.

6) For the similar reasons to point 2, Learn to 'git pull --rebase'

Thursday, September 2, 2010

ActiveRecord for Oracle won't update records

I needed a script to fix up some date data in an Oracle database that didn't lend itself to using a pl/sql script. Naturally I turned to Ruby and ActiveRecord to sort out the issue. I drafted the script against a local MySQL DB and it worked flawlessly, but when run against the Oracle instance it wouldn't save any data changes.

Here's what happened, and how to fix it...


So turns out this has happened before to other - see this post on Ruby-Forum.com for details. The OP didn't get any replies so I'm assuming that he figured it out on his own, unluckily for me he didn't share the fix so I had to do some leg work.

For starters I'm running Ruby v1.8.7, activerecord v2.3.8 and activerecord-oracle_enhanced-adapter v1.3.0

My schema is legacy with a primary key that isn't "id". Easy to sort out, I coded up something like this:

class Receipt < ActiveRecord::Base
set_primary_key "rt_receipt_id"
end

So onto the issue. This worked fine with MySQL but not Oracle so my first stop is to check out the SQL that's being created:

UPDATE "RECEIPT"
SET "RT_RECEIVED" = TO_DATE('2008-01-03 23:58:19','YYYY-MM-DD HH24:MI:SS')
WHERE "RT_RECEIPT_ID" = NULL

NULL?

On any update, AR tries to sql encode the value of the AR object's "id" value as the primary key. Calling the id accessor on my Receipt objects was returning nil, and AR was translating that to a sql NULL. There's a simple fix, alias id to our new primary key accessor:

class Receipt < ActiveRecord::Base
set_primary_key "rt_receipt_id"
alias_attribute :id, :rt_receipt_id
end

Thursday, July 22, 2010

A couple of useful Ruby scripts

Ruby is my goto language for a lot of small scripting tasks, here's a couple of useful examples. Note that these scripts are good enough implementations and could be made easier to use by adding commandline arguments, I've just never had reason to use them regularly enough for that.

Gutenberg Crawler
Sometimes you need some real files with decent content for testing or whatever. Project Gutenberg is a great source of Public Domain books. Their robot page shows a number of ways to automate download of their files, however a quick and dirty (or effective, depends on your point of view) is to build the path to the text document itself. Exercise restraint - hammering their servers is rude, there are guidelines on the page linked earlier.




SVN Stripper
Git is friendly, it only adds one folder to your project. Subversion is invasive adding one to every single folder. Sometimes clients want source, for whatever reason this script strips out the .svn or _svn folders so you can unversion some subversioned source without folder hunting.


The power of Rails isn't Rails

My team is primarily a Java team (we write servers and services) so when we have to do some web work it always ends up being with a Java web framework, some reasonable, some not so good.

There are a lot of reasons to choose Java, it's stable, it's very well understood (by the people who care to dig into it's internals) and it's brilliant for long running processes like servers. What it's not good at, it seems, is web. Of all of the mainstream languages, Java seems to have the worst web frameworks, the worst view engines and the most over-thought data access conventions. If there's one saving grace in the enterprise Java landscape it's Spring, but even their best (Spring @MVC), while better or even the best in the Java landscape, it never quite feels like the right tool for the job.

Given this, the Spring team created ROO, a project to add code generation to Spring MVC. While it may not be the case here, many other web frameworks looked at the Power of Rails project and asset generation and thought "YES! That's the secret sauce!", and it turns out they're wrong. Spring ROO generates a whole load of code, it manages your DAO layer, but even with all of that power, it's real world use case has by many been deemed prototyping, not enterprise project ready. I felt the same way when I tried to use it, easy to get running, hard to keep progressing. Turns out all of the code generation in the world isn't the secret sauce.

There are two factors that I believe make Rails a killer web framework.

The first is The Community (yes, proper noun). The Rails lighthouse shows over 800 open bug tickets. I've seen people mock this fact (ROO in contrast appears to have 240, and I couldn't find the ASP.net one...) but the nature of The Community is that bugs, when found, are reported, usually with a failing test and possibly a patch for good measure. The number of found bugs (along with the rate of commits on the Rails Github account) is actually a positive sign, it means that The Community as a whole is invested in the success of Rails, and is working together to improve it rather than letting it atrophy or ignoring the issues with it and working around them. This leads to a vibrant piece of software that is a joy to use, that while not perfect, won't settle for average.

The second reason is that Rails, for multiple reasons, naturally lends itself towards a style of application that allows you to maintain the original "Wow I got that project running fast!" feeling (PM types: read "Project Velocity") for the entire duration of the Project. This seems to be why people who love agile seem to gravitate towards Rails, your burndown chart isn't logarithmic, it's flatter, more predictable, and more accurate (until the client changes their mind) than that old Gannt chart.

For the same reason that excites customers and project managers is why developers love it, because we love adding features, getting a product past just enough to the wow stage. Working a lot with legacy code teaches you the value of testability, simplicity, readability, and other agile-ilities, so anything that promotes these things to the extent that Rails does or that lets us add value to a product at the same rate regardless of the age or size of a codebase is a good thing, for everyone.

I believe that any framework garners all of it's power from the language that it sits on. A Java based web framework will be constrained by Java's inherit strengths and limitations. Likewise, a Ruby based web framework will live and die by Ruby's strengths and limitations.

It seems for the web, that Ruby's strengths are paramount to it's success, and it's limitations can be lived with.

Thursday, January 14, 2010

Scaffolds from existing tables

I find it hard to believe how often I see experienced, skilled and intelligent programmers who when faced with a tiny feature they would like to see in an OSS product resort to whining on forums or to colleagues instead of checking if there's already an existing solution

Granted this doesn't seem to come up in the Ruby world as much as it does a few other language circles I'm involved in (I suspect it's because it's usually faster to write the Ruby code to do what you want than to log into a forum...), but there are a few of these "requests" that you see over and over again, even when a good solution already exists and is freely and openly available. In rails it tends to be the "I have an existing schema but I want scaffolding!" one.

I had that thought trigger while dealing with a CRUD app I've been working on that deals with a large, legacy schema. It's not because I like scaffolding all that much (I don't) but because I wanted to get a working prototype up and running really fast and Ruby is much better at writing boilerplate code than I am.

In an attempt to become more like the programmers I look up to I didn't whine, I didn't log into a tech forum or post to a google group (where they are undoubtedly already 500 emails requesting the same thing already) I just started coding. Here's the "simplest thing that might work", it uses eval, it's not altogether elegant, but it fits all of the requirements.



We don't need to Google everything, there's nothing wrong with programmers that actually write code to solve problems...

Monday, November 23, 2009

Recursion in Ruby

I recently took part in the RPCFN. Being that this month's challenge was a Shortest Path type challenge and I've done enough discrete maths papers to know that the best graph traversal Algorithm for this is Dijkstra's least cost path one I went away and implemented it in a couple of hours. Many others did exactly the same thing, often much more elegantly that me. What struck me was that the markers were quite obviously looking for people to imagine up their own method of finding the shortest path, and had a massive bias towards recursive algorithms.

Now the winning submission is a very nice piece of code, it's concise, easy to read, simple, well tested, and it clearly lays out it's goals, to find a recursive solution to the problem with disregard of performance. It performed ok, I did wonder however how the recursion would impact the performance on larger problem sets.

So I took Todd's code and refactored mine to work with his data structures. I also changed up my code to match his module's interface and packaged both implementations into their own classes so that there wouldn't be clashes while trying to test them. (modules are for adding abilities to classes, not for providing whole feature sets, if you see yourself including a module into main, you're doing it wrong...)

And here it is.

I ran benchmarks on a low end computer (Pentium 2.8) against 3 graphs, one with 2 nodes and 2 edges, the RPCFN example with 7 nodes and 10 edges, and a larger, more complicated one of 7 nodes and 21 edges, all of this is in the code linked above. Here's the results over 10000 iterations:
Simple Graph:
Iterative Approach took 1.54700second(s).
Recursive Approach took 0.95300second(s).
RPCFN Graph:
Iterative Approach took 6.37500second(s).
Recursive Approach took 20.62500second(s).
Large Graph:
Iterative Approach took 10.70300second(s).
Recursive Approach took 472.96200second(s).

The numbers speak for themselves, this approach doesn't scale at all well. In fact at first I thought I'd broken some of Todd's code and created an infinite loop of some sort. It's more than likely that the recursive function could be tweaked to get better performance, but short version is that if I were ever to need to implement graph traversal in Ruby for any production system, recursion would be the last approach I'd look at.

Final word
Todd's decision to use a recursive solution in this case was totally justified, readability and simplicity were massive factors in this event. That said I believe that outside of the smaller, more contrived problem scopes, recursion brings a lot of headaches and scaling issues than the iterative approaches.

Exception Errno::ENOENT in PhusionPassenger

As Passenger fails so rarely there's not much documentation on the error messages, so I'm posting this for the benefit of googlers everwhere... Scroll to the bottom for the Cliffs notes.

Passenger is a fantastic piece of software, I can't praise it highly enough. It's brought Ruby deployments from the complexity of reverse proxying to a mongrel cluster up to being on par of ease with PHP, a difficult and noteworthy achievement that can only increase the adoption of Rack based technologies in the future.

That said, in very rare cases the Passenger spawner blows up in spectacular ways that the old Mongrel deployments never even dreamed of. When this happens all of your current and future Rack instances running on Passenger will respond to every request with a 500 error, your only course of action being a full Apache restart, and since it's so rare there's usually nothing that can be found on the net to fix it.

Here's an example from one of my company's Sinatra services:

*** Exception Errno::ENOENT in PhusionPassenger::Rack::ApplicationSpawner (No such file or directory - /tmp/passenger.19250/backends/backend.Hoa3NPf9xWIsBy3D4sBZtTKE1DgjhTKjbSpdwSPWW6FakeTwddzh2hwteMo6qYecQC
zgV) (process 8942):
from /opt/ruby-enterprise-1.8.6-20090610/lib/ruby/gems/1.8/gems/passenger-2.2.4/lib/phusion_passenger/abstract_request_handler.rb:279:in `initialize'
from /opt/ruby-enterprise-1.8.6-20090610/lib/ruby/gems/1.8/gems/passenger-
...snip...
[ pid=725 file=ext/apache2/Hooks.cpp:688 time=2009-11-24 06:31:02.381 ]:
Unexpected error in mod_passenger: Cannot spawn application '/opt/number_service': The spawn server has exited unexpectedly.
Backtrace:
in 'virtual boost::shared_ptr Passenger::ApplicationPoolServer::Client::get(const Passenger::PoolOptions&)' (ApplicationPoolServer.h:471)
in 'int Hooks::handleRequest(request_rec*)' (Hooks.cpp:485)

The root cause here is actually this ticket - the /tmp/passenger.****/ folder will be almost empty because some temp watcher cleaned it out in a quiet period. The ticket has been closed but unless you feel like building from source you'll have to wait until the next release to fix the issue.

Our fix was to move the Passenger temp directory out of /tmp in the Apache httpd.conf to stop temp watchers from nuking our deployments. Instructions on setting this up are found in the fantastic Passenger documentation.