After I read the excellent article 4 Things Java Programmers Can Learn from Clojure (without Learning Clojure) I not only took in the interesting lessons the author had, but I was prompted to think about all the lessons I’ve learned over the years from the various frameworks, languages, APIs, projects, and people I’ve worked with.
So, in the interest of starting a series which I may or may not update periodically, here’s the first installment of “What I learned from…”. I decided to start with the single framework I spent not that much time with (off and on for a couple of years) but from which I learned more than any other; Ruby on Rails.
Here are five things that I learned from Ruby on Rails:
1: A holistic approach can be wonderful
A lot of frameworks and languages end up just being a big bucket of parts from which you can pull to assemble your own development platform. What ends up happening is that every business ends up with their own variant on that mix.
Rails is often referred to as “opinionated”. In practice that means that they make decisions for how things will be, whether its file formats, or directory structure, or the libraries which are included as standard. They try to come up with a solution that will work 80% of the time for every need a web application developer typically has and then wire that up as the standard in the framework. However, in many cases they have put in work to ensure that you could replace a given piece if your app is one of the 20% for whom that particular solution isn’t a good fit.
2: All the “extras” as standard
This is kind of saying the same thing as my comment about a holistic approach, but lots of other frameworks I’ve worked with skipped huge swaths of problems and yet still seemed to think of themselves as “one stop” solutions. Rails saw that you didn’t really have a solution unless you had addressed package installation, testing, different deploynment environments, database changes, etc. Here are three big ones that are either usually skipped or which didn’t get much attention until post-Rails.
- Testing – No, testing isn’t really optional. It makes your code better and it costs very little once you get over initial setup costs. Any effort put in by the framework to make it easier is time spent that multiplies tens or perhaps hundreds of thousands of times as it encourages people to improve their projects.
- Environments – This is such a basic thing that I’m astonished how few frameworks deal with it. Virtually all software is run in development mode with different settings than in production. Even if those are your only two enviroments (or if you have others like test and beta), you can benefit from having support for different configurations and setup that are per environment.
- Migrations – Although there are some third party Java libraries (Flyway, LiquiBase) that try to offer the same kind of functionality, I haven’t seen Rail’s concept of a series of updates which can take your database to the latest version to match your code (or backwards when needed) take off nearly the way a lot of other early Rails stuff seems to have been adopted elsewhere. I think just about every app development framework which deals with databases would benefit from it and I’m always surprised this one hasn’t spread more, though I noticed a recent Kickstarter to add them to Django.
3: Convention over configuration
If you’ve ever worked with Struts then you’re familiar with files that have to be filled in with data every time you add a new page to an application. Rails avoids that by simply saying, “Put this type of file in this directory and I’ll know, by convention, what you want me to do with it.” In many cases it can use the name and location of a file to know everything about how to hook it into an existing application.
There are people out there in your career who will try to convince you that having a file (or in some cases, many files) you have to edit are better than simple conventions. That they allow you “flexibility” and you can put your files anywhere you want. Do not listen to those people.
4: Proscribed directory layout
Simple test, take a random open source Rails project out of Github and a Java one. Try to find stuff and quickly understand each of the two projects. The Maven proponents would claim that adopting Maven gets you that same kind of structure to your project for Java and I don’t have enough experience with it to agree or disagree. But my experience with regular Java projects tells me that each one is a “unique little snowflake.”
This is actually a Ruby thing and not a Rails thing at all, but Rails gets lots of mileage from it.
method_missing is a method that gets called whenever a method gets called on a Ruby class that doesn’t exist. However, you can implement method_missing yourself and you get full information on what the code tried to call. Rails uses that in ActiveRecord to synthesize new functions on the fly to keep the syntax of their ORM system ridiculously simple. For example, “Person.find_all_by_name(‘John’)”. Is there really a find_all_by_name? Nope. Can it create one on the fly based on the name of the function you called? You bet.
It seems like method_missing is something that would only work in a dynamic interpreted language like Ruby, but I’ve long thought that you could create a completely compiled language that would be capable of synthesizing new functions like this at compile time as well. The benefits are largely in the area of ease-of-coding but they are real ones. For example, why bother having getters and setters on your classes if they could be synthesized automatically?
I’m not sure where I’m ever going to use a language construct like this again unless I somebody asks my advice about writing a new language, but I’m storing it away. You never can tell when something like that will come in handy.